diff --git a/.github/workflows/examples-k32w.yaml b/.github/workflows/examples-k32w.yaml index 0a79f70a125b72..1f9c2f5871c8b6 100644 --- a/.github/workflows/examples-k32w.yaml +++ b/.github/workflows/examples-k32w.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: Build example - K32W with SE051 +name: Build example - K32W on: push: @@ -37,7 +37,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-k32w:5 + image: ghcr.io/project-chip/chip-build-k32w:6 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: @@ -46,7 +46,7 @@ jobs: - name: Checkout submodules & Bootstrap uses: ./.github/actions/checkout-submodules-and-bootstrap with: - platform: k32w0 + platform: k32w - name: Set up environment for size reports uses: ./.github/actions/setup-size-reports @@ -58,12 +58,14 @@ jobs: run: | scripts/run_in_build_env.sh "\ ./scripts/build/build_examples.py \ - --target k32w-light-crypto-platform-tokenizer \ - --target k32w-lock-crypto-platform-tokenizer \ - --target k32w-lock-crypto-platform-low-power-nologs \ - --target k32w-contact-crypto-platform-tokenizer \ - --target k32w-contact-crypto-platform-low-power-nologs \ - --target k32w-shell-crypto-platform \ + --target k32w-k32w0-light-crypto-platform-tokenizer \ + --target k32w-k32w0-lock-crypto-platform-tokenizer \ + --target k32w-k32w0-lock-crypto-platform-low-power-nologs \ + --target k32w-k32w0-contact-crypto-platform-tokenizer \ + --target k32w-k32w0-contact-crypto-platform-low-power-nologs \ + --target k32w-k32w0-shell-crypto-platform \ + --target k32w-k32w1-light-crypto-platform-openthread-ftd \ + --target k32w-k32w1-contact-crypto-platform-low-power-nologs \ build \ --copy-artifacts-to out/artifacts \ " @@ -71,19 +73,27 @@ jobs: run: | .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ k32w k32w0+release light \ - out/artifacts/k32w-light-crypto-platform-tokenizer/chip-k32w0x-light-example \ + out/artifacts/k32w-k32w0-light-crypto-platform-tokenizer/chip-k32w0x-light-example.elf \ + /tmp/bloat_reports/ + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + k32w k32w1+release light \ + out/artifacts/k32w-k32w1-light-crypto-platform-openthread-ftd/chip-k32w1-light-example.elf \ /tmp/bloat_reports/ - name: Get lock size stats run: | .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ k32w k32w0+release lock \ - out/artifacts/k32w-lock-crypto-platform-tokenizer/chip-k32w0x-lock-example \ + out/artifacts/k32w-k32w0-lock-crypto-platform-tokenizer/chip-k32w0x-lock-example.elf \ /tmp/bloat_reports/ - name: Get contact size stats run: | .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ k32w k32w0+release contact \ - out/artifacts/k32w-contact-crypto-platform-tokenizer/chip-k32w0x-contact-example \ + out/artifacts/k32w-k32w0-contact-crypto-platform-tokenizer/chip-k32w0x-contact-example.elf \ + /tmp/bloat_reports/ + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + k32w k32w1+release contact \ + out/artifacts/k32w-k32w1-contact-crypto-platform-low-power-nologs/chip-k32w1-contact-example.elf \ /tmp/bloat_reports/ - name: Uploading Size Reports uses: ./.github/actions/upload-size-reports diff --git a/.gitmodules b/.gitmodules index b5d7c5dc253ca2..6ebfd6dbad7141 100644 --- a/.gitmodules +++ b/.gitmodules @@ -54,16 +54,16 @@ path = third_party/freertos/repo url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git branch = V10.3.1-kernel-only - platforms = ameba,cc13xx_26xx,bouffalolab,efr32,esp32,k32w0,infineon,qpg,cc32xx,silabs_docker + platforms = ameba,cc13xx_26xx,bouffalolab,efr32,esp32,k32w,infineon,qpg,cc32xx,silabs_docker [submodule "simw-top-mini"] path = third_party/simw-top-mini/repo url = https://github.com/NXP/plug-and-trust.git branch = int/CHIPSE_Release - platforms = k32w0 + platforms = k32w [submodule "third_party/openthread/ot-nxp"] path = third_party/openthread/ot-nxp url = https://github.com/openthread/ot-nxp.git - platforms = k32w0 + platforms = k32w [submodule "third_party/openthread/ot-qorvo"] path = third_party/openthread/ot-qorvo url = https://github.com/openthread/ot-qorvo.git diff --git a/build_overrides/k32w1_sdk.gni b/build_overrides/k32w1_sdk.gni new file mode 100644 index 00000000000000..2f4f2320937360 --- /dev/null +++ b/build_overrides/k32w1_sdk.gni @@ -0,0 +1,18 @@ +# 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. + +declare_args() { + # Root directory for K32W SDK build files. + k32w1_sdk_build_root = "//third_party/nxp/k32w1_sdk" +} diff --git a/examples/build_overrides/k32w1_sdk.gni b/examples/build_overrides/k32w1_sdk.gni new file mode 100644 index 00000000000000..ab4655d7717f9a --- /dev/null +++ b/examples/build_overrides/k32w1_sdk.gni @@ -0,0 +1,19 @@ +# 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. + +declare_args() { + # Root directory for k32w SDK. + k32w1_sdk_build_root = + "//third_party/connectedhomeip/third_party/nxp/k32w1_sdk" +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/.gn b/examples/contact-sensor-app/nxp/k32w/k32w1/.gn new file mode 100644 index 00000000000000..dec954b4b9ff69 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2020-2023 Project CHIP Authors +# Copyright (c) 2023 NXP +# +# 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" + + import("//args.gni") +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/BUILD.gn b/examples/contact-sensor-app/nxp/k32w/k32w1/BUILD.gn new file mode 100644 index 00000000000000..1404ad8dd36a1c --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/BUILD.gn @@ -0,0 +1,136 @@ +# Copyright (c) 2021-2023 Project CHIP Authors +# Copyright (c) 2023 NXP +# +# 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/k32w1_sdk.gni") +import("//build_overrides/openthread.gni") + +import("${k32w1_sdk_build_root}/k32w1_executable.gni") +import("${k32w1_sdk_build_root}/k32w1_sdk.gni") + +import("${chip_root}/src/crypto/crypto.gni") +import("${chip_root}/src/lib/core/core.gni") +import("${chip_root}/src/platform/device.gni") + +declare_args() { + chip_software_version = 0 +} + +assert(current_os == "freertos") + +k32w1_platform_dir = "${chip_root}/examples/platform/nxp/k32w/k32w1" +k32w1_sdk_root = getenv("NXP_K32W1_SDK_ROOT") + +k32w1_sdk("sdk") { + sources = [ + "${k32w1_platform_dir}/app/project_include/OpenThreadConfig.h", + "include/CHIPProjectConfig.h", + "include/FreeRTOSConfig.h", + "main/include/app_config.h", + ] + + public_deps = + [ "${chip_root}/third_party/openthread/platforms:libopenthread-platform" ] + + include_dirs = [ + "main/include", + "main", + "include", + "${k32w1_platform_dir}/app/project_include", + "${k32w1_platform_dir}/app/support", + "${k32w1_platform_dir}/util/include", + ] + + defines = [] + if (is_debug) { + defines += [ "BUILD_RELEASE=0" ] + } else { + defines += [ "BUILD_RELEASE=1" ] + } + + if (chip_software_version != 0) { + defines += [ + "CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION=${chip_software_version}", + ] + } +} + +k32w1_executable("contact_sensor_app") { + output_name = "chip-k32w1-contact-example" + + sources = [ + "${k32w1_platform_dir}/util/LEDWidget.cpp", + "${k32w1_platform_dir}/util/include/LEDWidget.h", + "main/AppTask.cpp", + "main/ContactSensorManager.cpp", + "main/ZclCallbacks.cpp", + "main/include/AppEvent.h", + "main/include/AppTask.h", + "main/include/ContactSensorManager.h", + "main/main.cpp", + ] + + deps = [ + ":sdk", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/contact-sensor-app/contact-sensor-common", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/platform:syscalls_stub", + "${chip_root}/third_party/mbedtls:mbedtls", + "${k32w1_platform_dir}/app/support:freertos_mbedtls_utils", + ] + + if (chip_openthread_ftd) { + deps += [ + "${chip_root}/third_party/openthread/repo:libopenthread-cli-ftd", + "${chip_root}/third_party/openthread/repo:libopenthread-ftd", + ] + } else { + deps += [ + "${chip_root}/third_party/openthread/repo:libopenthread-cli-mtd", + "${chip_root}/third_party/openthread/repo:libopenthread-mtd", + ] + } + + cflags = [ "-Wconversion" ] + + output_dir = root_out_dir + + ldscript = "${k32w1_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc/connectivity.ld" + + inputs = [ ldscript ] + + ldflags = [ + "-Wl,--defsym=__heap_size__=0", + "-Wl,--defsym=__stack_size__=0x480", + "-Wl,--defsym=gNvmSectors=8", + "-Wl,--defsym=lp_ram_lower_limit=0x04000000", + "-Wl,--defsym=lp_ram_upper_limit=0x2001C000", + "-Wl,-print-memory-usage", + "-Wl,--no-warn-rwx-segments", + "-T" + rebase_path(ldscript, root_build_dir), + ] + + output_dir = root_out_dir +} + +group("k32w1") { + deps = [ ":contact_sensor_app" ] +} + +group("default") { + deps = [ ":k32w1" ] +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/README.md b/examples/contact-sensor-app/nxp/k32w/k32w1/README.md new file mode 100644 index 00000000000000..da6e3eb00f2f66 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/README.md @@ -0,0 +1,414 @@ +# Matter K32W1 Contact Sensor Example Application + +Matter K32W1 Contact Sensor Example uses buttons to test changing the lock and +device states and LEDs to show the state of these changes. You can use this +example as a reference for creating your own application. + +The example is based on +[Matter](https://github.com/project-chip/connectedhomeip) and the NXP K32W1 SDK, +and a simulated contact sensor over a low-power, 802.15.4 Thread network. + +The example behaves as a Matter accessory, that is a device that can be paired +into an existing Matter network and can be controlled by this network. + +
+ +- [Matter K32W1 Contact Sensor Example Application](#matter-k32w1-contact-sensor-example-application) +- [Introduction](#introduction) + - [Bluetooth LE Advertising](#bluetooth-le-advertising) + - [Bluetooth LE Rendezvous](#bluetooth-le-rendezvous) +- [Device UI](#device-ui) +- [Building](#building) +- [Flashing](#flashing) + - [Flashing the NBU image](#flashing-the-nbu-image) + - [Flashing the host image](#flashing-the-host-image) +- [Debugging](#debugging) +- [OTA](#ota) + - [Convert srec into sb3 file](#convert-srec-into-sb3-file) + - [Convert sb3 into ota file](#convert-sb3-into-ota-file) + - [Running OTA](#running-ota) + - [Known issues](#known-issues) +- [Low power](#low-power) + + + +## Introduction + +![K32W1 EVK](../../../../platform/nxp/k32w/k32w1/doc/images/k32w1-evk.jpg) + +The K32W1 contact sensor example application provides a working demonstration of +a connected contact sensor device, built using the Matter codebase and the NXP +K32W1 SDK. The example supports remote access (e.g.: using CHIP Tool from a +mobile phone) and control of a simulated contact sensor over a low-power, +802.15.4 Thread network. It is capable of being paired into an existing Matter +network along with other Matter-enabled devices. + +The Matter device that runs the contact sensor application is controlled by the +Matter controller device over the Thread protocol. By default, the Matter device +has Thread disabled, and it should be paired over Bluetooth LE with the Matter +controller and obtain configuration from it. The actions required before +establishing full communication are described below. + +### Bluetooth LE Advertising + +In this example, to commission the device onto a Matter network, it must be +discoverable over Bluetooth LE. For security reasons, you must start Bluetooth +LE advertising manually after powering up the device by pressing Button SW2. + +### Bluetooth LE Rendezvous + +In this example, the commissioning procedure (called rendezvous) is done over +Bluetooth LE between a Matter device and the Matter controller, where the +controller has the commissioner role. + +To start the rendezvous, the controller must get the commissioning information +from the Matter device. The data payload is encoded within a QR code, or printed +to the UART console. + +### Thread Provisioning + +## Device UI + +The example application provides a simple UI that depicts the state of the +device and offers basic user control. This UI is implemented via the +general-purpose LEDs and buttons built in the K32W1 EVK board. + +**LED 2** shows the overall state of the device and its connectivity. Four +states are depicted: + +- _Short Flash On (50ms on/950ms off)_ — The device is in an + unprovisioned (unpaired) state and is waiting for a commissioning + application to connect. + +* _Rapid Even Flashing (100ms on/100ms off)_ — The device is in an + unprovisioned state and a commissioning application is connected via BLE. + +- _Short Flash Off (950ms on/50ms off)_ — The device is full + provisioned, but does not yet have full network (Thread) or service + connectivity. + +* _Solid On_ — The device is fully provisioned and has full network and + service connectivity. + +NOTE: LED2 will be disabled when CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR is +enabled. On K32W1 EVK board, `PTB0` is wired to LED2 also is wired to CS (Chip +Select) External Flash Memory. OTA image is stored in external memory because of +it's size. If LED2 is enabled then it will affect External Memory CS and OTA +will not work. + +**RGB LED** shows the state of the simulated contact sensor. when the LED is +lit, the sensor is contacted, when not lit, the sensor is non-contacted. + +**Button SW2** can be used to start BLE advertising. A SHORT press of the button +will enable Bluetooth LE advertising for a predefined period of time. A LONG +Press Button SW2 initiates a factory reset. After an initial period of 3 +seconds, LED 2 and RGB LED will flash in unison to signal the pending reset. +After 6 seconds will cause the device to reset its persistent configuration and +initiate a reboot. The reset action can be cancelled by press SW2 button at any +point before the 6 second limit. + +**Button SW3** can be used to change the state of the simulated contact sensor. +The button behaves as a toggle, swapping the state every time it is pressed. + +## Building + +In order to build the Matter example, we recommend using a Linux distribution +(the demo-application was compiled on Ubuntu 20.04). + +- Download [K32W1 SDK for Matter](https://mcuxpresso.nxp.com/). Creating an + nxp.com account is required before being able to download the SDK. Once the + account is created, login and follow the steps for downloading K32W1 SDK. + The SDK Builder UI selection should be similar with the one from the image + below. + ![MCUXpresso SDK Download](../../../../platform/nxp/k32w/k32w1/doc/images/mcux-sdk-download.jpg) + +``` +user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W1_SDK_ROOT=/home/user/Desktop/SDK_K32W1/ +user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/activate.sh +user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/contact-sensor-app/nxp/k32w/k32w1 +user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w1$ gn gen out/debug --args="chip_with_ot_cli=0 is_debug=false chip_openthread_ftd=false chip_crypto=\"platform\"" +user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w1$ ninja -C out/debug +``` + +In case that Openthread CLI is needed, chip_with_ot_cli build argument must be +set to 1. + +After a successful build, the `elf` and `srec` files are found in `out/debug/` - +`see the files prefixed with chip-k32w1-contact-example`. + +## Flashing + +Two images must be written to the board: one for the host (CM33) and one for the +`NBU` (CM3). + +The image needed on the host side is the one generated in `out/debug/` while the +one needed on the `NBU` side can be found in the downloaded NXP-SDK package at +path - +`middleware\wireless\ieee-802.15.4\bin\k32w1\k32w1_nbu_ble_15_4_dyn_matter_$version.sb3`. + +### Flashing the `NBU` image + +`NBU` image should be written only when a new NXP-SDK is released. + +[K32W148 board quick start guide](https://www.nxp.com/document/guide/getting-started-with-the-k32w148-development-platform:GS-K32W148EVK) +can be used for updating the `NBU/radio` core: + +- Section 2.4 – Get Software – install `SPSDK` (Secure Provisioning Command + Line Tool) +- Section 3.3 – Updating `NBU` for Wireless examples - use the corresponding + `.sb3` file found in the SDK package at path + `middleware\wireless\ieee-802.15.4\bin\k32w1\` + +### Flashing the host image + +Host image is the one found under `out/debug/`. It should be written after each +build process. + +If debugging is needed then jump directly to the [Debugging](#debugging) +section. Otherwise, if only flashing is needed then +[JLink 7.84b](https://www.segger.com/downloads/jlink/) can be used: + +- Plug K32W1 to the USB port (no need to keep the SW4 button pressed while + doing this) + +- Create a new file, `commands_script`, with the following content (change + application name accordingly): + +```bash +reset +halt +loadfile chip-k32w1-contact-example.srec +reset +go +quit +``` + +- copy the application and `commands_script` in the same folder that JLink + executable is placed. Execute: + +```bash +$ jlink -device K32W1480 -if SWD -speed 4000 -autoconnect 1 -CommanderScript commands_script +``` + +## Debugging + +One option for debugging would be to use MCUXpresso IDE. + +- Drag-and-drop the zip file containing the NXP SDK in the "Installed SDKs" + tab: + +![Installed SDKs](../../../../platform/nxp/k32w/k32w1/doc/images/installed_sdks.jpg) + +- Import any demo application from the installed SDK: + +``` +Import SDK example(s).. -> choose a demo app (demo_apps -> hello_world) -> Finish +``` + +![Import demo](../../../../platform/nxp/k32w/k32w1/doc/images/import_demo.jpg) + +- Flash the previously imported demo application on the board: + +``` +Right click on the application (from Project Explorer) -> Debug as -> JLink/CMSIS-DAP +``` + +After this step, a debug configuration specific for the K32W1 board was created. +This debug configuration will be used later on for debugging the application +resulted after ot-nxp compilation. + +- Import Matter repo in MCUXpresso IDE as Makefile Project. Use _none_ as + _Toolchain for Indexer Settings_: + +``` +File -> Import -> C/C++ -> Existing Code as Makefile Project +``` + +![New Project](../../../../platform/nxp/k32w/k32w1/doc/images/new_project.jpg) + +- Replace the path of the existing demo application with the path of the K32W1 + application: + +``` +Run -> Debug Configurations... -> C/C++ Application +``` + +![Debug K32W1](../../../../platform/nxp/k32w/k32w1/doc/images/debug_k32w1.jpg) + +## OTA + +### Convert `srec` into `sb3` file + +The OTA image files must be encrypted using Over The Air Programming Tool +([OTAP](https://www.nxp.com/design/microcontrollers-developer-resources/connectivity-tool-suite:CONNECTIVITY-TOOL-SUITE?#downloads)). +Bootloader will load the new OTA image only if it detects that the file was +encrypted with the `OTAP` correct keys. + +`.srec` file is input for Over The air Programming (`OTAP`) application +(unencrypted) and it's converted to `.sb3` format (encrypted). + +In `OTAP` application + +- select OTA protocol => `OTAP` Matter +- Browse File +- follow default options (KW45/K32W148, Preserve NVM) +- image information: will update "Application Core (MCU)" - this will generate + the image only for the CM33 core +- keep other settings at default values + +### Convert sb3 into ota file + +In order to build an OTA image, use NXP wrapper over the standard tool +`src/app/ota_image_tool.py`: + +- `scripts/tools/nxp/factory_data_generator/ota_image_tool.py` The tool can be + used to generate an OTA image with the following format: + `| OTA image header | TLV1 | TLV2 | ... | TLVn |` where each TLV is in the + form `|tag|length|value|` + +Note that "standard" TLV format is used. Matter TLV format is only used for +factory data TLV value. + +Please see more in the +[OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). + +Here is an example that generates an OTA image with application update TLV from +a sb3 file: + +``` +./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 43033 -vs "1.0" -da sha256 --app-input-file ~/binaries/chip-k32w1-43033.sb3 ~/binaries/chip-k32w1-43033.ota + +``` + +A note regarding OTA image header version (`-vn` option). An application binary +has its own software version (given by +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). For +having a correct OTA process, the OTA header version should be the same as the +binary embedded software version. A user can set a custom software version in +the gn build args by setting `chip_software_version` to the wanted version. + +### Running OTA + +The OTA topology used for OTA testing is illustrated in the figure below. +Topology is similar with the one used for Matter Test Events. + +![OTA_TOPOLOGY](../../../../platform/nxp/k32w/k32w1/doc/images/ota_topology.JPG) + +The concept for OTA is the next one: + +- there is an OTA Provider Application that holds the OTA image. In our case, + this is a Linux application running on an Ubuntu based-system; +- the OTA Requestor functionality is embedded inside the Contact Sensor + Application. It will be used for requesting OTA blocks from the OTA + Provider; +- the controller (a linux application called chip-tool) will be used for + commissioning both the device and the OTA Provider App. The device will be + commissioned using the standard Matter flow (BLE + IEEE 802.15.4) while the + OTA Provider Application will be commissioned using the _onnetwork_ option + of chip-tool; +- during commissioning, each device is assigned a node id by the chip-tool + (can be specified manually by the user). Using the node id of the device and + of the contact sensor application, chip-tool triggers the OTA transfer by + invoking the _announce-ota-provider_ command - basically, the OTA Requestor + is informed of the node id of the OTA Provider Application. + +_Computer #1_ can be any system running an Ubuntu distribution. We recommand +using CSA official instructions from +[here](https://groups.csa-iot.org/wg/matter-csg/document/28566), where RPi 4 are +proposed. Also, CSA official instructions document point to the OS/Docker images +that should be used on the RPis. For compatibility reasons, we recommand +compiling chip-tool and OTA Provider applications with the same commit id that +was used for compiling the Contact Sensor Application. Also, please note that +there is a single controller (chip-tool) running on Computer #1 which is used +for commissioning both the device and the OTA Provider Application. If needed, +[these instructions](https://itsfoss.com/connect-wifi-terminal-ubuntu/) could be +used for connecting the RPis to WiFi. + +Build the Linux OTA provider application: + +``` +user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false +``` + +Build Linux chip-tool: + +``` +user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/chip-tool out/chip-tool-app +``` + +Start the OTA Provider Application: + +``` +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w1-43033.ota +``` + +Provision the OTA provider application and assign node id _1_. Also, grant ACL +entries to allow OTA requestors: + +``` +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing onnetwork 1 20202021 +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' 1 0 +``` + +Provision the device and assign node id _2_: + +``` +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing ble-thread 2 hex: 20202021 3840 +``` + +Start the OTA process: + +``` +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 2 0 +``` + +## Low power + +The example also offers the possibility to run in low power mode. This means +that the board will go in deep sleep most of the time and the power consumption +will be very low. + +In order to build with low power support, the `chip_with_low_power=1` must be +provided to the build system. In this case, please note that the GN build +arguments `chip_openthread_ftd` and `chip_with_ot_cli` must be set to `false/0` +and `chip_logging` must be set to `false` to disable logging. + +In order to maintain a low power consumption, the LEDs showing the state of the +contact sensor and the internal state are disabled. Console logs can be used +instead. Also, please note that once the board is flashed with MCUXpresso the +debugger disconnects because the board enters low power. + +### Known issues + +- SRP cache on the openthread border router needs to flushed each time a new + commissioning process is attempted. For this, factory reset the device, then + execute _ot-ctl server disable_ followed by _ot-ctl server enable_. After + this step, the commissioning process of the device can start; +- Due to some MDNS issues, the commissioning of the OTA Provider Application + may fail. Please make sure that the SRP cache is disabled (_ot-ctl srp + server disable_) on the openthread border router while commissioning the OTA + Provider Application; +- No other Docker image should be running (e.g.: Docker image needed by Test + Harness) except the OTBR one. A docker image can be killed using the + command: + +``` +user@computer1:~/connectedhomeip$ : sudo docker kill $container_id +``` + +- In order to avoid MDNS issues, only one interface should be active at one + time. E.g.: if WiFi is used then disable the Ethernet interface and also + disable multicast on that interface: + +``` +user@computer1:~/connectedhomeip$ sudo ip link set dev eth0 down +user@computer1:~/connectedhomeip$ sudo ifconfig eth0 -multicast +``` + +- If OTBR Docker image is used, then the "-B" parameter should point to the + interface used for the backbone. + +- If Wi-Fi is used on a RPI4, then a 5Ghz network should be selected. + Otherwise, issues related to BLE-WiFi combo may appear. diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/args.gni b/examples/contact-sensor-app/nxp/k32w/k32w1/args.gni new file mode 100644 index 00000000000000..c0497aa27421d2 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/args.gni @@ -0,0 +1,25 @@ +# Copyright (c) 2020-2023 Project CHIP Authors +# Copyright (c) 2023 NXP +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("${chip_root}/config/standalone/args.gni") +import("${chip_root}/examples/platform/nxp/k32w/k32w1/args.gni") + +# SDK target. This is overridden to add our SDK app_config.h & defines. +k32w1_sdk_target = get_label_info(":sdk", "label_no_toolchain") + +chip_enable_ota_requestor = true +chip_stack_lock_tracking = "fatal" +chip_enable_ble = true diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/build_overrides b/examples/contact-sensor-app/nxp/k32w/k32w1/build_overrides new file mode 120000 index 00000000000000..ad07557834803a --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/build_overrides @@ -0,0 +1 @@ +../../../../build_overrides/ \ No newline at end of file diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/include/CHIPProjectConfig.h b/examples/contact-sensor-app/nxp/k32w/k32w1/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..af3a7067c99e1a --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/include/CHIPProjectConfig.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright (c) 2020 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @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 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + * + * 0xFFF1: Test vendor. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + * + */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8006 + +// Use a default setup PIN code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +// Use a default pairing code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_PAIRING_CODE "CHIPUS" + +/** + * 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_DEVICE_CONFIG_DEVICE_VENDOR_ID + * + * 0xFFF1: Test vendor. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + * + */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8006 + +/** + * 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 100 + +#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING "v0.1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP 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 "03-2022-te8" +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 42020 +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME "NXP Semiconductors" +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME "NXP Demo App" +#endif + +/** + * CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_TIMEOUT + * + * The amount of time in miliseconds after which BLE should change his advertisements + * from fast interval to slow interval. + * + * 30000 (30 secondes). + */ +#define CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_TIMEOUT (30 * 1000) + +/** + * CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT + * + * The amount of time in miliseconds after which BLE advertisement should be disabled, counting + * from the moment of slow advertisement commencement. + * + * Defaults to 9000000 (15 minutes). + */ +#define CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT (15 * 60 * 1000) + +/** + * CONFIG_CHIP_NFC_COMMISSIONING, CHIP_DEVICE_CONFIG_ENABLE_NFC + * + * NFC commissioning is not supported on K32W1 + */ +#define CONFIG_CHIP_NFC_COMMISSIONING 0 +#define CHIP_DEVICE_CONFIG_ENABLE_NFC 0 + +/** + * @def CHIP_CONFIG_MAX_FABRICS + * + * @brief + * Maximum number of fabrics the device can participate in. Each fabric can + * provision the device with its unique operational credentials and manage + * its own access control lists. + */ +#define CHIP_CONFIG_MAX_FABRICS 5 // 5 is the minimum number of supported fabrics + +#define CHIP_DEVICE_CONFIG_ENABLE_SED 1 +#define CHIP_DEVICE_CONFIG_SED_IDLE_INTERVAL 1000_ms32 +#define CHIP_DEVICE_CONFIG_SED_ACTIVE_INTERVAL 100_ms32 + +/** + * @def CHIP_IM_MAX_NUM_COMMAND_HANDLER + * + * @brief Defines the maximum number of CommandHandler, limits the number of active commands transactions on server. + */ +#define CHIP_IM_MAX_NUM_COMMAND_HANDLER 2 + +/** + * @def CHIP_IM_MAX_NUM_WRITE_HANDLER + * + * @brief Defines the maximum number of WriteHandler, limits the number of active write transactions on server. + */ +#define CHIP_IM_MAX_NUM_WRITE_HANDLER 2 + +/** + * CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE + * + * For a development build, set the default importance of events to be logged as Debug. + * Since debug is the lowest importance level, this means all standard, critical, info and + * debug importance level vi events get logged. + */ +#if BUILD_RELEASE +#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Production +#else +#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Debug +#endif // BUILD_RELEASE + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/include/FreeRTOSConfig.h b/examples/contact-sensor-app/nxp/k32w/k32w1/include/FreeRTOSConfig.h new file mode 100644 index 00000000000000..a4e204700672a3 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/include/FreeRTOSConfig.h @@ -0,0 +1,207 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#pragma once + +/* Ensure stdint is only used by the compiler, and not the assembler. */ +#if defined(__ICCARM__) || defined(__ARMCC_VERSION) || defined(__GNUC__) +#include +extern uint32_t SystemCoreClock; +#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. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) +#define configUSE_TICKLESS_IDLE 1 +#else +#define configUSE_TICKLESS_IDLE 0 +#endif + +#define configCPU_CLOCK_HZ (SystemCoreClock) +#define configTICK_RATE_HZ ((TickType_t) 100) +#define configMAX_PRIORITIES (8) + +#if defined(configUSE_TICKLESS_IDLE) && (configUSE_TICKLESS_IDLE == 1) +#define configMINIMAL_STACK_SIZE ((unsigned short) 610) +#else +#define configMINIMAL_STACK_SIZE ((unsigned short) 450) +#endif + +#define configMAX_TASK_NAME_LEN 20 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 8 +#define configUSE_QUEUE_SETS 0 +/* make sure that Thread task can interrupt lengthy Matter + * processing in case priority inversion occurs + */ +#define configUSE_TIME_SLICING 1 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 + +/* Tasks.c additions (e.g. Thread Aware Debug capability) */ +#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 + +/* Used memory allocation (heap_x.c) */ +#define configFRTOS_MEMORY_SCHEME 4 + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE ((size_t) (gTotalHeapSize_c)) +#define configAPPLICATION_ALLOCATED_HEAP 1 + +/* Hook function related definitions. */ +#ifndef configUSE_IDLE_HOOK +#define configUSE_IDLE_HOOK 1 +#endif +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#ifndef configUSE_MALLOC_FAILED_HOOK +#define configUSE_MALLOC_FAILED_HOOK 0 +#endif +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Task aware debugging. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH (360) + +/* Define to trap errors during development. */ +#if defined gLoggingActive_d && (gLoggingActive_d != 0) +#include "dbg_logging.h" +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + taskDISABLE_INTERRUPTS(); \ + DbgLogDump(1); \ + } +#else +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + taskDISABLE_INTERRUPTS(); \ + for (;;) \ + ; \ + } +#endif + +/* 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 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 0 +#define INCLUDE_xTaskGetHandle 0 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +/* Interrupt nesting behaviour configuration. Cortex-M specific. */ +#ifdef __NVIC_PRIO_BITS +/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ +#define configPRIO_BITS __NVIC_PRIO_BITS +#else +#define configPRIO_BITS 3 +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7 + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1 + +/* 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 (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) +/* !!!! 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 (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) + +#ifndef configENABLE_FPU +#define configENABLE_FPU 0 +#endif +#ifndef configENABLE_MPU +#define configENABLE_MPU 0 +#endif +#ifndef configENABLE_TRUSTZONE +#define configENABLE_TRUSTZONE 0 +#endif +#ifndef configRUN_FREERTOS_SECURE_ONLY +#define configRUN_FREERTOS_SECURE_ONLY 1 +#endif + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp b/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp new file mode 100644 index 00000000000000..bce7374d7ea7ef --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp @@ -0,0 +1,812 @@ +/* + * + * Copyright (c) 2022-2023 Project CHIP Authors + * Copyright (c) 2022 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AppTask.h" +#include "AppEvent.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* OTA related includes */ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +#include "OtaSupport.h" +#include +#include +#include +#include +#include +#endif + +#include "K32W1PersistentStorageOpKeystore.h" + +#include "LEDWidget.h" +#include "app.h" +#include "app_config.h" +#include "fsl_component_button.h" +#include "fwk_platform.h" + +#define FACTORY_RESET_TRIGGER_TIMEOUT 6000 +#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 +#define APP_TASK_PRIORITY 2 +#define APP_EVENT_QUEUE_SIZE 10 + +TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. + +static QueueHandle_t sAppEventQueue; + +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) +/* + * The status LED and the external flash CS pin are wired together. + * The OTA image writing may fail if used together. + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static LEDWidget sStatusLED; +#endif +static LEDWidget sContactSensorLED; +#endif + +static bool sIsThreadProvisioned = false; +static bool sHaveBLEConnections = false; + +static uint32_t eventMask = 0; + +#if CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI +extern "C" void otPlatUartProcess(void); +#endif + +extern "C" void PWR_DisallowDeviceToSleep(void); +extern "C" void PWR_AllowDeviceToSleep(void); + +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; +using namespace chip; +using namespace chip::app; + +AppTask AppTask::sAppTask; + +static Identify gIdentify = { chip::EndpointId{ 1 }, AppTask::OnIdentifyStart, AppTask::OnIdentifyStop, + Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator }; + +/* OTA related variables */ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static DefaultOTARequestor gRequestorCore __attribute__((section(".data"))); +static DefaultOTARequestorStorage gRequestorStorage __attribute__((section(".data"))); +static DeviceLayer::DefaultOTARequestorDriver gRequestorUser __attribute__((section(".data"))); +static BDXDownloader gDownloader __attribute__((section(".data"))); + +constexpr uint16_t requestedOtaBlockSize = 1024; +#endif + +CHIP_ERROR AppTask::StartAppTask() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + err = APP_ERROR_EVENT_QUEUE_FAILED; + K32W_LOG("Failed to allocate app event queue"); + assert(err == CHIP_NO_ERROR); + } + + return err; +} + +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + if (ContactSensorMgr().Init() != 0) + { + K32W_LOG("ContactSensorMgr().Init() failed"); + assert(status == 0); + } + + PlatformMgr().AddEventHandler(MatterEventHandler, 0); + + // Init ZCL Data Model and start server + PlatformMgr().ScheduleWork(InitServer, 0); + + // Initialize device attestation config + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + + // QR code will be used with CHIP Tool + AppTask::PrintOnboardingInfo(); + +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) + /* start with all LEDS turnedd off */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Init(SYSTEM_STATE_LED, false); +#endif + + sContactSensorLED.Init(CONTACT_SENSOR_STATE_LED, false); + sContactSensorLED.Set(ContactSensorMgr().IsContactClosed()); +#endif + + UpdateDeviceState(); + + /* intialize the Keyboard and button press callback */ + BUTTON_InstallCallback((button_handle_t) g_buttonHandle[0], KBD_Callback, (void *) BLE_BUTTON); + BUTTON_InstallCallback((button_handle_t) g_buttonHandle[1], KBD_Callback, (void *) CONTACT_SENSOR_BUTTON); + + // 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 + TimerEventHandler // timer callback handler + ); + if (sFunctionTimer == NULL) + { + err = APP_ERROR_CREATE_TIMER_FAILED; + K32W_LOG("app_timer_create() failed"); + assert(err == CHIP_NO_ERROR); + } + + ContactSensorMgr().SetCallback(OnStateChanged); + + // Print the current software version + char currentSoftwareVer[ConfigurationManager::kMaxSoftwareVersionStringLength + 1] = { 0 }; + err = ConfigurationMgr().GetSoftwareVersionString(currentSoftwareVer, sizeof(currentSoftwareVer)); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Get version error"); + assert(err == CHIP_NO_ERROR); + } + + uint32_t currentVersion; + err = ConfigurationMgr().GetSoftwareVersion(currentVersion); + + K32W_LOG("Current Software Version: %s, %d", currentSoftwareVer, currentVersion); + + return err; +} + +void LockOpenThreadTask(void) +{ + PWR_DisallowDeviceToSleep(); + chip::DeviceLayer::ThreadStackMgr().LockThreadStack(); +} + +void UnlockOpenThreadTask(void) +{ + chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack(); + PWR_AllowDeviceToSleep(); +} + +void AppTask::InitServer(intptr_t arg) +{ + static chip::CommonCaseDeviceServerInitParams initParams; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + +#if CHIP_CRYPTO_PLATFORM + static chip::K32W1PersistentStorageOpKeystore sK32W1PersistentStorageOpKeystore; + VerifyOrDie((sK32W1PersistentStorageOpKeystore.Init(initParams.persistentStorageDelegate)) == CHIP_NO_ERROR); + initParams.operationalKeystore = &sK32W1PersistentStorageOpKeystore; +#endif + + // Init ZCL Data Model and start server + chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams; + nativeParams.lockCb = LockOpenThreadTask; + nativeParams.unlockCb = UnlockOpenThreadTask; + nativeParams.openThreadInstancePtr = chip::DeviceLayer::ThreadStackMgrImpl().OTInstance(); + initParams.endpointNativeParams = static_cast(&nativeParams); + VerifyOrDie((chip::Server::GetInstance().Init(initParams)) == CHIP_NO_ERROR); +} + +void AppTask::PrintOnboardingInfo() +{ + chip::PayloadContents payload; + CHIP_ERROR err = GetPayloadContents(payload, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "GetPayloadContents() failed: %" CHIP_ERROR_FORMAT, err.Format()); + } + payload.commissioningFlow = chip::CommissioningFlow::kUserActionRequired; + PrintOnboardingCodes(payload); +} + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void AppTask::InitOTA(intptr_t arg) +{ + // 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); + gRequestorUser.SetMaxDownloadBlockSize(requestedOtaBlockSize); + auto & imageProcessor = OTAImageProcessorImpl::GetDefaultInstance(); + gRequestorUser.Init(&gRequestorCore, &imageProcessor); + CHIP_ERROR err = imageProcessor.Init(&gDownloader); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Image processor init failed"); + assert(err == CHIP_NO_ERROR); + } + + // Connect the gDownloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&imageProcessor); + // Initialize and interconnect the Requestor and Image Processor objects -- END +} +#endif + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("AppTask.Init() failed"); + assert(err == CHIP_NO_ERROR); + } + + while (true) + { + TickType_t xTicksToWait = pdMS_TO_TICKS(10); + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + xTicksToWait = portMAX_DELAY; +#endif + + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, xTicksToWait); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + + // 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 (PlatformMgr().TryLockChipStack()) + { +#if CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI + otPlatUartProcess(); +#endif + + sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); + PlatformMgr().UnlockChipStack(); + } + + // Update the status LED if factory reset or identify process have 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 !defined(chip_with_low_power) || (chip_with_low_power == 0) +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (sAppTask.mFunction != Function::kFactoryReset && sAppTask.mFunction != Function::kIdentify) + { + if (sIsThreadProvisioned) + { + sStatusLED.Blink(950, 50); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(100, 100); + } + else + { + sStatusLED.Blink(50, 950); + } + } + + sStatusLED.Animate(); +#endif + + sContactSensorLED.Animate(); +#endif + } +} + +void AppTask::ButtonEventHandler(uint8_t pin_no, uint8_t button_action) +{ + if ((pin_no != RESET_BUTTON) && (pin_no != CONTACT_SENSOR_BUTTON) && (pin_no != OTA_BUTTON) && (pin_no != BLE_BUTTON)) + { + return; + } + + AppEvent button_event; + button_event.Type = AppEvent::kButton; + button_event.ButtonEvent.PinNo = pin_no; + button_event.ButtonEvent.Action = button_action; + + if (pin_no == RESET_BUTTON) + { + button_event.Handler = ResetActionEventHandler; + } + else if (pin_no == CONTACT_SENSOR_BUTTON) + { + button_event.Handler = ContactActionEventHandler; + } + else if (pin_no == OTA_BUTTON) + { + // Starting OTA by button functionality is not used. + // button_event.Handler = OTAHandler; + } + else if (pin_no == BLE_BUTTON) + { + button_event.Handler = BleHandler; + + if (button_action == RESET_BUTTON_PUSH) + { + button_event.Handler = ResetActionEventHandler; + } + } + + sAppTask.PostEvent(&button_event); +} + +button_status_t AppTask::KBD_Callback(void * buttonHandle, button_callback_message_t * message, void * callbackParam) +{ + uint32_t pinNb = (uint32_t) callbackParam; + switch (message->event) + { + case kBUTTON_EventOneClick: + case kBUTTON_EventShortPress: + switch (pinNb) + { + case BLE_BUTTON: + K32W_LOG("pb1 short press"); + if (sAppTask.mResetTimerActive) + { + ButtonEventHandler(BLE_BUTTON, RESET_BUTTON_PUSH); + } + else + { + ButtonEventHandler(BLE_BUTTON, BLE_BUTTON_PUSH); + } + break; + + case CONTACT_SENSOR_BUTTON: + K32W_LOG("pb2 short press"); + ButtonEventHandler(CONTACT_SENSOR_BUTTON, CONTACT_SENSOR_BUTTON_PUSH); + break; + } + break; + + case kBUTTON_EventLongPress: + switch (pinNb) + { + case BLE_BUTTON: + K32W_LOG("pb1 long press"); + ButtonEventHandler(BLE_BUTTON, RESET_BUTTON_PUSH); + break; + + case CONTACT_SENSOR_BUTTON: + K32W_LOG("pb2 long press"); + ButtonEventHandler(OTA_BUTTON, OTA_BUTTON_PUSH); + break; + } + break; + + default: + /* No action required */ + break; + } + return kStatus_BUTTON_Success; +} + +void AppTask::TimerEventHandler(TimerHandle_t xTimer) +{ + AppEvent event; + event.Type = AppEvent::kTimer; + event.TimerEvent.Context = (void *) xTimer; + event.Handler = FunctionTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FunctionTimerEventHandler(void * aGenericEvent) +{ + AppEvent * aEvent = (AppEvent *) aGenericEvent; + + if (aEvent->Type != AppEvent::kTimer) + return; + + K32W_LOG("Device will factory reset..."); + + // Actually trigger Factory Reset + chip::Server::GetInstance().ScheduleFactoryReset(); +} + +void AppTask::ResetActionEventHandler(void * aGenericEvent) +{ + AppEvent * aEvent = (AppEvent *) aGenericEvent; + + if (aEvent->ButtonEvent.PinNo != RESET_BUTTON && aEvent->ButtonEvent.PinNo != BLE_BUTTON) + return; + + if (sAppTask.mResetTimerActive) + { + sAppTask.CancelTimer(); + sAppTask.mFunction = Function::kNoneSelected; + +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) + /* restore initial state for the LED indicating contact state */ + if (!ContactSensorMgr().IsContactClosed()) + { + sContactSensorLED.Set(false); + } + else + { + sContactSensorLED.Set(true); + } +#endif + + K32W_LOG("Factory Reset was cancelled!"); + } + else + { + uint32_t resetTimeout = FACTORY_RESET_TRIGGER_TIMEOUT; + + if (sAppTask.mFunction != Function::kNoneSelected) + { + K32W_LOG("Another function is scheduled. Could not initiate Factory Reset!"); + return; + } + + K32W_LOG("Factory Reset Triggered. Push the RESET button within %lu ms to cancel!", resetTimeout); + sAppTask.mFunction = Function::kFactoryReset; + + /* LEDs will start blinking to signal that a Factory Reset was scheduled */ +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Set(false); + sStatusLED.Blink(500); +#endif + sContactSensorLED.Set(false); + sContactSensorLED.Blink(500); +#endif + + sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); + } +} + +void AppTask::ContactActionEventHandler(void * aGenericEvent) +{ + AppEvent * aEvent = (AppEvent *) aGenericEvent; + ContactSensorManager::Action action = ContactSensorManager::Action::kInvalid; + CHIP_ERROR err = CHIP_NO_ERROR; + bool state_changed = false; + + if (sAppTask.mFunction != Function::kNoneSelected) + { + K32W_LOG("Another function is scheduled. Could not change contact state."); + return; + } + + if (aEvent->Type == AppEvent::kContact) + { + action = static_cast(aEvent->ContactEvent.Action); + } + else if (aEvent->Type == AppEvent::kButton) + { + if (ContactSensorMgr().IsContactClosed()) + { + action = ContactSensorManager::Action::kSignalLost; + } + else + { + action = ContactSensorManager::Action::kSignalDetected; + } + + sAppTask.SetSyncClusterToButtonAction(true); + } + else + { + err = APP_ERROR_UNHANDLED_EVENT; + action = ContactSensorManager::Action::kInvalid; + } + + if (err == CHIP_NO_ERROR) + { + ContactSensorMgr().InitiateAction(action); + } +} + +void AppTask::OTAHandler(void * aGenericEvent) +{ + AppEvent * aEvent = (AppEvent *) aGenericEvent; + if (aEvent->ButtonEvent.PinNo != OTA_BUTTON) + return; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (sAppTask.mFunction != Function::kNoneSelected) + { + K32W_LOG("Another function is scheduled. Could not initiate OTA!"); + return; + } + + PlatformMgr().ScheduleWork(StartOTAQuery, 0); +#endif +} + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void AppTask::StartOTAQuery(intptr_t arg) +{ + GetRequestorInstance()->TriggerImmediateQuery(); +} +#endif + +void AppTask::BleHandler(void * aGenericEvent) +{ + AppEvent * aEvent = (AppEvent *) aGenericEvent; + + if (aEvent->ButtonEvent.PinNo != BLE_BUTTON) + return; + + if (sAppTask.mFunction != Function::kNoneSelected) + { + K32W_LOG("Another function is scheduled. Could not toggle BLE state!"); + return; + } + PlatformMgr().ScheduleWork(AppTask::BleStartAdvertising, 0); +} + +void AppTask::BleStartAdvertising(intptr_t arg) +{ + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + ConnectivityMgr().SetBLEAdvertisingEnabled(false); + K32W_LOG("Stopped BLE Advertising!"); + } + else + { + ConnectivityMgr().SetBLEAdvertisingEnabled(true); + + if (chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() == CHIP_NO_ERROR) + { + K32W_LOG("Started BLE Advertising!"); + } + else + { + K32W_LOG("OpenBasicCommissioningWindow() failed"); + } + } +} + +void AppTask::MatterEventHandler(const ChipDeviceEvent * event, intptr_t) +{ + if (event->Type == DeviceEventType::kServiceProvisioningChange && event->ServiceProvisioningChange.IsServiceProvisioned) + { + if (event->ServiceProvisioningChange.IsServiceProvisioned) + { + sIsThreadProvisioned = TRUE; + } + else + { + sIsThreadProvisioned = FALSE; + } + } + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (event->Type == DeviceEventType::kDnssdInitialized) + { + K32W_LOG("Dnssd platform initialized."); + PlatformMgr().ScheduleWork(InitOTA, 0); + } +#endif +} + +void AppTask::CancelTimer() +{ + if (xTimerStop(sFunctionTimer, 0) == pdFAIL) + { + K32W_LOG("app timer stop() failed"); + } + + mResetTimerActive = false; +} + +void AppTask::StartTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sFunctionTimer)) + { + K32W_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(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + K32W_LOG("app timer start() failed"); + } + + mResetTimerActive = true; +} + +void AppTask::OnStateChanged(ContactSensorManager::State aState) +{ + // If the contact state was changed, update LED state and cluster state (only if button was pressed). + // - turn on the contact LED if contact sensor is in closed state. + // - turn off the lock LED if contact sensor is in opened state. + if (ContactSensorManager::State::kContactClosed == aState) + { + K32W_LOG("Contact state changed to closed.") +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) + sContactSensorLED.Set(true); +#endif + } + else if (ContactSensorManager::State::kContactOpened == aState) + { + K32W_LOG("Contact state changed to opened.") +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) + sContactSensorLED.Set(false); +#endif + } + + if (sAppTask.IsSyncClusterToButtonAction()) + { + sAppTask.UpdateClusterState(); + } + + sAppTask.mFunction = Function::kNoneSelected; +} + +void AppTask::OnIdentifyStart(Identify * identify) +{ + if (Clusters::Identify::EffectIdentifierEnum::kBlink == identify->mCurrentEffectIdentifier) + { + if (Function::kNoneSelected != sAppTask.mFunction) + { + K32W_LOG("Another function is scheduled. Could not initiate Identify process!"); + return; + } + K32W_LOG("Identify process has started. Status LED should blink every 0.5 seconds."); + sAppTask.mFunction = Function::kIdentify; +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Set(false); + sStatusLED.Blink(500); +#endif +#endif + } +} + +void AppTask::OnIdentifyStop(Identify * identify) +{ + if (Clusters::Identify::EffectIdentifierEnum::kBlink == identify->mCurrentEffectIdentifier) + { + K32W_LOG("Identify process has stopped."); + sAppTask.mFunction = Function::kNoneSelected; + } +} + +void AppTask::PostContactActionRequest(ContactSensorManager::Action aAction) +{ + AppEvent event; + event.Type = AppEvent::kContact; + event.ContactEvent.Action = static_cast(aAction); + event.Handler = ContactActionEventHandler; + PostEvent(&event); +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + portBASE_TYPE taskToWake = pdFALSE; + if (sAppEventQueue != NULL) + { + if (__get_IPSR()) + { + if (!xQueueSendToFrontFromISR(sAppEventQueue, aEvent, &taskToWake)) + { + K32W_LOG("Failed to post event to app task event queue"); + } + if (taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + } + else if (!xQueueSend(sAppEventQueue, aEvent, 0)) + { + K32W_LOG("Failed to post event to app task event queue"); + } + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + /* specific processing for events sent from App_PostCallbackMessage (see main.cpp) */ + if (aEvent->Type == AppEvent::kEventType_Lp) + { + aEvent->Handler(aEvent->param); + } + else +#endif + + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + K32W_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateClusterState(void) +{ + PlatformMgr().ScheduleWork(UpdateClusterStateInternal, 0); +} +extern void logBooleanStateEvent(bool state); +void AppTask::UpdateClusterStateInternal(intptr_t arg) +{ + uint8_t newValue = ContactSensorMgr().IsContactClosed(); + + // write the new on/off value + EmberAfStatus status = app::Clusters::BooleanState::Attributes::StateValue::Set(1, newValue); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(NotSpecified, "ERR: updating boolean status value %x", status); + } + logBooleanStateEvent(newValue); +} + +void AppTask::UpdateDeviceState(void) +{ + PlatformMgr().ScheduleWork(UpdateDeviceStateInternal, 0); +} + +void AppTask::UpdateDeviceStateInternal(intptr_t arg) +{ + bool stateValueAttrValue = 0; + + /* get onoff attribute value */ + (void) app::Clusters::BooleanState::Attributes::StateValue::Get(1, &stateValueAttrValue); + +#if !defined(chip_with_low_power) || (chip_with_low_power == 0) + /* set the device state */ + sContactSensorLED.Set(stateValueAttrValue); +#endif +} + +extern "C" void OTAIdleActivities(void) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + OTA_TransactionResume(); +#endif +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/ContactSensorManager.cpp b/examples/contact-sensor-app/nxp/k32w/k32w1/main/ContactSensorManager.cpp new file mode 100644 index 00000000000000..9e0a665cbb5aa9 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/ContactSensorManager.cpp @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2022-2023 Project CHIP Authors + * Copyright (c) 2022 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ContactSensorManager.h" + +#include "AppTask.h" +#include "FreeRTOS.h" + +#include "app_config.h" + +ContactSensorManager ContactSensorManager::sContactSensor; + +int ContactSensorManager::Init() +{ + int err = 0; + + mState = State::kContactOpened; + mCallbackStateChanged = nullptr; + + return err; +} + +void ContactSensorManager::SetCallback(CallbackStateChanged aCallbackStateChanged) +{ + mCallbackStateChanged = aCallbackStateChanged; +} + +bool ContactSensorManager::IsContactClosed() +{ + return mState == State::kContactClosed; +} + +void ContactSensorManager::InitiateAction(Action aAction) +{ + AppEvent event; + event.Type = AppEvent::kContact; + event.ContactEvent.Action = static_cast(aAction); + event.Handler = HandleAction; + GetAppTask().PostEvent(&event); +} + +void ContactSensorManager::HandleAction(void * aGenericEvent) +{ + AppEvent * event = static_cast(aGenericEvent); + Action action = static_cast(event->ContactEvent.Action); + // Change current state based on action: + // - if state is closed and action is signal lost, change state to opened + // - if state is opened and action is signal detected, change state to closed + // - else, the state/action combination does not change the state. + if (State::kContactClosed == sContactSensor.mState && Action::kSignalLost == action) + { + sContactSensor.mState = State::kContactOpened; + } + else if (State::kContactOpened == sContactSensor.mState && Action::kSignalDetected == action) + { + sContactSensor.mState = State::kContactClosed; + } + + if (sContactSensor.mCallbackStateChanged != nullptr) + { + sContactSensor.mCallbackStateChanged(sContactSensor.mState); + } + else + { + K32W_LOG("Callback for state change was not set. Please set an appropriate callback."); + } +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/ZclCallbacks.cpp b/examples/contact-sensor-app/nxp/k32w/k32w1/main/ZclCallbacks.cpp new file mode 100644 index 00000000000000..e1e35b4cb4ec7e --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/ZclCallbacks.cpp @@ -0,0 +1,98 @@ +/* + * + * Copyright (c) 2022-2023 Project CHIP Authors + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "AppTask.h" +#include "ContactSensorManager.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::app::Clusters; +using namespace ::chip::app::Clusters::BooleanState; + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & path, uint8_t type, uint16_t size, uint8_t * value) +{ + ChipLogProgress(Zcl, "MatterPostAttributeChangeCallback, value:%d\n", *value); + if (path.mClusterId != BooleanState::Id) + { + ChipLogProgress(Zcl, "Unknown cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(path.mClusterId)); + return; + } + + if (path.mAttributeId != BooleanState::Attributes::StateValue::Id) + { + ChipLogProgress(Zcl, "Unknown attribute ID: " ChipLogFormatMEI, ChipLogValueMEI(path.mAttributeId)); + return; + } + + AppTask & task = GetAppTask(); + // If the callback is called after the cluster attribute was changed due to pressing a button, + // set the sync value to false. Both LED and attribute were updated at this point. + // On the other hand, if the cluster attribute was changed due to a cluster command, + // forward the request to AppTask in order to update the LED state. + if (task.IsSyncClusterToButtonAction()) + { + task.SetSyncClusterToButtonAction(false); + } + else + { + task.PostContactActionRequest(*value ? ContactSensorManager::Action::kSignalDetected + : ContactSensorManager::Action::kSignalLost); + } +} + +/** @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 emberAfBooleanStateClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "emberAfBooleanStateClusterInitCallback\n"); + GetAppTask().UpdateClusterState(); +} + +void logBooleanStateEvent(bool state) +{ + EventNumber eventNumber; + Events::StateChange::Type event{ state }; + if (CHIP_NO_ERROR != LogEvent(event, 1, eventNumber)) + { + ChipLogProgress(Zcl, "booleanstate: failed to reacord state-change event"); + } +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/AppEvent.h b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/AppEvent.h new file mode 100644 index 00000000000000..f3e0d729abe2e7 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/AppEvent.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2022 Nest Labs, Inc. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct AppEvent; +typedef void (*EventHandler)(void *); + +struct AppEvent +{ + enum AppEventTypes + { + kButton = 0, + kTimer, + kContact, + kInstall, +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + kEventType_Lp, +#endif + kOTAResume, + }; + + AppEventTypes Type; + + union + { + struct + { + uint8_t PinNo; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + } ContactEvent; + }; + + EventHandler Handler; + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + void * param; +#endif +}; diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/AppTask.h b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/AppTask.h new file mode 100644 index 00000000000000..47b644769cfb63 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/AppTask.h @@ -0,0 +1,129 @@ +/* + * + * Copyright (c) 2022 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" +#include "ContactSensorManager.h" + +#include "CHIPProjectConfig.h" + +#include +#include + +#include "FreeRTOS.h" +#include "fsl_component_button.h" +#include "timers.h" + +// 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) + +class AppTask +{ +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + + void PostContactActionRequest(ContactSensorManager::Action aAction); + void PostEvent(const AppEvent * event); + + void UpdateClusterState(void); + void UpdateDeviceState(void); + + bool IsSyncClusterToButtonAction(); + void SetSyncClusterToButtonAction(bool value); + // Identify cluster callbacks. + static void OnIdentifyStart(Identify * identify); + static void OnIdentifyStop(Identify * identify); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static void OnStateChanged(ContactSensorManager::State aState); + + void CancelTimer(void); + + void DispatchEvent(AppEvent * event); + + static void FunctionTimerEventHandler(void * aGenericEvent); + static button_status_t KBD_Callback(void * buttonHandle, button_callback_message_t * message, void * callbackParam); + static void HandleKeyboard(void); + static void OTAHandler(void * aGenericEvent); + static void BleHandler(void * aGenericEvent); + static void BleStartAdvertising(intptr_t arg); + static void ContactActionEventHandler(void * aGenericEvent); + static void ResetActionEventHandler(void * aGenericEvent); + static void InstallEventHandler(void * aGenericEvent); + + static void ButtonEventHandler(uint8_t pin_no, uint8_t button_action); + static void TimerEventHandler(TimerHandle_t xTimer); + + static void MatterEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void StartTimer(uint32_t aTimeoutInMs); + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static void InitOTA(intptr_t arg); + static void StartOTAQuery(intptr_t arg); +#endif + + static void UpdateClusterStateInternal(intptr_t arg); + static void UpdateDeviceStateInternal(intptr_t arg); + static void InitServer(intptr_t arg); + static void PrintOnboardingInfo(); + + enum class Function : uint8_t + { + kNoneSelected = 0, + kFactoryReset, + kContact, + kIdentify, + kInvalid + }; + + Function mFunction = Function::kNoneSelected; + bool mResetTimerActive = false; + bool mSyncClusterToButtonAction = false; + + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} + +inline bool AppTask::IsSyncClusterToButtonAction() +{ + return mSyncClusterToButtonAction; +} + +inline void AppTask::SetSyncClusterToButtonAction(bool value) +{ + mSyncClusterToButtonAction = value; +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/ContactSensorManager.h b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/ContactSensorManager.h new file mode 100644 index 00000000000000..69a71ee14ee344 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/ContactSensorManager.h @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2022 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support + +class ContactSensorManager +{ +public: + enum class Action : uint8_t + { + kSignalDetected = 0, + kSignalLost, + kInvalid + }; + + enum class State : uint8_t + { + kContactClosed = 0, + kContactOpened, + kInvalid + }; + + int Init(); + bool IsContactClosed(); + void InitiateAction(Action aAction); + + typedef void (*CallbackStateChanged)(State aState); + void SetCallback(CallbackStateChanged aCallbackStateChanged); + + static void HandleAction(void * aGenericEvent); + +private: + friend ContactSensorManager & ContactSensorMgr(void); + State mState; + CallbackStateChanged mCallbackStateChanged; + static ContactSensorManager sContactSensor; +}; + +inline ContactSensorManager & ContactSensorMgr(void) +{ + return ContactSensorManager::sContactSensor; +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/app_config.h b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/app_config.h new file mode 100644 index 00000000000000..b62ce79567e8db --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/include/app_config.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2022 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// ---- Contact Example App Config ---- + +#define RESET_BUTTON 1 +#define CONTACT_SENSOR_BUTTON 2 +#define OTA_BUTTON 3 +#define BLE_BUTTON 4 + +#define RESET_BUTTON_PUSH 1 +#define CONTACT_SENSOR_BUTTON_PUSH 2 +#define OTA_BUTTON_PUSH 3 +#define BLE_BUTTON_PUSH 4 + +#define APP_BUTTON_PUSH 1 + +#define CONTACT_SENSOR_STATE_LED 1 +#define SYSTEM_STATE_LED 0 + +// ---- Contact Example SWU Config ---- +#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours +#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours + +// ---- Thread Polling Config ---- +// #define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 +// #define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 + +#if K32W_LOG_ENABLED +#define K32W_LOG(...) otPlatLog(OT_LOG_LEVEL_NONE, OT_LOG_REGION_API, ##__VA_ARGS__); +#else +#define K32W_LOG(...) +#endif diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/main.cpp b/examples/contact-sensor-app/nxp/k32w/k32w1/main/main.cpp new file mode 100644 index 00000000000000..700bbc5ad9356c --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/main.cpp @@ -0,0 +1,143 @@ +/* + * + * Copyright (c) 2022 Google LLC. + * Copyright (c) 2023 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ================================================================================ +// Main Code +// ================================================================================ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "FreeRtosHooks.h" +#include "app_config.h" +#include "openthread/platform/logging.h" + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +using namespace ::chip::Logging; + +#include + +typedef void (*InitFunc)(void); +extern InitFunc __init_array_start; +extern InitFunc __init_array_end; + +extern "C" void main_task(void const * argument) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + /* Call C++ constructors */ + InitFunc * pFunc = &__init_array_start; + for (; pFunc < &__init_array_end; ++pFunc) + { + (*pFunc)(); + } + + mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); + + err = PlatformMgrImpl().InitBoardFwk(); + if (err != CHIP_NO_ERROR) + { + return; + } + + /* Used for HW initializations */ + otSysInit(0, NULL); + + if (err != CHIP_NO_ERROR) + { + return; + } + + K32W_LOG("Welcome to NXP Contact Sensor Demo App"); + + /* Mbedtls Threading support is needed because both + * Thread and Matter tasks are using it */ + freertos_mbedtls_mutex_init(); + + // Init Chip memory management before the stack + chip::Platform::MemoryInit(); + + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during PlatformMgr().InitMatterStack()"); + goto exit; + } + + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during ThreadStackMgr().InitThreadStack()"); + goto exit; + } + + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); + if (err != CHIP_NO_ERROR) + { + goto exit; + } + + // Start OpenThread task + err = ThreadStackMgrImpl().StartThreadTask(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during ThreadStackMgrImpl().StartThreadTask()"); + goto exit; + } + + err = GetAppTask().StartAppTask(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during GetAppTask().StartAppTask()"); + goto exit; + } + + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during PlatformMgr().StartEventLoopTask();"); + goto exit; + } + + GetAppTask().AppTaskMain(NULL); + +exit: + return; +} + +/** + * 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); +} diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/third_party/connectedhomeip b/examples/contact-sensor-app/nxp/k32w/k32w1/third_party/connectedhomeip new file mode 120000 index 00000000000000..305f2077ffe860 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../../.. \ No newline at end of file diff --git a/examples/lighting-app/nxp/k32w/k32w1/.gn b/examples/lighting-app/nxp/k32w/k32w1/.gn new file mode 100644 index 00000000000000..3d48789e30ab3d --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/.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" + + import("//args.gni") +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/BUILD.gn b/examples/lighting-app/nxp/k32w/k32w1/BUILD.gn new file mode 100644 index 00000000000000..fd095a2cb197c5 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/BUILD.gn @@ -0,0 +1,141 @@ +# 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/k32w1_sdk.gni") +import("//build_overrides/openthread.gni") + +import("${k32w1_sdk_build_root}/k32w1_executable.gni") +import("${k32w1_sdk_build_root}/k32w1_sdk.gni") + +import("${chip_root}/src/crypto/crypto.gni") +import("${chip_root}/src/lib/core/core.gni") +import("${chip_root}/src/platform/device.gni") + +declare_args() { + chip_software_version = 0 +} + +assert(current_os == "freertos") + +k32w1_platform_dir = "${chip_root}/examples/platform/nxp/k32w/k32w1" +k32w1_sdk_root = getenv("NXP_K32W1_SDK_ROOT") + +k32w1_sdk("sdk") { + sources = [ + "${k32w1_platform_dir}/app/project_include/OpenThreadConfig.h", + "include/CHIPProjectConfig.h", + "include/FreeRTOSConfig.h", + "main/include/app_config.h", + ] + + public_deps = + [ "${chip_root}/third_party/openthread/platforms:libopenthread-platform" ] + + include_dirs = [ + "main/include", + "main", + "include", + "${k32w1_platform_dir}/app/project_include", + "${k32w1_platform_dir}/app/support", + "${k32w1_platform_dir}/app/ldscripts", + "${k32w1_platform_dir}/util/include", + ] + + defines = [] + if (is_debug) { + defines += [ "BUILD_RELEASE=0" ] + } else { + defines += [ "BUILD_RELEASE=1" ] + } + + if (chip_software_version != 0) { + defines += [ + "CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION=${chip_software_version}", + ] + } +} + +k32w1_executable("light_app") { + output_name = "chip-k32w1-light-example" + + sources = [ + "${k32w1_platform_dir}/util/LEDWidget.cpp", + "${k32w1_platform_dir}/util/include/LEDWidget.h", + "main/AppTask.cpp", + "main/LightingManager.cpp", + "main/ZclCallbacks.cpp", + "main/include/AppEvent.h", + "main/include/AppTask.h", + "main/include/LightingManager.h", + "main/main.cpp", + ] + + deps = [ + ":sdk", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/lighting-app/nxp/zap/", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/platform:syscalls_stub", + "${chip_root}/third_party/mbedtls:mbedtls", + "${k32w1_platform_dir}/app/support:freertos_mbedtls_utils", + ] + + if (chip_openthread_ftd) { + deps += [ + "${chip_root}/third_party/openthread/repo:libopenthread-cli-ftd", + "${chip_root}/third_party/openthread/repo:libopenthread-ftd", + ] + } else { + deps += [ + "${chip_root}/third_party/openthread/repo:libopenthread-cli-mtd", + "${chip_root}/third_party/openthread/repo:libopenthread-mtd", + ] + } + + cflags = [ "-Wconversion" ] + + if (use_smu2_as_system_memory) { + ldscript = "${k32w1_platform_dir}/app/ldscripts/k32w1_app.ld" + base_ldscript_dir = "${k32w1_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc" + } else { + ldscript = "${k32w1_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc/connectivity.ld" + } + + inputs = [ ldscript ] + + ldflags = [ + "-Wl,--defsym=__heap_size__=0", + "-Wl,--defsym=__stack_size__=0x480", + "-Wl,--defsym=gNvmSectors=8", + "-Wl,-print-memory-usage", + "-Wl,--no-warn-rwx-segments", + "-T" + rebase_path(ldscript, root_build_dir), + ] + + if (use_smu2_as_system_memory) { + ldflags += [ "-L" + rebase_path(base_ldscript_dir, root_build_dir) ] + } + + output_dir = root_out_dir +} + +group("k32w1") { + deps = [ ":light_app" ] +} + +group("default") { + deps = [ ":k32w1" ] +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/README.md b/examples/lighting-app/nxp/k32w/k32w1/README.md new file mode 100644 index 00000000000000..92dca287111449 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/README.md @@ -0,0 +1,425 @@ +# Matter K32W1 Lighting Example Application + +Matter K32W1 Lighting Example demonstrates how to remotely control a light bulb. +The light bulb is simulated using one of the LEDs from the expansion board. It +uses buttons to test turn on/turn off of the light bulb. You can use this +example as a reference for creating your own application. + +The example is based on +[Matter](https://github.com/project-chip/connectedhomeip) and the NXP K32W1 SDK, +and supports remote access and control of a light bulb over a low-power, +802.15.4 Thread network. + +The example behaves as a Matter accessory, that is a device that can be paired +into an existing Matter network and can be controlled by this network. + +
+ +- [Matter K32W1 Lighting Example Application](#matter-k32w1-lighting-example-application) +- [Introduction](#introduction) + - [Bluetooth LE Advertising](#bluetooth-le-advertising) + - [Bluetooth LE Rendezvous](#bluetooth-le-rendezvous) +- [Device UI](#device-ui) +- [Building](#building) + - [SMU2](#smu2-memory) +- [Flashing](#flashing) + - [Flashing the NBU image](#flashing-the-nbu-image) + - [Flashing the host image](#flashing-the-host-image) +- [Debugging](#debugging) +- [OTA](#ota) + + - [Convert srec into sb3 file](#convert-srec-into-sb3-file) + - [Convert sb3 into ota file](#convert-sb3-into-ota-file) + - [Running OTA](#running-ota) + - [Known issues](#known-issues) + + + +## Introduction + +![K32W1 EVK](../../../../platform/nxp/k32w/k32w1/doc/images/k32w1-evk.jpg) + +The K32W1 lighting example application provides a working demonstration of a +light bulb device, built using the Matter codebase and the NXP K32W1 SDK. The +example supports remote access (e.g.: using CHIP Tool from a mobile phone) and +control of a light bulb over a low-power, 802.15.4 Thread network. It is capable +of being paired into an existing Matter network along with other Matter-enabled +devices. + +The Matter device that runs the lighting application is controlled by the Matter +controller device over the Thread protocol. By default, the Matter device has +Thread disabled, and it should be paired over Bluetooth LE with the Matter +controller and obtain configuration from it. The actions required before +establishing full communication are described below. + +### Bluetooth LE Advertising + +In this example, to commission the device onto a Matter network, it must be +discoverable over Bluetooth LE. For security reasons, you must start Bluetooth +LE advertising manually after powering up the device by pressing Button SW2. + +### Bluetooth LE Rendezvous + +In this example, the commissioning procedure (called rendezvous) is done over +Bluetooth LE between a Matter device and the Matter controller, where the +controller has the commissioner role. + +To start the rendezvous, the controller must get the commissioning information +from the Matter device. The data payload is encoded within a QR code, or printed +to the UART console. + +### Thread Provisioning + +## Device UI + +The example application provides a simple UI that depicts the state of the +device and offers basic user control. This UI is implemented via the +general-purpose LEDs and buttons built in the K32W1 EVK board. + +**LED 2** shows the overall state of the device and its connectivity. Four +states are depicted: + +- _Short Flash On (50ms on/950ms off)_ — The device is in an + unprovisioned (unpaired) state and is waiting for a commissioning + application to connect. + +* _Rapid Even Flashing (100ms on/100ms off)_ — The device is in an + unprovisioned state and a commissioning application is connected via BLE. + +- _Short Flash Off (950ms on/50ms off)_ — The device is full + provisioned, but does not yet have full network (Thread) or service + connectivity. + +* _Solid On_ — The device is fully provisioned and has full network and + service connectivity. + +NOTE: LED2 will be disabled when CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR is +enabled. On K32W1 EVK board, `PTB0` is wired to LED2 also is wired to CS (Chip +Select) External Flash Memory. OTA image is stored in external memory because of +it's size. If LED2 is enabled then it will affect External Memory CS and OTA +will not work. + +**RGB LED** shows the state of the simulated light bulb. When the LED is lit the +light bulb is on; when not lit, the light bulb is off. + +**Button SW2** can be used to start BLE advertising. A SHORT press of the button +will enable Bluetooth LE advertising for a predefined period of time. A LONG +Press Button SW2 initiates a factory reset. After an initial period of 3 +seconds, LED 2 and RGB LED will flash in unison to signal the pending reset. +After 6 seconds will cause the device to reset its persistent configuration and +initiate a reboot. The reset action can be cancelled by press SW2 button at any +point before the 6 second limit. + +**Button SW3** can be used to change the state of the simulated light bulb. This +can be used to mimic a user manually operating a switch. The button behaves as a +toggle, swapping the state every time it is pressed. + +## Building + +In order to build the Matter example, we recommend using a Linux distribution +(the demo-application was compiled on Ubuntu 20.04). + +- Download [K32W1 SDK for Matter](https://mcuxpresso.nxp.com/). Creating an + nxp.com account is required before being able to download the SDK. Once the + account is created, login and follow the steps for downloading K32W148-EVK + MCUXpresso SDK. The SDK Builder UI selection should be similar with the one + from the image below. + + ![MCUXpresso SDK Download](../../../../platform/nxp/k32w/k32w1/doc/images/mcux-sdk-download.jpg) + + Please refer to Matter release notes for getting the latest released SDK. + +``` +user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_K32W1_SDK_ROOT=/home/user/Desktop/SDK_K32W1/ +user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/activate.sh +user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/lighting-app/nxp/k32w/k32w1 +user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w1$ gn gen out/debug --args="chip_with_ot_cli=0 is_debug=false chip_openthread_ftd=true chip_crypto=\"platform\"" +user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w1$ ninja -C out/debug +``` + +In case that Openthread CLI is needed, `chip_with_ot_cli` build argument must be +set to 1. + +After a successful build, the `elf` and `srec` files are found in `out/debug/` - +see the files prefixed with `chip-k32w1-light-example`. + +### `SMU2` Memory + +Some Matter instances and global variables can be placed in the `NBU` `SMU2` +memory. When compiling with OpenThread FTD support (`chip_openthread_ftd=true`) +and with `use_smu2_as_system_memory=true`, the following components are placed +in `SMU2` memory: + +- `gImageProcessor` from `OTAImageProcessorImpl.cpp`. +- `gApplicationProcessor` from `OTAHooks.cpp`. +- `Server::sServer` from `Server.cpp`. +- `ThreadStackManagerImpl::sInstance` from `ThreadStackManagerImpl.cpp`. + +These instances and global variables are placed in `SMU2` memory through name +matching in the application linker script. They should not be changed or, if +changed, the names must be updated in `k32w1_app.ld`. See +[k32w1_app.ld](../../../../platform/nxp/k32w/k32w1/app/ldscripts/k32w1_app.ld) +for names and `SMU2` memory range size. + +To use the `SMU2` Memory an optimized `NBU` binary is also needed. See +[Flashing the NBU image](#flashing-the-nbu-image). + +## Flashing + +Two images must be written to the board: one for the host (CM33) and one for the +`NBU` (CM3). + +The image needed on the host side is the one generated in `out/debug/` while the +one needed on the `NBU` side can be found in the downloaded NXP-SDK package at +path - +`middleware\wireless\ieee-802.15.4\bin\k32w1\k32w1_nbu_ble_15_4_dyn_matter_$version.sb3`. + +### Flashing the `NBU` image + +`NBU` image should be written only when a new NXP-SDK is released. + +[K32W148 board quick start guide](https://www.nxp.com/document/guide/getting-started-with-the-k32w148-development-platform:GS-K32W148EVK) +can be used for updating the `NBU/radio` core: + +- Section 2.4 – Get Software – install `SPSDK` (Secure Provisioning Command + Line Tool) +- Section 3.3 – Updating `NBU` for Wireless examples - use the corresponding + .sb3 file found in the SDK package at path + `middleware\wireless\ieee-802.15.4\bin\k32w1\` + +### Flashing the host image + +Host image is the one found under `out/debug/`. It should be written after each +build process. + +If debugging is needed then jump directly to the [Debugging](#debugging) +section. Otherwise, if only flashing is needed then +[JLink 7.84b](https://www.segger.com/downloads/jlink/) can be used: + +- Plug K32W1 to the USB port (no need to keep the SW4 button pressed while + doing this) + +- Create a new file, `commands_script`, with the following content (change + application name accordingly): + +```bash +reset +halt +loadfile chip-k32w1-light-example.srec +reset +go +quit +``` + +- copy the application and `commands_script` in the same folder that JLink + executable is placed. Execute: + +```bash +$ jlink -device K32W1480 -if SWD -speed 4000 -autoconnect 1 -CommanderScript commands_script +``` + +## Debugging + +One option for debugging would be to use MCUXpresso IDE. + +- Drag-and-drop the zip file containing the NXP SDK in the "Installed SDKs" + tab: + +![Installed SDKs](../../../../platform/nxp/k32w/k32w1/doc/images/installed_sdks.jpg) + +- Import any demo application from the installed SDK: + +``` +Import SDK example(s).. -> choose a demo app (demo_apps -> hello_world) -> Finish +``` + +![Import demo](../../../../platform/nxp/k32w/k32w1/doc/images/import_demo.jpg) + +- Flash the previously imported demo application on the board: + +``` +Right click on the application (from Project Explorer) -> Debug as -> JLink/CMSIS-DAP +``` + +After this step, a debug configuration specific for the K32W1 board was created. +This debug configuration will be used later on for debugging the application +resulted after ot-nxp compilation. + +- Import Matter repo in MCUXpresso IDE as Makefile Project. Use _none_ as + _Toolchain for Indexer Settings_: + +``` +File -> Import -> C/C++ -> Existing Code as Makefile Project +``` + +![New Project](../../../../platform/nxp/k32w/k32w1/doc/images/new_project.jpg) + +- Replace the path of the existing demo application with the path of the K32W1 + application: + +``` +Run -> Debug Configurations... -> C/C++ Application +``` + +![Debug K32W1](../../../../platform/nxp/k32w/k32w1/doc/images/debug_k32w1.jpg) + +## OTA + +### Convert `srec` into `sb3` file + +The OTA image files must be encrypted using Over The Air Programming Tool +([OTAP](https://www.nxp.com/design/microcontrollers-developer-resources/connectivity-tool-suite:CONNECTIVITY-TOOL-SUITE?#downloads)). +Bootloader will load the new OTA image only if it detects that the file was +encrypted with the `OTAP` correct keys. + +`.srec` file is input for Over The air Programming (`OTAP`) application +(unencrypted) and it's converted to `.sb3` format (encrypted). + +In `OTAP` application + +- select OTA protocol => `OTAP` Matter +- Browse File +- follow default options (KW45/K32W148, Preserve NVM) +- image information: will update "Application Core (MCU)" - this will generate + the image only for the CM33 core +- keep other settings at default values + +### Convert sb3 into ota file + +In order to build an OTA image, use NXP wrapper over the standard tool +`src/app/ota_image_tool.py`: + +- `scripts/tools/nxp/factory_data_generator/ota_image_tool.py` The tool can be + used to generate an OTA image with the following format: + `| OTA image header | TLV1 | TLV2 | ... | TLVn |` where each TLV is in the + form `|tag|length|value|` + +Note that "standard" TLV format is used. Matter TLV format is only used for +factory data TLV value. + +Please see more in the +[OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). + +Here is an example that generates an OTA image with application update TLV from +a sb3 file: + +``` +./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 43033 -vs "1.0" -da sha256 --app-input-file ~/binaries/chip-k32w1-43033.sb3 ~/binaries/chip-k32w1-43033.ota + +``` + +A note regarding OTA image header version (`-vn` option). An application binary +has its own software version (given by +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). For +having a correct OTA process, the OTA header version should be the same as the +binary embedded software version. A user can set a custom software version in +the gn build args by setting `chip_software_version` to the wanted version. + +### Running OTA + +The OTA topology used for OTA testing is illustrated in the figure below. +Topology is similar with the one used for Matter Test Events. + +![OTA_TOPOLOGY](../../../../platform/nxp/k32w/k32w1/doc/images/ota_topology.JPG) + +The concept for OTA is the next one: + +- there is an OTA Provider Application that holds the OTA image. In our case, + this is a Linux application running on an Ubuntu based-system; +- the OTA Requestor functionality is embedded inside the Lighting Application. + It will be used for requesting OTA blocks from the OTA Provider; +- the controller (a linux application called chip-tool) will be used for + commissioning both the device and the OTA Provider App. The device will be + commissioned using the standard Matter flow (BLE + IEEE 802.15.4) while the + OTA Provider Application will be commissioned using the _onnetwork_ option + of chip-tool; +- during commissioning, each device is assigned a node id by the chip-tool + (can be specified manually by the user). Using the node id of the device and + of the lighting application, chip-tool triggers the OTA transfer by invoking + the _announce-ota-provider_ command - basically, the OTA Requestor is + informed of the node id of the OTA Provider Application. + +_Computer #1_ can be any system running an Ubuntu distribution. We recommand +using CSA official instructions from +[here](https://groups.csa-iot.org/wg/matter-csg/document/28566), where RPi 4 are +proposed. Also, CSA official instructions document point to the OS/Docker images +that should be used on the RPis. For compatibility reasons, we recommand +compiling chip-tool and OTA Provider applications with the same commit id that +was used for compiling the Lighting Application. Also, please note that there is +a single controller (chip-tool) running on Computer #1 which is used for +commissioning both the device and the OTA Provider Application. If needed, +[these instructions](https://itsfoss.com/connect-wifi-terminal-ubuntu/) could be +used for connecting the RPis to WiFi. + +Build the Linux OTA provider application: + +``` +user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false +``` + +Build Linux chip-tool: + +``` +user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/chip-tool out/chip-tool-app +``` + +Start the OTA Provider Application: + +``` +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w1-43033.ota +``` + +Provision the OTA provider application and assign node id _1_. Also, grant ACL +entries to allow OTA requestors: + +``` +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing onnetwork 1 20202021 +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' 1 0 +``` + +Provision the device and assign node id _2_: + +``` +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing ble-thread 2 hex: 20202021 3840 +``` + +Start the OTA process: + +``` +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 2 0 +``` + +### Known issues + +- SRP cache on the openthread border router needs to flushed each time a new + commissioning process is attempted. For this, factory reset the device, then + execute _ot-ctl server disable_ followed by _ot-ctl server enable_. After + this step, the commissioning process of the device can start; +- Due to some MDNS issues, the commissioning of the OTA Provider Application + may fail. Please make sure that the SRP cache is disabled (_ot-ctl srp + server disable_) on the openthread border router while commissioning the OTA + Provider Application; +- No other Docker image should be running (e.g.: Docker image needed by Test + Harness) except the OTBR one. A docker image can be killed using the + command: + +``` +user@computer1:~/connectedhomeip$ : sudo docker kill $container_id +``` + +- In order to avoid MDNS issues, only one interface should be active at one + time. E.g.: if WiFi is used then disable the Ethernet interface and also + disable multicast on that interface: + +``` +user@computer1:~/connectedhomeip$ sudo ip link set dev eth0 down +user@computer1:~/connectedhomeip$ sudo ifconfig eth0 -multicast +``` + +- If OTBR Docker image is used, then the "-B" parameter should point to the + interface used for the backbone. + +- If Wi-Fi is used on a RPI4, then a 5Ghz network should be selected. + Otherwise, issues related to BLE-WiFi combo may appear. diff --git a/examples/lighting-app/nxp/k32w/k32w1/args.gni b/examples/lighting-app/nxp/k32w/k32w1/args.gni new file mode 100644 index 00000000000000..4efb6421f5ca02 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/args.gni @@ -0,0 +1,23 @@ +# 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("${chip_root}/examples/platform/nxp/k32w/k32w1/args.gni") + +# SDK target. This is overridden to add our SDK app_config.h & defines. +k32w1_sdk_target = get_label_info(":sdk", "label_no_toolchain") + +chip_enable_ota_requestor = true +chip_stack_lock_tracking = "fatal" +chip_enable_ble = true diff --git a/examples/lighting-app/nxp/k32w/k32w1/build_overrides b/examples/lighting-app/nxp/k32w/k32w1/build_overrides new file mode 120000 index 00000000000000..ad07557834803a --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/build_overrides @@ -0,0 +1 @@ +../../../../build_overrides/ \ No newline at end of file diff --git a/examples/lighting-app/nxp/k32w/k32w1/include/CHIPProjectConfig.h b/examples/lighting-app/nxp/k32w/k32w1/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..07d8b6a92f5e69 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/include/CHIPProjectConfig.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + +// Security and Authentication disabled for development build. +// For convenience, enable CHIP Security Test Mode and disable the requirement for +// authentication in various protocols. +// 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 + +// Use a default setup PIN code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +// Use a default pairing code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_PAIRING_CODE "CHIPUS" + +/** + * 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_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 100 + +#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING "v0.1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP 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 "03-2022-te8" +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 42020 +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME "NXP Semiconductors" +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME "NXP Demo App" +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC + * + * Enables synchronizing the device's real time clock with a remote CHIP Time service + * using the CHIP Time Sync protocol. + */ +// #define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 1 + +/** + * CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_TIMEOUT + * + * The amount of time in miliseconds after which BLE should change his advertisements + * from fast interval to slow interval. + * + * 30000 (30 secondes). + */ +#define CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_TIMEOUT (30 * 1000) + +/** + * CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT + * + * The amount of time in miliseconds after which BLE advertisement should be disabled, counting + * from the moment of slow advertisement commencement. + * + * Defaults to 9000000 (15 minutes). + */ +#define CHIP_DEVICE_CONFIG_BLE_ADVERTISING_TIMEOUT (15 * 60 * 1000) + +/** + * CONFIG_CHIP_NFC_COMMISSIONING, CHIP_DEVICE_CONFIG_ENABLE_NFC + * + * NFC commissioning is not supported on K32W1 + */ +#define CONFIG_CHIP_NFC_COMMISSIONING 0 +#define CHIP_DEVICE_CONFIG_ENABLE_NFC 0 + +/** + * @def CHIP_CONFIG_MAX_FABRICS + * + * @brief + * Maximum number of fabrics the device can participate in. Each fabric can + * provision the device with its unique operational credentials and manage + * its own access control lists. + */ +#define CHIP_CONFIG_MAX_FABRICS 5 // 5 is the minimum number of supported fabrics + +/** + * @def CHIP_IM_MAX_NUM_COMMAND_HANDLER + * + * @brief Defines the maximum number of CommandHandler, limits the number of active commands transactions on server. + */ +#define CHIP_IM_MAX_NUM_COMMAND_HANDLER 2 + +/** + * @def CHIP_IM_MAX_NUM_WRITE_HANDLER + * + * @brief Defines the maximum number of WriteHandler, limits the number of active write transactions on server. + */ +#define CHIP_IM_MAX_NUM_WRITE_HANDLER 2 + +/** + * CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE + * + * For a development build, set the default importance of events to be logged as Debug. + * Since debug is the lowest importance level, this means all standard, critical, info and + * debug importance level vi events get logged. + */ +#if BUILD_RELEASE +#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Production +#else +#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Debug +#endif // BUILD_RELEASE + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 diff --git a/examples/lighting-app/nxp/k32w/k32w1/include/FreeRTOSConfig.h b/examples/lighting-app/nxp/k32w/k32w1/include/FreeRTOSConfig.h new file mode 100644 index 00000000000000..95279e6337a7f7 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/include/FreeRTOSConfig.h @@ -0,0 +1,181 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#pragma once + +/*----------------------------------------------------------- + * 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. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_TICKLESS_IDLE 0 +/* Ensure stdint is only used by the compiler, and not the assembler. */ +#if defined(__ICCARM__) || defined(__ARMCC_VERSION) || defined(__GNUC__) +#include +extern uint32_t SystemCoreClock; +#endif +#define configCPU_CLOCK_HZ (SystemCoreClock) +#define configTICK_RATE_HZ ((TickType_t) 100) +#define configMAX_PRIORITIES (8) +// idle task stack size needs to be increased for OTA EEPROM processing +#define configMINIMAL_STACK_SIZE ((unsigned short) 450) +#define configMAX_TASK_NAME_LEN 20 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 8 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 + +/* Tasks.c additions (e.g. Thread Aware Debug capability) */ +#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 + +/* Used memory allocation (heap_x.c) */ +#define configFRTOS_MEMORY_SCHEME 4 + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE ((size_t) (gTotalHeapSize_c)) +#define configAPPLICATION_ALLOCATED_HEAP 1 + +/* Hook function related definitions. */ +#ifndef configUSE_IDLE_HOOK +#define configUSE_IDLE_HOOK 1 +#endif +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#ifndef configUSE_MALLOC_FAILED_HOOK +#define configUSE_MALLOC_FAILED_HOOK 0 +#endif +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Task aware debugging. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH (360) + +/* Define to trap errors during development. */ +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + taskDISABLE_INTERRUPTS(); \ + for (;;) \ + ; \ + } + +/* 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 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 0 +#define INCLUDE_xTaskGetHandle 0 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +/* Interrupt nesting behaviour configuration. Cortex-M specific. */ +#ifdef __NVIC_PRIO_BITS +/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ +#define configPRIO_BITS __NVIC_PRIO_BITS +#else +#define configPRIO_BITS 3 +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7 + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1 + +/* 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 (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) +/* !!!! 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 (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) + +#ifndef configENABLE_FPU +#define configENABLE_FPU 0 +#endif +#ifndef configENABLE_MPU +#define configENABLE_MPU 0 +#endif +#ifndef configENABLE_TRUSTZONE +#define configENABLE_TRUSTZONE 0 +#endif +#ifndef configRUN_FREERTOS_SECURE_ONLY +#define configRUN_FREERTOS_SECURE_ONLY 1 +#endif + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/AppTask.cpp b/examples/lighting-app/nxp/k32w/k32w1/main/AppTask.cpp new file mode 100644 index 00000000000000..66eee725c581c2 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/AppTask.cpp @@ -0,0 +1,870 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021 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 "AppEvent.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* OTA related includes */ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +#include "OtaSupport.h" +#include +#include +#include +#include +#include +#endif + +#include "K32W1PersistentStorageOpKeystore.h" + +#include "LEDWidget.h" +#include "app.h" +#include "app_config.h" +#include "fsl_component_button.h" +#include "fwk_platform.h" + +#define FACTORY_RESET_TRIGGER_TIMEOUT 6000 +#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 +#define APP_TASK_PRIORITY 2 +#define APP_EVENT_QUEUE_SIZE 10 + +TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. + +static QueueHandle_t sAppEventQueue; + +/* + * The status LED and the external flash CS pin are wired together. + * The OTA image writing may fail if used together. + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static LEDWidget sStatusLED; +#endif +static LEDWidget sLightLED; + +static bool sIsThreadProvisioned = false; +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static bool sHaveFullConnectivity = false; +#endif +static bool sHaveBLEConnections = false; + +#if CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI +extern "C" void otPlatUartProcess(void); +#endif + +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; +using namespace chip; +using namespace chip::app; + +AppTask AppTask::sAppTask; + +// This key is for testing/certification only and should not be used in production devices. +// For production devices this key must be provided from factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + +static Identify gIdentify = { chip::EndpointId{ 1 }, AppTask::OnIdentifyStart, AppTask::OnIdentifyStop, + Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator, AppTask::OnTriggerEffect, + // Use invalid value for identifiers to enable TriggerEffect command + // to stop Identify command for each effect + Clusters::Identify::EffectIdentifierEnum::kUnknownEnumValue, + Clusters::Identify::EffectVariantEnum::kDefault }; + +/* OTA related variables */ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static DefaultOTARequestor gRequestorCore; +static DefaultOTARequestorStorage gRequestorStorage; +static DeviceLayer::DefaultOTARequestorDriver gRequestorUser; +static BDXDownloader gDownloader; + +constexpr uint16_t requestedOtaBlockSize = 1024; +#endif + +CHIP_ERROR AppTask::StartAppTask() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + err = APP_ERROR_EVENT_QUEUE_FAILED; + K32W_LOG("Failed to allocate app event queue"); + assert(err == CHIP_NO_ERROR); + } + + return err; +} + +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + PlatformMgr().AddEventHandler(MatterEventHandler, 0); + + // Init ZCL Data Model and start server + PlatformMgr().ScheduleWork(InitServer, 0); + + // Initialize device attestation config + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + + // QR code will be used with CHIP Tool + AppTask::PrintOnboardingInfo(); + + if (LightingMgr().Init() != 0) + { + K32W_LOG("LightingMgr().Init() failed"); + assert(0); + } + + LightingMgr().SetCallbacks(ActionInitiated, ActionCompleted); + + /* start with all LEDS turnedd off */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Init(SYSTEM_STATE_LED, false); +#endif + sLightLED.Init(LIGHT_STATE_LED, false); + UpdateDeviceState(); + + /* intialize the Keyboard and button press callback */ + BUTTON_InstallCallback((button_handle_t) g_buttonHandle[0], KBD_Callback, (void *) BLE_BUTTON); + BUTTON_InstallCallback((button_handle_t) g_buttonHandle[1], KBD_Callback, (void *) LIGHT_BUTTON); + + // 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 + TimerEventHandler // timer callback handler + ); + + if (sFunctionTimer == NULL) + { + err = APP_ERROR_CREATE_TIMER_FAILED; + K32W_LOG("app_timer_create() failed"); + assert(err == CHIP_NO_ERROR); + } + + // Print the current software version + char currentSoftwareVer[ConfigurationManager::kMaxSoftwareVersionStringLength + 1] = { 0 }; + err = ConfigurationMgr().GetSoftwareVersionString(currentSoftwareVer, sizeof(currentSoftwareVer)); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Get version error"); + assert(err == CHIP_NO_ERROR); + } + + uint32_t currentVersion; + err = ConfigurationMgr().GetSoftwareVersion(currentVersion); + + K32W_LOG("Current Software Version: %s, %d", currentSoftwareVer, currentVersion); + + return err; +} + +void LockOpenThreadTask(void) +{ + chip::DeviceLayer::ThreadStackMgr().LockThreadStack(); +} + +void UnlockOpenThreadTask(void) +{ + chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack(); +} + +void AppTask::InitServer(intptr_t arg) +{ + static chip::CommonCaseDeviceServerInitParams initParams; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + +#if CHIP_CRYPTO_PLATFORM + static chip::K32W1PersistentStorageOpKeystore sK32W1PersistentStorageOpKeystore; + VerifyOrDie((sK32W1PersistentStorageOpKeystore.Init(initParams.persistentStorageDelegate)) == CHIP_NO_ERROR); + initParams.operationalKeystore = &sK32W1PersistentStorageOpKeystore; +#endif + + // Init ZCL Data Model and start server + static DefaultTestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + initParams.testEventTriggerDelegate = &testEventTriggerDelegate; + chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams; + nativeParams.lockCb = LockOpenThreadTask; + nativeParams.unlockCb = UnlockOpenThreadTask; + nativeParams.openThreadInstancePtr = chip::DeviceLayer::ThreadStackMgrImpl().OTInstance(); + initParams.endpointNativeParams = static_cast(&nativeParams); + VerifyOrDie((chip::Server::GetInstance().Init(initParams)) == CHIP_NO_ERROR); +} + +void AppTask::PrintOnboardingInfo() +{ + chip::PayloadContents payload; + CHIP_ERROR err = GetPayloadContents(payload, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "GetPayloadContents() failed: %" CHIP_ERROR_FORMAT, err.Format()); + } + payload.commissioningFlow = chip::CommissioningFlow::kUserActionRequired; + PrintOnboardingCodes(payload); +} + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void AppTask::InitOTA(intptr_t arg) +{ + // 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); + gRequestorUser.SetMaxDownloadBlockSize(requestedOtaBlockSize); + auto & imageProcessor = OTAImageProcessorImpl::GetDefaultInstance(); + gRequestorUser.Init(&gRequestorCore, &imageProcessor); + CHIP_ERROR err = imageProcessor.Init(&gDownloader); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Image processor init failed"); + assert(err == CHIP_NO_ERROR); + } + + // Connect the gDownloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&imageProcessor); + // Initialize and interconnect the Requestor and Image Processor objects -- END +} +#endif + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("AppTask.Init() failed"); + assert(err == CHIP_NO_ERROR); + } + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + + // 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 (PlatformMgr().TryLockChipStack()) + { +#if CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI + otPlatUartProcess(); +#endif + + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); + PlatformMgr().UnlockChipStack(); + } + + // Update the status LED if factory reset or identify process have 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 (sAppTask.mFunction != kFunction_FactoryReset) + { +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (sHaveFullConnectivity) + { + sStatusLED.Set(true); + } + else if (sIsThreadProvisioned) + { + sStatusLED.Blink(950, 50); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(100, 100); + } + else + { + sStatusLED.Blink(50, 950); + } +#endif + } + +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Animate(); +#endif + sLightLED.Animate(); + } +} + +void AppTask::ButtonEventHandler(uint8_t pin_no, uint8_t button_action) +{ + if ((pin_no != RESET_BUTTON) && (pin_no != LIGHT_BUTTON) && (pin_no != OTA_BUTTON) && (pin_no != BLE_BUTTON)) + { + return; + } + + AppEvent button_event; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.PinNo = pin_no; + button_event.ButtonEvent.Action = button_action; + + if (pin_no == LIGHT_BUTTON) + { + button_event.Handler = LightActionEventHandler; + } + else if (pin_no == OTA_BUTTON) + { + // button_event.Handler = OTAHandler; + } + else if (pin_no == BLE_BUTTON) + { + button_event.Handler = BleHandler; + + if (button_action == RESET_BUTTON_PUSH) + { + button_event.Handler = ResetActionEventHandler; + } + } + sAppTask.PostEvent(&button_event); +} + +button_status_t AppTask::KBD_Callback(void * buttonHandle, button_callback_message_t * message, void * callbackParam) +{ + uint32_t pinNb = (uint32_t) callbackParam; + switch (message->event) + { + case kBUTTON_EventOneClick: + case kBUTTON_EventShortPress: + switch (pinNb) + { + case BLE_BUTTON: + K32W_LOG("pb1 short press"); + if (sAppTask.mResetTimerActive) + { + ButtonEventHandler(BLE_BUTTON, RESET_BUTTON_PUSH); + } + else + { + ButtonEventHandler(BLE_BUTTON, BLE_BUTTON_PUSH); + } + break; + + case LIGHT_BUTTON: + K32W_LOG("pb2 short press"); + ButtonEventHandler(LIGHT_BUTTON, LIGHT_BUTTON_PUSH); + break; + } + break; + + case kBUTTON_EventLongPress: + switch (pinNb) + { + case BLE_BUTTON: + K32W_LOG("pb1 long press"); + ButtonEventHandler(BLE_BUTTON, RESET_BUTTON_PUSH); + break; + + case LIGHT_BUTTON: + K32W_LOG("pb2 long press"); + ButtonEventHandler(OTA_BUTTON, OTA_BUTTON_PUSH); + break; + } + break; + + default: + /* No action required */ + break; + } + return kStatus_BUTTON_Success; +} + +void AppTask::TimerEventHandler(TimerHandle_t xTimer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = (void *) xTimer; + event.Handler = FunctionTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + return; + + K32W_LOG("Device will factory reset..."); + + // Actually trigger Factory Reset + chip::Server::GetInstance().ScheduleFactoryReset(); +} + +void AppTask::ResetActionEventHandler(AppEvent * aEvent) +{ + if (aEvent->ButtonEvent.PinNo != RESET_BUTTON && aEvent->ButtonEvent.PinNo != BLE_BUTTON) + return; + + if (sAppTask.mResetTimerActive) + { + sAppTask.CancelTimer(); + sAppTask.mFunction = kFunction_NoneSelected; + + RestoreLightingState(); + + K32W_LOG("Factory Reset was cancelled!"); + } + else + { + uint32_t resetTimeout = FACTORY_RESET_TRIGGER_TIMEOUT; + + if (sAppTask.mFunction != kFunction_NoneSelected) + { + K32W_LOG("Another function is scheduled. Could not initiate Factory Reset!"); + return; + } + + K32W_LOG("Factory Reset Triggered. Push the RESET button within %lu ms to cancel!", resetTimeout); + sAppTask.mFunction = kFunction_FactoryReset; + + /* LEDs will start blinking to signal that a Factory Reset was scheduled */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Set(false); +#endif + sLightLED.Set(false); + +#ifndef CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + sStatusLED.Blink(500); +#endif + sLightLED.Blink(500); + + sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); + } +} + +void AppTask::LightActionEventHandler(AppEvent * aEvent) +{ + LightingManager::Action_t action; + CHIP_ERROR err = CHIP_NO_ERROR; + int32_t actor = 0; + bool initiated = false; + + if (sAppTask.mFunction != kFunction_NoneSelected) + { + K32W_LOG("Another function is scheduled. Could not initiate ON/OFF Light command!"); + return; + } + + if (aEvent->Type == AppEvent::kEventType_TurnOn) + { + action = static_cast(aEvent->LightEvent.Action); + actor = aEvent->LightEvent.Actor; + } + else if (aEvent->Type == AppEvent::kEventType_Button) + { + actor = AppEvent::kEventType_Button; + + if (LightingMgr().IsTurnedOff()) + { + action = LightingManager::TURNON_ACTION; + } + else + { + action = LightingManager::TURNOFF_ACTION; + } + } + else + { + err = APP_ERROR_UNHANDLED_EVENT; + action = LightingManager::INVALID_ACTION; + } + + if (err == CHIP_NO_ERROR) + { + initiated = LightingMgr().InitiateAction(actor, action); + + if (!initiated) + { + K32W_LOG("Action is already in progress or active."); + } + } +} + +void AppTask::OTAHandler(AppEvent * aEvent) +{ + if (aEvent->ButtonEvent.PinNo != OTA_BUTTON) + return; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (sAppTask.mFunction != kFunction_NoneSelected) + { + K32W_LOG("Another function is scheduled. Could not initiate OTA!"); + return; + } + + PlatformMgr().ScheduleWork(StartOTAQuery, 0); +#endif +} + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void AppTask::StartOTAQuery(intptr_t arg) +{ + GetRequestorInstance()->TriggerImmediateQuery(); +} +#endif + +void AppTask::BleHandler(AppEvent * aEvent) +{ + if (aEvent->ButtonEvent.PinNo != BLE_BUTTON) + return; + + if (sAppTask.mFunction != kFunction_NoneSelected) + { + K32W_LOG("Another function is scheduled. Could not toggle BLE state!"); + return; + } + PlatformMgr().ScheduleWork(AppTask::BleStartAdvertising, 0); +} + +void AppTask::BleStartAdvertising(intptr_t arg) +{ + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + ConnectivityMgr().SetBLEAdvertisingEnabled(false); + K32W_LOG("Stopped BLE Advertising!"); + } + else + { + ConnectivityMgr().SetBLEAdvertisingEnabled(true); + if (chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() == CHIP_NO_ERROR) + { + K32W_LOG("Started BLE Advertising!"); + } + else + { + K32W_LOG("OpenBasicCommissioningWindow() failed"); + } + } +} + +void AppTask::MatterEventHandler(const ChipDeviceEvent * event, intptr_t) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (event->Type == DeviceEventType::kDnssdInitialized) + { + K32W_LOG("Dnssd platform initialized."); + PlatformMgr().ScheduleWork(InitOTA, 0); + } +#else + if (event->Type == DeviceEventType::kDnssdInitialized) + { + sHaveFullConnectivity = TRUE; + } +#endif +} + +void AppTask::CancelTimer() +{ + if (xTimerStop(sFunctionTimer, 0) == pdFAIL) + { + K32W_LOG("app timer stop() failed"); + } + + mResetTimerActive = false; +} + +void AppTask::StartTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sFunctionTimer)) + { + K32W_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(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + K32W_LOG("app timer start() failed"); + } + + mResetTimerActive = true; +} + +void AppTask::ActionInitiated(LightingManager::Action_t aAction, int32_t aActor) +{ + // start flashing the LEDs rapidly to indicate action initiation. + if (aAction == LightingManager::TURNON_ACTION) + { + K32W_LOG("Turn on Action has been initiated") + } + else if (aAction == LightingManager::TURNOFF_ACTION) + { + K32W_LOG("Turn off Action has been initiated") + } + + if (aActor == AppEvent::kEventType_Button) + { + sAppTask.mSyncClusterToButtonAction = true; + } + + sAppTask.mFunction = kFunctionTurnOnTurnOff; +} + +void AppTask::ActionCompleted(LightingManager::Action_t aAction) +{ + // Turn on the light LED if in a TURNON state OR + // Turn off the light LED if in a TURNOFF state. + if (aAction == LightingManager::TURNON_ACTION) + { + K32W_LOG("Turn on action has been completed") + sLightLED.Set(true); + } + else if (aAction == LightingManager::TURNOFF_ACTION) + { + K32W_LOG("Turn off action has been completed") + sLightLED.Set(false); + } + + if (sAppTask.mSyncClusterToButtonAction) + { + sAppTask.UpdateClusterState(); + sAppTask.mSyncClusterToButtonAction = false; + } + + sAppTask.mFunction = kFunction_NoneSelected; +} + +void AppTask::RestoreLightingState(void) +{ + /* restore initial state for the LED indicating Lighting state */ + if (LightingMgr().IsTurnedOff()) + { + sLightLED.Set(false); + } + else + { + sLightLED.Set(true); + } +} + +void AppTask::OnIdentifyStart(Identify * identify) +{ + if ((kFunction_NoneSelected != sAppTask.mFunction) && (kFunction_TriggerEffect != sAppTask.mFunction)) + { + K32W_LOG("Another function is scheduled. Could not initiate Identify process!"); + return; + } + + if (kFunction_TriggerEffect == sAppTask.mFunction) + { + chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectComplete, identify); + OnTriggerEffectComplete(&chip::DeviceLayer::SystemLayer(), identify); + } + + ChipLogProgress(Zcl, "Identify process has started. Status LED should blink with a period of 0.5 seconds."); + sAppTask.mFunction = kFunction_Identify; + sLightLED.Set(false); + sLightLED.Blink(250); +} + +void AppTask::OnIdentifyStop(Identify * identify) +{ + if (kFunction_Identify == sAppTask.mFunction) + { + ChipLogProgress(Zcl, "Identify process has stopped."); + sAppTask.mFunction = kFunction_NoneSelected; + + RestoreLightingState(); + } +} + +void AppTask::OnTriggerEffectComplete(chip::System::Layer * systemLayer, void * appState) +{ + // Let Identify command take over if called during TriggerEffect already running + if (kFunction_TriggerEffect == sAppTask.mFunction) + { + ChipLogProgress(Zcl, "TriggerEffect has stopped."); + sAppTask.mFunction = kFunction_NoneSelected; + + // TriggerEffect finished - reset identifiers + // Use invalid value for identifiers to enable TriggerEffect command + // to stop Identify command for each effect + gIdentify.mCurrentEffectIdentifier = Clusters::Identify::EffectIdentifierEnum::kUnknownEnumValue; + gIdentify.mTargetEffectIdentifier = Clusters::Identify::EffectIdentifierEnum::kUnknownEnumValue; + gIdentify.mEffectVariant = Clusters::Identify::EffectVariantEnum::kDefault; + + RestoreLightingState(); + } +} + +void AppTask::OnTriggerEffect(Identify * identify) +{ + // Allow overlapping TriggerEffect calls + if ((kFunction_NoneSelected != sAppTask.mFunction) && (kFunction_TriggerEffect != sAppTask.mFunction)) + { + K32W_LOG("Another function is scheduled. Could not initiate Identify process!"); + return; + } + + sAppTask.mFunction = kFunction_TriggerEffect; + uint16_t timerDelay = 0; + + ChipLogProgress(Zcl, "TriggerEffect has started."); + + switch (identify->mCurrentEffectIdentifier) + { + case Clusters::Identify::EffectIdentifierEnum::kBlink: + timerDelay = 2; + break; + + case Clusters::Identify::EffectIdentifierEnum::kBreathe: + timerDelay = 15; + break; + + case Clusters::Identify::EffectIdentifierEnum::kOkay: + timerDelay = 4; + break; + + case Clusters::Identify::EffectIdentifierEnum::kChannelChange: + ChipLogProgress(Zcl, "Channel Change effect not supported, using effect %d", + to_underlying(Clusters::Identify::EffectIdentifierEnum::kBlink)); + timerDelay = 2; + break; + + case Clusters::Identify::EffectIdentifierEnum::kFinishEffect: + chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectComplete, identify); + timerDelay = 1; + break; + + case Clusters::Identify::EffectIdentifierEnum::kStopEffect: + chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectComplete, identify); + OnTriggerEffectComplete(&chip::DeviceLayer::SystemLayer(), identify); + break; + + default: + ChipLogProgress(Zcl, "Invalid effect identifier."); + } + + if (timerDelay) + { + sLightLED.Set(false); + sLightLED.Blink(500); + + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(timerDelay), OnTriggerEffectComplete, identify); + } +} + +void AppTask::PostTurnOnActionRequest(int32_t aActor, LightingManager::Action_t aAction) +{ + AppEvent event; + event.Type = AppEvent::kEventType_TurnOn; + event.LightEvent.Actor = aActor; + event.LightEvent.Action = aAction; + event.Handler = LightActionEventHandler; + PostEvent(&event); +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + if (sAppEventQueue != NULL) + { + if (!xQueueSend(sAppEventQueue, aEvent, 1)) + { + K32W_LOG("Failed to post event to app task event queue"); + } + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + K32W_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateClusterState(void) +{ + PlatformMgr().ScheduleWork(UpdateClusterStateInternal, 0); +} + +void AppTask::UpdateClusterStateInternal(intptr_t arg) +{ + uint8_t newValue = !LightingMgr().IsTurnedOff(); + + // write the new on/off value + EmberAfStatus status = app::Clusters::OnOff::Attributes::OnOff::Set(1, newValue); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(NotSpecified, "ERR: updating on/off %x", status); + } +} + +void AppTask::UpdateDeviceState(void) +{ + PlatformMgr().ScheduleWork(UpdateDeviceStateInternal, 0); +} + +void AppTask::UpdateDeviceStateInternal(intptr_t arg) +{ + bool onoffAttrValue = 0; + + /* get onoff attribute value */ + (void) app::Clusters::OnOff::Attributes::OnOff::Get(1, &onoffAttrValue); + + /* set the device state */ + sLightLED.Set(onoffAttrValue); + LightingMgr().SetState(onoffAttrValue); +} + +extern "C" void OTAIdleActivities(void) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + OTA_TransactionResume(); +#endif +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/LightingManager.cpp b/examples/lighting-app/nxp/k32w/k32w1/main/LightingManager.cpp new file mode 100644 index 00000000000000..7a5cefc9b668fc --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/LightingManager.cpp @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 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 "AppTask.h" +#include "FreeRTOS.h" + +#include "app_config.h" + +LightingManager LightingManager::sLight; + +int LightingManager::Init() +{ + mState = kState_On; + + return 0; +} + +void LightingManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) +{ + mActionInitiated_CB = aActionInitiated_CB; + mActionCompleted_CB = aActionCompleted_CB; +} + +void LightingManager::SetState(bool state) +{ + mState = state ? kState_On : kState_Off; +} + +bool LightingManager::IsTurnedOff() +{ + return (mState == kState_Off) ? true : false; +} + +bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction) +{ + bool action_initiated = false; + + if (mState == kState_On && aAction == TURNOFF_ACTION) + { + action_initiated = true; + mState = kState_Off; + } + else if (mState == kState_Off && aAction == TURNON_ACTION) + { + action_initiated = true; + mState = kState_On; + } + + if (action_initiated) + { + if (mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor); + } + if (mActionCompleted_CB) + { + mActionCompleted_CB(aAction); + } + } + + return action_initiated; +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/ZclCallbacks.cpp b/examples/lighting-app/nxp/k32w/k32w1/main/ZclCallbacks.cpp new file mode 100644 index 00000000000000..5a4eee6e2c09e4 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/ZclCallbacks.cpp @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "AppTask.h" +#include "LightingManager.h" + +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app::Clusters; + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & path, uint8_t type, uint16_t size, uint8_t * value) +{ + if (path.mClusterId == OnOff::Id) + { + if (path.mAttributeId != OnOff::Attributes::OnOff::Id) + { + ChipLogProgress(Zcl, "Unknown attribute ID: " ChipLogFormatMEI, ChipLogValueMEI(path.mAttributeId)); + return; + } + + LightingMgr().InitiateAction(0, *value ? LightingManager::TURNON_ACTION : LightingManager::TURNOFF_ACTION); + } + else if (path.mClusterId == LevelControl::Id) + { + ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(path.mAttributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (path.mClusterId == ColorControl::Id) + { + ChipLogProgress(Zcl, "Color Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(path.mAttributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (path.mClusterId == OnOffSwitchConfiguration::Id) + { + ChipLogProgress(Zcl, "OnOff Switch Configuration attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(path.mAttributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else + { + ChipLogProgress(Zcl, "Unknown attribute ID: " ChipLogFormatMEI, ChipLogValueMEI(path.mAttributeId)); + } +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/include/AppEvent.h b/examples/lighting-app/nxp/k32w/k32w1/main/include/AppEvent.h new file mode 100644 index 00000000000000..902c70b3cb656f --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/include/AppEvent.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2021 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_None = 0, + kEventType_Button, + kEventType_Timer, + kEventType_TurnOn, + kEventType_Install, + kEventType_OTAResume, + }; + + AppEventTypes Type; + + union + { + struct + { + uint8_t PinNo; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LightEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/include/AppTask.h b/examples/lighting-app/nxp/k32w/k32w1/main/include/AppTask.h new file mode 100644 index 00000000000000..db81edf168c41e --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/include/AppTask.h @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2021 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 "LightingManager.h" + +#include +#include + +#include "FreeRTOS.h" +#include "fsl_component_button.h" +#include "timers.h" + +// 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) + +class AppTask +{ +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + + void PostTurnOnActionRequest(int32_t aActor, LightingManager::Action_t aAction); + void PostEvent(const AppEvent * event); + + void UpdateClusterState(void); + void UpdateDeviceState(void); + + // Identify cluster callbacks. + static void OnIdentifyStart(Identify * identify); + static void OnIdentifyStop(Identify * identify); + static void OnTriggerEffect(Identify * identify); + static void OnTriggerEffectComplete(chip::System::Layer * systemLayer, void * appState); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor); + static void ActionCompleted(LightingManager::Action_t aAction); + + void CancelTimer(void); + + void DispatchEvent(AppEvent * event); + + static void FunctionTimerEventHandler(AppEvent * aEvent); + static button_status_t KBD_Callback(void * buttonHandle, button_callback_message_t * message, void * callbackParam); + static void OTAHandler(AppEvent * aEvent); + static void BleHandler(AppEvent * aEvent); + static void BleStartAdvertising(intptr_t arg); + static void LightActionEventHandler(AppEvent * aEvent); + static void ResetActionEventHandler(AppEvent * aEvent); + static void InstallEventHandler(AppEvent * aEvent); + + static void ButtonEventHandler(uint8_t pin_no, uint8_t button_action); + static void TimerEventHandler(TimerHandle_t xTimer); + + static void MatterEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void StartTimer(uint32_t aTimeoutInMs); + + static void RestoreLightingState(void); + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static void InitOTA(intptr_t arg); + static void StartOTAQuery(intptr_t arg); +#endif + + static void UpdateClusterStateInternal(intptr_t arg); + static void UpdateDeviceStateInternal(intptr_t arg); + static void InitServer(intptr_t arg); + static void PrintOnboardingInfo(); + + enum Function_t + { + kFunction_NoneSelected = 0, + kFunction_FactoryReset, + kFunctionTurnOnTurnOff, + kFunction_Identify, + kFunction_TriggerEffect, + kFunction_Invalid + } Function; + + Function_t mFunction = kFunction_NoneSelected; + bool mResetTimerActive = false; + bool mSyncClusterToButtonAction = false; + + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/include/LightingManager.h b/examples/lighting-app/nxp/k32w/k32w1/main/include/LightingManager.h new file mode 100644 index 00000000000000..327bf3bdf02763 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/include/LightingManager.h @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2021 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 + +class LightingManager +{ +public: + enum Action_t + { + TURNON_ACTION = 0, + TURNOFF_ACTION, + + INVALID_ACTION + } Action; + + enum State_t + { + kState_On = 0, + kState_Off, + } State; + + int Init(); + bool IsTurnedOff(); + 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); + void SetState(bool state); + +private: + friend LightingManager & LightingMgr(void); + State_t mState; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + static LightingManager sLight; +}; + +inline LightingManager & LightingMgr(void) +{ + return LightingManager::sLight; +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/include/app_config.h b/examples/lighting-app/nxp/k32w/k32w1/main/include/app_config.h new file mode 100644 index 00000000000000..ff938f494b089d --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/include/app_config.h @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2021 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 + +// ---- Light Example App Config ---- + +#define RESET_BUTTON 1 +#define LIGHT_BUTTON 2 +#define OTA_BUTTON 3 +#define BLE_BUTTON 4 + +#define RESET_BUTTON_PUSH 1 +#define LIGHT_BUTTON_PUSH 2 +#define OTA_BUTTON_PUSH 3 +#define BLE_BUTTON_PUSH 4 + +#define APP_BUTTON_PUSH 1 + +#define LIGHT_STATE_LED 1 +#define SYSTEM_STATE_LED 0 + +// Time it takes for the light to switch on/off +#define ACTUATOR_MOVEMENT_PERIOS_MS 50 + +// ---- Light Example SWU Config ---- +#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours +#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours + +#if K32W_LOG_ENABLED +#define K32W_LOG(...) otPlatLog(OT_LOG_LEVEL_NONE, OT_LOG_REGION_API, ##__VA_ARGS__); +#else +#define K32W_LOG(...) +#endif diff --git a/examples/lighting-app/nxp/k32w/k32w1/main/main.cpp b/examples/lighting-app/nxp/k32w/k32w1/main/main.cpp new file mode 100644 index 00000000000000..7ebd3f3ed3b1b7 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/main/main.cpp @@ -0,0 +1,140 @@ +/* + * + * Copyright (c) 2021 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. + */ + +// ================================================================================ +// Main Code +// ================================================================================ + +#include "openthread/platform/logging.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "FreeRtosHooks.h" +#include "app_config.h" + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +using namespace ::chip::Logging; + +#include + +typedef void (*InitFunc)(void); +extern InitFunc __init_array_start; +extern InitFunc __init_array_end; + +extern "C" void main_task(void const * argument) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + /* Call C++ constructors */ + InitFunc * pFunc = &__init_array_start; + for (; pFunc < &__init_array_end; ++pFunc) + { + (*pFunc)(); + } + + mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); + + err = PlatformMgrImpl().InitBoardFwk(); + if (err != CHIP_NO_ERROR) + { + return; + } + + /* Used for HW initializations */ + otSysInit(0, NULL); + + K32W_LOG("Welcome to NXP Lighting Demo App"); + + /* Mbedtls Threading support is needed because both + * Thread and Matter tasks are using it */ + freertos_mbedtls_mutex_init(); + + // Init Chip memory management before the stack + chip::Platform::MemoryInit(); + + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during PlatformMgr().InitMatterStack()"); + goto exit; + } + + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during ThreadStackMgr().InitThreadStack()"); + goto exit; + } + + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router); + + if (err != CHIP_NO_ERROR) + { + goto exit; + } + + // Start OpenThread task + err = ThreadStackMgrImpl().StartThreadTask(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during ThreadStackMgrImpl().StartThreadTask()"); + goto exit; + } + + err = GetAppTask().StartAppTask(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during GetAppTask().StartAppTask()"); + goto exit; + } + + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + K32W_LOG("Error during PlatformMgr().StartEventLoopTask();"); + goto exit; + } + + GetAppTask().AppTaskMain(NULL); + +exit: + return; +} + +/** + * 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); + } +} diff --git a/examples/lighting-app/nxp/k32w/k32w1/third_party/connectedhomeip b/examples/lighting-app/nxp/k32w/k32w1/third_party/connectedhomeip new file mode 120000 index 00000000000000..305f2077ffe860 --- /dev/null +++ b/examples/lighting-app/nxp/k32w/k32w1/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../../.. \ No newline at end of file diff --git a/examples/platform/nxp/k32w/k32w1/BUILD.gn b/examples/platform/nxp/k32w/k32w1/BUILD.gn new file mode 100644 index 00000000000000..0a980406bce075 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/BUILD.gn @@ -0,0 +1,33 @@ +# 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/k32w1_sdk.gni") + +import("${k32w1_sdk_build_root}/k32w1_sdk.gni") + +config("chip_examples_project_config") { + include_dirs = [ + "app/project_include", + "${chip_root}", + ] +} + +source_set("openthread_core_config_k32w1_chip_examples") { + sources = [ "app/project_include/OpenThreadConfig.h" ] + + public_deps = [ "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w1:openthread_core_config_k32w1" ] + + public_configs = [ ":chip_examples_project_config" ] +} diff --git a/examples/platform/nxp/k32w/k32w1/app/BUILD.gn b/examples/platform/nxp/k32w/k32w1/app/BUILD.gn new file mode 100644 index 00000000000000..6671d140688df9 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/BUILD.gn @@ -0,0 +1,27 @@ +# 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") + +config("chip_examples_project_config") { + include_dirs = [ "app/project_include" ] +} + +source_set("openthread_core_config_k32w1_chip_examples") { + sources = [ "app/project_include/OpenThreadConfig.h" ] + + public_deps = [ "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w1:openthread_core_config_k32w1" ] + + public_configs = [ ":chip_examples_project_config" ] +} diff --git a/examples/platform/nxp/k32w/k32w1/app/args.gni b/examples/platform/nxp/k32w/k32w1/app/args.gni new file mode 100644 index 00000000000000..c09510c14df229 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/args.gni @@ -0,0 +1,33 @@ +# 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("${chip_root}/src/platform/nxp/k32w/k32w1/args.gni") + +arm_float_abi = "hard" +arm_cpu = "cortex-m33" +arm_fpu = "fpv5-sp-d16" +arm_arch = "armv8-m.main+dsp+fp" + +openthread_project_core_config_file = "OpenThreadConfig.h" + +chip_ble_project_config_include = "" +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_inet_project_config_include = "" +chip_system_project_config_include = "" + +chip_system_config_provide_statistics = false +chip_with_nlfaultinjection = true diff --git a/examples/platform/nxp/k32w/k32w1/app/ldscripts/k32w1_app.ld b/examples/platform/nxp/k32w/k32w1/app/ldscripts/k32w1_app.ld new file mode 100644 index 00000000000000..de9c882af9fed4 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/ldscripts/k32w1_app.ld @@ -0,0 +1,52 @@ +/* +** Copyright (c) 2023 Project CHIP Authors +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +m_smu2_data_start = 0x489C0000; +m_smu2_data_end = 0x489C537B; +m_smu2_data_size = m_smu2_data_end - m_smu2_data_start + 1; + +/* Specify the extra application specific memory areas */ +MEMORY +{ + m_smu2_data (RW) : ORIGIN = m_smu2_data_start, LENGTH = m_smu2_data_size +} + + +/* Define the extra application specific output sections */ +SECTIONS +{ + .smu2 (NOLOAD) : + { + /* This is used by the startup in order to initialize the free .smu2 section */ + . = ALIGN(4); + __START_SMU2 = .; + __smu2_start__ = .; + *(.smu2) + /* These input section descriptions should not be changed as they match */ + /* specific Matter instances/global variables. */ + *(.bss.*chip*Server*sServer*) + *(*gImageProcessor) + *(*gApplicationProcessor) + *(.bss.*ThreadStackManagerImpl*sInstance*) + . = ALIGN(4); + __smu2_end__ = .; + __END_SMU2 = .; + ASSERT(__smu2_end__ > 18K, "SMU2 section unexpected end address, check variable names"); + } > m_smu2_data +} + + +INCLUDE connectivity.ld diff --git a/examples/platform/nxp/k32w/k32w1/app/project_include/OpenThreadConfig.h b/examples/platform/nxp/k32w/k32w1/app/project_include/OpenThreadConfig.h new file mode 100644 index 00000000000000..932812aa711659 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/project_include/OpenThreadConfig.h @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 2020 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 + +// Disable the Nxp-supplied OpenThread logging facilities +// and use the facilities provided by the Device Layer +// (see src/platform/K32W/Logging.cpp). +#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_APP + +// When operating in a less than ideal RF environment, having a more forgiving configuration +// of OpenThread makes thread a great deal more reliable. +#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY 120 // default is 28800 +#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT 15 // default is 3 +#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT 1 // default is 0 +#define OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS 16 // default is 4 + +// Enable periodic parent search to speed up finding a better parent. +#define OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE 1 // default is 0 +#define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -45 // default is -65 +#define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1 // default is 0 + +// Use smaller maximum interval to speed up reattaching. +#define OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_MAXIMUM_INTERVAL (60 * 10 * 1000) // default 1200000 ms + +// 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 + +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 0 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 0 + +#define OPENTHREAD_CONFIG_DUA_ENABLE 1 +#define OPENTHREAD_CONFIG_MLR_ENABLE 1 + +#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1 +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE 0 +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE 0 + +#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 30 + +#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 0 + +// #define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_DEBG + +// Use the NXP-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-k32w1-config.h" diff --git a/examples/platform/nxp/k32w/k32w1/app/support/BUILD.gn b/examples/platform/nxp/k32w/k32w1/app/support/BUILD.gn new file mode 100644 index 00000000000000..dafa6de4d3d31d --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/support/BUILD.gn @@ -0,0 +1,53 @@ +# 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/k32w1_sdk.gni") + +config("support_config") { + include_dirs = [ "../../../../.." ] + + # Link options that provides replace 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", + "-Wl,--gc-sections,--defsym=gUseNVMLink_d=1", + ] +} + +source_set("freertos_mbedtls_utils") { + sources = [ + "FreeRtosHooks.c", + "FreeRtosHooks.h", + "Memconfig.cpp", + ] + + deps = [ "${chip_root}/src/lib/support" ] + + cflags = [ "-Wconversion" ] + + public_configs = [ ":support_config" ] +} diff --git a/examples/platform/nxp/k32w/k32w1/app/support/FreeRtosHooks.c b/examples/platform/nxp/k32w/k32w1/app/support/FreeRtosHooks.c new file mode 100644 index 00000000000000..83549b1dc1f04a --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/support/FreeRtosHooks.c @@ -0,0 +1,152 @@ +/* + * + * Copyright (c) 2020 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 "FreeRtosHooks.h" + +#include "FreeRTOS.h" +#include "semphr.h" + +#include + +#include +#include + +#include "NVM_Interface.h" +#include "PWR_Interface.h" +#include "board.h" +#include "fsl_os_abstraction.h" + +/* Bluetooth Low Energy */ +#include "ble_config.h" +#include "l2ca_cb_interface.h" + +#if defined gLoggingActive_d && (gLoggingActive_d > 0) +#include "dbg_logging.h" +#ifndef DBG_APP +#define DBG_APP 0 +#endif +#define APP_DBG_LOG(fmt, ...) \ + if (DBG_APP) \ + do \ + { \ + DbgLogAdd(__FUNCTION__, fmt, VA_NUM_ARGS(__VA_ARGS__), ##__VA_ARGS__); \ + } while (0); +#else +#define APP_DBG_LOG(...) +#endif + +#if (configUSE_TICKLESS_IDLE != 0) +extern uint64_t PWR_TryEnterLowPower(uint64_t timeoutUs); +#endif + +static inline void mutex_init(mbedtls_threading_mutex_t * p_mutex) +{ + assert(p_mutex != NULL); + *p_mutex = xSemaphoreCreateMutex(); + assert(*p_mutex != NULL); +} + +static inline void mutex_free(mbedtls_threading_mutex_t * p_mutex) +{ + assert(p_mutex != NULL); + assert(*p_mutex != NULL); + vSemaphoreDelete(*p_mutex); +} + +static inline int mutex_lock(mbedtls_threading_mutex_t * p_mutex) +{ + assert(p_mutex != NULL); + assert(*p_mutex != NULL); + return xSemaphoreTake(*p_mutex, portMAX_DELAY) != pdTRUE; +} + +static inline int mutex_unlock(mbedtls_threading_mutex_t * p_mutex) +{ + assert(p_mutex != NULL); + assert(*p_mutex != NULL); + return xSemaphoreGive(*p_mutex) != pdTRUE; +} + +void freertos_mbedtls_mutex_init(void) +{ + mbedtls_threading_set_alt(mutex_init, mutex_free, mutex_lock, mutex_unlock); +} + +void freertos_mbedtls_mutex_free(void) +{ + mbedtls_threading_free_alt(); +} + +#if (configUSE_TICKLESS_IDLE != 0) + +/*! ********************************************************************************* + *\private + *\fn void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) + *\brief This function will try to put the MCU into a deep sleep mode for at + * most the maximum OS idle time specified. Else the MCU will enter a + * sleep mode until the first IRQ. + * + *\param [in] xExpectedIdleTime The idle time in OS ticks. + * + *\retval none. + * + *\remarks This feature is available only for FreeRTOS. + ********************************************************************************** */ +void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime) +{ + bool abortIdle = false; + uint64_t actualIdleTimeUs, expectedIdleTimeUs; + + /* The OSA_InterruptDisable() API will prevent us to wakeup so we use + * OSA_DisableIRQGlobal() */ + OSA_DisableIRQGlobal(); + + /* Disable and prepare systicks for low power */ + abortIdle = PWR_SysticksPreProcess((uint32_t) xExpectedIdleTime, &expectedIdleTimeUs); + + if (abortIdle == false) + { + /* Enter low power with a maximal timeout */ + actualIdleTimeUs = PWR_TryEnterLowPower(expectedIdleTimeUs); + + /* Re enable systicks and compensate systick timebase */ + PWR_SysticksPostProcess(expectedIdleTimeUs, actualIdleTimeUs); + } + + /* Exit from critical section */ + OSA_EnableIRQGlobal(); +} +#endif + +extern void OTAIdleActivities(void); + +void vApplicationIdleHook(void) +{ + // Data queued by PDM will be written to external flash + // when PDM_vIdleTask is called. Interrupts are disabled + // to ensure there is no context switch during the actual + // writing, thus avoiding race conditions. + OSA_InterruptDisable(); +#if CHIP_PLAT_NVM_SUPPORT + NvIdle(); +#endif + OSA_InterruptEnable(); + + OTAIdleActivities(); +} diff --git a/examples/platform/nxp/k32w/k32w1/app/support/FreeRtosHooks.h b/examples/platform/nxp/k32w/k32w1/app/support/FreeRtosHooks.h new file mode 100644 index 00000000000000..a27f72d498f81d --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/support/FreeRtosHooks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 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 + +typedef void * mbedtls_threading_mutex_t; + +extern void mbedtls_threading_set_alt(void (*mutex_init)(mbedtls_threading_mutex_t *), + void (*mutex_free)(mbedtls_threading_mutex_t *), + int (*mutex_lock)(mbedtls_threading_mutex_t *), + int (*mutex_unlock)(mbedtls_threading_mutex_t *)); + +extern void mbedtls_threading_free_alt(void); + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Function for initializing alternative MbedTLS mutexes to enable the usage of the FreeRTOS implementation. */ +void freertos_mbedtls_mutex_init(void); + +/**@brief Function for releasing MbedTLS alternative mutexes. */ +void freertos_mbedtls_mutex_free(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/nxp/k32w/k32w1/app/support/Memconfig.cpp b/examples/platform/nxp/k32w/k32w1/app/support/Memconfig.cpp new file mode 100644 index 00000000000000..e5acf5ea3ceecb --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/app/support/Memconfig.cpp @@ -0,0 +1,184 @@ +/* + * + * 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. + */ + +/** + * @file + * This file contains platform specific implementations for stdlib malloc/calloc/realloc/free + * functions, so that CHIPPlatformMemory* works as intended with the platform's heap. + */ + +#include "FreeRTOS.h" +#include "task.h" +#include +#include +#include + +#ifndef NDEBUG +#include +#include +#endif + +#include + +#if CHIP_CONFIG_MEMORY_DEBUG_DMALLOC +#include +#include +#endif // CHIP_CONFIG_MEMORY_DEBUG_DMALLOC + +/* Assumes 8bit bytes! */ +#define heapBITS_PER_BYTE ((size_t) 8) + +/* Define the linked list structure. This is used to link free blocks in order +of their memory address. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +} BlockLink_t; + +/* The size of the structure placed at the beginning of each allocated memory +block must by correctly byte aligned. */ +static const size_t xHeapStructSize = + (sizeof(BlockLink_t) + ((size_t) (portBYTE_ALIGNMENT - 1))) & ~((size_t) portBYTE_ALIGNMENT_MASK); + +/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize +member of an BlockLink_t structure is set then the block belongs to the +application. When the bit is free the block is still part of the free heap +space. */ +static size_t xBlockAllocatedBit = ((size_t) 1) << ((sizeof(size_t) * heapBITS_PER_BYTE) - 1); + +extern "C" { + +/* xPortMallocUsableSize relies on heap4 implementation. +It returns the size of an allocated block and it is +called by __wrap_realloc. +Thus it is validated in __wrap_realloc function that the allocated size +of the old_ptr is smaller than the allocated size of new_ptr */ +size_t xPortMallocUsableSize(void * pv) +{ + uint8_t * puc = (uint8_t *) pv; + BlockLink_t * pxLink; + void * voidp; + size_t sz = 0; + + if (pv != NULL) + { + vTaskSuspendAll(); + { + /* The memory being checked will have an BlockLink_t structure immediately + before it. */ + puc -= xHeapStructSize; + + /* This casting is to keep the compiler from issuing warnings. */ + voidp = (void *) puc; + pxLink = (BlockLink_t *) voidp; + + /* Check if the block is actually allocated. */ + configASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0); + configASSERT(pxLink->pxNextFreeBlock == NULL); + + sz = (pxLink->xBlockSize & ~xBlockAllocatedBit) - xHeapStructSize; + } + (void) xTaskResumeAll(); + } + + return sz; +} + +void * __wrap_malloc(size_t size) +{ + return pvPortMalloc(size); +} + +void __wrap_free(void * ptr) +{ + vPortFree(ptr); +} + +void * __wrap_calloc(size_t num, size_t size) +{ + size_t total_size = num * size; + + // Handle overflow from (num * size) + if ((size != 0) && ((total_size / size) != num)) + { + return nullptr; + } + + void * ptr = pvPortMalloc(total_size); + if (ptr) + { + memset(ptr, 0, total_size); + } + else + { + ChipLogError(DeviceLayer, "__wrap_calloc: Could not allocate memory!"); + } + + return ptr; +} + +void * __wrap_realloc(void * ptr, size_t new_size) +{ + + void * new_ptr = NULL; + + if (new_size) + { + size_t old_ptr_size = xPortMallocUsableSize(ptr); + if (new_size <= old_ptr_size) + { + /* Return old pointer if the newly allocated size is smaller + or equal to the allocated size for old_ptr */ + return ptr; + } + + /* if old_ptr is NULL, then old_ptr_size is zero and new_ptr will be returned */ + new_ptr = pvPortMalloc(new_size); + + if (!new_ptr) + { + ChipLogError(DeviceLayer, "__wrap_realloc: Could not allocate memory!"); + return NULL; + } + + memset(reinterpret_cast(new_ptr) + old_ptr_size, 0, (new_size - old_ptr_size)); + memcpy(new_ptr, ptr, old_ptr_size); + } + + vPortFree(ptr); + + return new_ptr; +} + +void * __wrap__malloc_r(void * REENT, size_t size) +{ + return __wrap_malloc(size); +} + +void __wrap__free_r(void * REENT, void * ptr) +{ + __wrap_free(ptr); +} + +void * __wrap__realloc_r(void * REENT, void * ptr, size_t new_size) +{ + return __wrap_realloc(ptr, new_size); +} + +} // extern "C" diff --git a/examples/platform/nxp/k32w/k32w1/args.gni b/examples/platform/nxp/k32w/k32w1/args.gni new file mode 100644 index 00000000000000..f7d9dccd82e1fd --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/args.gni @@ -0,0 +1,38 @@ +# 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("${chip_root}/src/platform/nxp/k32w/k32w1/args.gni") + +arm_float_abi = "hard" +arm_cpu = "cortex-m33" +arm_fpu = "fpv5-sp-d16" +arm_arch = "armv8-m.main+dsp+fp" + +chip_openthread_ftd = false +openthread_core_config_deps = [] +openthread_core_config_deps = [ "${chip_root}/examples/platform/nxp/k32w/k32w1:openthread_core_config_k32w1_chip_examples" ] + +chip_ble_project_config_include = "" +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_inet_project_config_include = "" +chip_system_project_config_include = "" + +chip_system_config_provide_statistics = false +chip_with_nlfaultinjection = true + +chip_system_config_use_open_thread_inet_endpoints = true +chip_with_lwip = false diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/debug_k32w1.jpg b/examples/platform/nxp/k32w/k32w1/doc/images/debug_k32w1.jpg new file mode 100644 index 00000000000000..407c781220c4a6 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/debug_k32w1.jpg differ diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/import_demo.jpg b/examples/platform/nxp/k32w/k32w1/doc/images/import_demo.jpg new file mode 100644 index 00000000000000..6016c448a48e49 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/import_demo.jpg differ diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/installed_sdks.jpg b/examples/platform/nxp/k32w/k32w1/doc/images/installed_sdks.jpg new file mode 100644 index 00000000000000..be3ad84380a8aa Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/installed_sdks.jpg differ diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/k32w1-evk.jpg b/examples/platform/nxp/k32w/k32w1/doc/images/k32w1-evk.jpg new file mode 100644 index 00000000000000..550f2743367865 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/k32w1-evk.jpg differ diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/mcux-sdk-download.jpg b/examples/platform/nxp/k32w/k32w1/doc/images/mcux-sdk-download.jpg new file mode 100644 index 00000000000000..9dd4190b6d99e0 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/mcux-sdk-download.jpg differ diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/new_project.jpg b/examples/platform/nxp/k32w/k32w1/doc/images/new_project.jpg new file mode 100644 index 00000000000000..ce34586229bd67 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/new_project.jpg differ diff --git a/examples/platform/nxp/k32w/k32w1/doc/images/ota_topology.JPG b/examples/platform/nxp/k32w/k32w1/doc/images/ota_topology.JPG new file mode 100644 index 00000000000000..75fc40a70e3b27 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w1/doc/images/ota_topology.JPG differ diff --git a/examples/platform/nxp/k32w/k32w1/util/LEDWidget.cpp b/examples/platform/nxp/k32w/k32w1/util/LEDWidget.cpp new file mode 100644 index 00000000000000..b7a01ae6c7545f --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/util/LEDWidget.cpp @@ -0,0 +1,93 @@ +/* + * + * 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" + +#include + +#include "app.h" + +#if (defined(gAppLedCnt_c) && (gAppLedCnt_c > 0)) + +void LEDWidget::Init(uint8_t led, bool inverted) +{ + mLastChangeTimeMS = 0; + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + mGPIONum = led; + mState = false; + mOnLogic = !inverted; + + Set(false); +} + +void LEDWidget::Invert(void) +{ + Set(!mState); +} + +void LEDWidget::Set(bool state) +{ + mLastChangeTimeMS = mBlinkOnTimeMS = mBlinkOffTimeMS = 0; + DoSet(state); +} + +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 = mState ? mBlinkOnTimeMS : mBlinkOffTimeMS; + uint64_t nextChangeTimeMS = mLastChangeTimeMS + stateDurMS; + + if (nextChangeTimeMS < nowMS) + { + DoSet(!mState); + mLastChangeTimeMS = nowMS; + } + } +} + +void LEDWidget::DoSet(bool state) +{ + mState = state; + + if (state) + { + (void) LED_TurnOnOff((led_handle_t) g_ledHandle[mGPIONum], mOnLogic); + } + else + { + (void) LED_TurnOnOff((led_handle_t) g_ledHandle[mGPIONum], !mOnLogic); + } +} + +#endif /* (defined(gAppLedCnt_c) && (gAppLedCnt_c > 0)) */ diff --git a/examples/platform/nxp/k32w/k32w1/util/include/LEDWidget.h b/examples/platform/nxp/k32w/k32w1/util/include/LEDWidget.h new file mode 100644 index 00000000000000..4d55f246d49e05 --- /dev/null +++ b/examples/platform/nxp/k32w/k32w1/util/include/LEDWidget.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 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 "LED.h" +#include "EmbeddedTypes.h" +#pragma once + +class LEDWidget +{ +public: + void Init(uint8_t gpioNum, bool inverted); + 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; + uint8_t mGPIONum; + bool mState; + bool mOnLogic; + + void DoSet(bool state); +}; diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 6d039d53b5676c..03089edd1d5571 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -24,7 +24,7 @@ from builders.host import HostApp, HostBoard, HostBuilder, HostCryptoLibrary, HostFuzzingType from builders.imx import IMXApp, IMXBuilder from builders.infineon import InfineonApp, InfineonBoard, InfineonBuilder -from builders.k32w import K32WApp, K32WBuilder +from builders.k32w import K32WApp, K32WBoard, K32WBuilder from builders.mbed import MbedApp, MbedBoard, MbedBuilder, MbedProfile from builders.mw320 import MW320App, MW320Builder from builders.nrf import NrfApp, NrfBoard, NrfConnectBuilder @@ -454,12 +454,18 @@ def BuildASRTarget(): def BuildK32WTarget(): target = BuildTarget('k32w', K32WBuilder) + # boards + target.AppendFixedTargets([ + TargetPart('k32w0', board=K32WBoard.K32W0), + TargetPart('k32w1', board=K32WBoard.K32W1) + ]) + # apps target.AppendFixedTargets([ TargetPart('light', app=K32WApp.LIGHT, release=True), TargetPart('shell', app=K32WApp.SHELL, release=True), TargetPart('lock', app=K32WApp.LOCK, release=True), - TargetPart('contact', app=K32WApp.CONTACT, release=True), + TargetPart('contact', app=K32WApp.CONTACT, release=True) ]) target.AppendModifier(name="se05x", se05x=True) @@ -470,6 +476,7 @@ def BuildK32WTarget(): target.AppendModifier(name="crypto-platform", crypto_platform=True) target.AppendModifier( name="tokenizer", tokenizer=True).ExceptIfRe("-nologs") + target.AppendModifier(name="openthread-ftd", openthread_ftd=True) return target diff --git a/scripts/build/builders/k32w.py b/scripts/build/builders/k32w.py index be17730c481148..1cf7862d3d8739 100644 --- a/scripts/build/builders/k32w.py +++ b/scripts/build/builders/k32w.py @@ -18,6 +18,27 @@ from .gn import GnBuilder +class K32WBoard(Enum): + K32W0 = auto() + K32W1 = auto() + + def Name(self): + if self == K32WBoard.K32W0: + return 'k32w0x' + elif self == K32WBoard.K32W1: + return 'k32w1' + else: + raise Exception('Unknown board type: %r' % self) + + def FolderName(self): + if self == K32WBoard.K32W0: + return 'k32w/k32w0' + elif self == K32WBoard.K32W1: + return 'k32w/k32w1' + else: + raise Exception('Unknown board type: %r' % self) + + class K32WApp(Enum): LIGHT = auto() LOCK = auto() @@ -36,20 +57,20 @@ def ExampleName(self): else: raise Exception('Unknown app type: %r' % self) - def AppNamePrefix(self): + def NameSuffix(self): if self == K32WApp.LIGHT: - return 'chip-k32w0x-light-example' + return 'light-example' elif self == K32WApp.LOCK: - return 'chip-k32w0x-lock-example' + return 'lock-example' elif self == K32WApp.SHELL: - return 'chip-k32w0x-shell-example' + return 'shell-example' elif self == K32WApp.CONTACT: - return 'chip-k32w0x-contact-example' + return 'contact-example' else: raise Exception('Unknown app type: %r' % self) - def BuildRoot(self, root): - return os.path.join(root, 'examples', self.ExampleName(), 'nxp', 'k32w', 'k32w0') + def BuildRoot(self, root, board): + return os.path.join(root, 'examples', self.ExampleName(), 'nxp', board.FolderName()) class K32WBuilder(GnBuilder): @@ -58,6 +79,7 @@ def __init__(self, root, runner, app: K32WApp = K32WApp.LIGHT, + board: K32WBoard = K32WBoard.K32W0, release: bool = False, low_power: bool = False, tokenizer: bool = False, @@ -66,12 +88,14 @@ def __init__(self, disable_logs: bool = False, se05x: bool = False, tinycrypt: bool = False, - crypto_platform: bool = False): + crypto_platform: bool = False, + openthread_ftd: bool = False): super(K32WBuilder, self).__init__( - root=app.BuildRoot(root), + root=app.BuildRoot(root, board), runner=runner) self.code_root = root self.app = app + self.board = board self.low_power = low_power self.tokenizer = tokenizer self.release = release @@ -81,11 +105,10 @@ def __init__(self, self.se05x = se05x self.tinycrypt = tinycrypt self.crypto_platform = crypto_platform + self.openthread_ftd = openthread_ftd def GnBuildArgs(self): - args = [ - 'k32w0_sdk_root="%s"' % os.environ['NXP_K32W0_SDK_ROOT'], - ] + args = [] if self.low_power: args.append('chip_with_low_power=1') @@ -116,18 +139,17 @@ def GnBuildArgs(self): if self.crypto_platform: args.append('chip_crypto=\"platform\"') + if self.openthread_ftd: + args.append('chip_openthread_ftd=true') + return args def generate(self): - self._Execute([os.path.join( - self.code_root, 'third_party/nxp/k32w0_sdk/sdk_fixes/patch_k32w_sdk.sh')]) - super(K32WBuilder, self).generate() def build_outputs(self): - items = {} - for extension in ["", ".map", ".hex"]: - name = '%s%s' % (self.app.AppNamePrefix(), extension) - items[name] = os.path.join(self.output_dir, name) - - return items + name = 'chip-%s-%s' % (self.board.Name(), self.app.NameSuffix()) + return { + '%s.elf' % name: os.path.join(self.output_dir, name), + '%s.map' % name: os.path.join(self.output_dir, '%s.map' % name) + } diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index e7500ab0ca3b76..c78c87b83fda35 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -14,7 +14,7 @@ linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,therm linux-x64-efr32-test-runner[-clang] imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release] infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage] -k32w-{light,shell,lock,contact}[-se05x][-no-ble][-no-ota][-low-power][-nologs][-crypto-platform][-tokenizer] +k32w-{k32w0,k32w1}-{light,shell,lock,contact}[-se05x][-no-ble][-no-ota][-low-power][-nologs][-crypto-platform][-tokenizer][-openthread-ftd] mbed-cy8cproto_062_4343w-{lock,light,all-clusters,all-clusters-minimal,pigweed,ota-requestor,shell}[-release][-develop][-debug] mw320-all-clusters-app nrf-{nrf5340dk,nrf52840dk,nrf52840dongle}-{all-clusters,all-clusters-minimal,lock,light,light-switch,shell,pump,pump-controller,window-covering}[-rpc] diff --git a/scripts/checkout_submodules.py b/scripts/checkout_submodules.py index 22750fd40a8bff..e1c8eb888fcc99 100755 --- a/scripts/checkout_submodules.py +++ b/scripts/checkout_submodules.py @@ -36,7 +36,7 @@ 'efr32', 'esp32', 'infineon', - 'k32w0', + 'k32w', 'linux', 'mbed', 'nrfconnect', diff --git a/src/lwip/BUILD.gn b/src/lwip/BUILD.gn index 3547ac1157568d..241a059abb7428 100644 --- a/src/lwip/BUILD.gn +++ b/src/lwip/BUILD.gn @@ -31,11 +31,12 @@ if (lwip_platform == "") { assert(lwip_platform == "external" || lwip_platform == "standalone" || lwip_platform == "cc13xx_26xx" || lwip_platform == "cc32xx" || lwip_platform == "silabs" || lwip_platform == "k32w0" || - lwip_platform == "qpg" || lwip_platform == "mbed" || - lwip_platform == "psoc6" || lwip_platform == "cyw30739" || - lwip_platform == "bl602" || lwip_platform == "mw320" || - lwip_platform == "bl702" || lwip_platform == "bl702l" || - lwip_platform == "mt793x" || lwip_platform == "asr", + lwip_platform == "k32w1" || lwip_platform == "qpg" || + lwip_platform == "mbed" || lwip_platform == "psoc6" || + lwip_platform == "cyw30739" || lwip_platform == "bl602" || + lwip_platform == "mw320" || lwip_platform == "bl702" || + lwip_platform == "bl702l" || lwip_platform == "mt793x" || + lwip_platform == "asr", "Unsupported lwIP platform: ${lwip_platform}") if (lwip_platform != "external") { @@ -56,6 +57,8 @@ if (lwip_platform == "cc13xx_26xx") { import("${qpg_sdk_build_root}/qpg_sdk.gni") } else if (lwip_platform == "k32w0") { import("//build_overrides/k32w0_sdk.gni") +} else if (lwip_platform == "k32w1") { + import("//build_overrides/k32w1_sdk.gni") } else if (lwip_platform == "psoc6") { import("//build_overrides/psoc6.gni") } else if (lwip_platform == "cyw30739") { @@ -207,6 +210,8 @@ if (current_os == "zephyr" || current_os == "mbed") { public_deps += [ "${chip_root}/src/lib/support" ] } else if (lwip_platform == "k32w0") { public_deps += [ "${k32w0_sdk_build_root}:k32w0_sdk" ] + } else if (lwip_platform == "k32w1") { + public_deps += [ "${k32w1_sdk_build_root}:k32w1_sdk" ] } else if (lwip_platform == "cyw30739") { public_deps += [ "${cyw30739_sdk_build_root}:cyw30739_sdk" ] } else if (lwip_platform == "bl702") { diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 292ab1cbd7ae77..c588b94fa1621b 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -205,6 +205,9 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { } else if (chip_device_platform == "k32w0") { device_layer_target_define = "K32W" defines += [ "CHIP_DEVICE_LAYER_TARGET=nxp/k32w/k32w0" ] + } else if (chip_device_platform == "k32w1") { + device_layer_target_define = "K32W" + defines += [ "CHIP_DEVICE_LAYER_TARGET=nxp/k32w/k32w1" ] } else if (chip_device_platform == "telink") { device_layer_target_define = "TELINK" defines += [ "CHIP_DEVICE_LAYER_TARGET=telink" ] @@ -494,6 +497,8 @@ if (chip_device_platform != "none") { _platform_target = "ESP32" } else if (chip_device_platform == "k32w0") { _platform_target = "nxp/k32w/k32w0" + } else if (chip_device_platform == "k32w1") { + _platform_target = "nxp/k32w/k32w1" } else if (chip_device_platform == "linux") { _platform_target = "Linux" } else if (chip_device_platform == "nrfconnect") { diff --git a/src/platform/device.gni b/src/platform/device.gni index 8bfaee12b86a01..b139f44fba879b 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -16,7 +16,7 @@ import("//build_overrides/chip.gni") import("${chip_root}/src/ble/ble.gni") declare_args() { - # Device platform layer: cc13x2_26x2, cc13x4_26x4, cc32xx, darwin, efr32, esp32, external, freertos, linux, nrfconnect, k32w0, qpg, tizen, cyw30739, bl602, mw320, zephyr, beken, openiotsdk, none. + # Device platform layer: cc13x2_26x2, cc13x4_26x4, cc32xx, darwin, efr32, esp32, external, freertos, linux, nrfconnect, k32w0, k32w1, qpg, tizen, cyw30739, bl602, mw320, zephyr, beken, openiotsdk, none. chip_device_platform = "auto" chip_platform_target = "" @@ -51,8 +51,9 @@ declare_args() { chip_device_platform == "linux" || chip_device_platform == "qpg" || chip_device_platform == "cc13x2_26x2" || chip_device_platform == "cc13x4_26x4" || - chip_device_platform == "k32w0" || chip_device_platform == "tizen" || - chip_device_platform == "webos" || chip_device_platform == "stm32" + chip_device_platform == "k32w0" || chip_device_platform == "k32w1" || + chip_device_platform == "tizen" || chip_device_platform == "stm32" || + chip_device_platform == "webos" } declare_args() { @@ -140,6 +141,8 @@ if (chip_device_platform == "cc13x2_26x2") { _chip_device_layer = "qpg" } else if (chip_device_platform == "k32w0") { _chip_device_layer = "nxp/k32w/k32w0" +} else if (chip_device_platform == "k32w1") { + _chip_device_layer = "nxp/k32w/k32w1" } else if (chip_device_platform == "telink") { _chip_device_layer = "telink" } else if (chip_device_platform == "mbed") { @@ -234,15 +237,15 @@ assert( chip_device_platform == "external" || chip_device_platform == "linux" || chip_device_platform == "tizen" || chip_device_platform == "nrfconnect" || - chip_device_platform == "k32w0" || chip_device_platform == "qpg" || - chip_device_platform == "telink" || chip_device_platform == "mbed" || - chip_device_platform == "psoc6" || chip_device_platform == "android" || - chip_device_platform == "ameba" || chip_device_platform == "cyw30739" || - chip_device_platform == "webos" || chip_device_platform == "mw320" || - chip_device_platform == "zephyr" || chip_device_platform == "beken" || - chip_device_platform == "bl602" || chip_device_platform == "bl702" || - chip_device_platform == "bl702l" || chip_device_platform == "mt793x" || - chip_device_platform == "SiWx917" || + chip_device_platform == "k32w0" || chip_device_platform == "k32w1" || + chip_device_platform == "qpg" || chip_device_platform == "telink" || + chip_device_platform == "mbed" || chip_device_platform == "psoc6" || + chip_device_platform == "android" || chip_device_platform == "ameba" || + chip_device_platform == "cyw30739" || chip_device_platform == "webos" || + chip_device_platform == "mw320" || chip_device_platform == "zephyr" || + chip_device_platform == "beken" || chip_device_platform == "bl602" || + chip_device_platform == "bl702" || chip_device_platform == "bl702l" || + chip_device_platform == "mt793x" || chip_device_platform == "SiWx917" || chip_device_platform == "openiotsdk" || chip_device_platform == "asr" || chip_device_platform == "stm32", "Please select a valid value for chip_device_platform") diff --git a/src/platform/nxp/k32w/common/BLEManagerCommon.cpp b/src/platform/nxp/k32w/common/BLEManagerCommon.cpp index 2e3c5a35974c96..65b2f68cb20e90 100644 --- a/src/platform/nxp/k32w/common/BLEManagerCommon.cpp +++ b/src/platform/nxp/k32w/common/BLEManagerCommon.cpp @@ -184,6 +184,18 @@ CHIP_ERROR BLEManagerCommon::_Init() eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_INIT_COMPLETE, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_INIT_COMPLETE, err = CHIP_ERROR_INCORRECT_STATE); +#if BLE_HIGH_TX_POWER + /* Set Adv Power */ + Gap_SetTxPowerLevel(gAdvertisingPowerLeveldBm_c, gTxPowerAdvChannel_c); + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); + VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, err = CHIP_ERROR_INCORRECT_STATE); + + /* Set Connect Power */ + Gap_SetTxPowerLevel(gConnectPowerLeveldBm_c, gTxPowerConnChannel_c); + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); + VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, err = CHIP_ERROR_INCORRECT_STATE); +#endif + #if defined(CPU_JN518X) && defined(chip_with_low_power) && (chip_with_low_power == 1) PWR_ChangeDeepSleepMode(cPWR_PowerDown_RamRet); #endif diff --git a/src/platform/nxp/k32w/common/K32W_OTA_README.md b/src/platform/nxp/k32w/common/K32W_OTA_README.md index 4f2ba7b6e52960..63079e0ce3c81e 100644 --- a/src/platform/nxp/k32w/common/K32W_OTA_README.md +++ b/src/platform/nxp/k32w/common/K32W_OTA_README.md @@ -128,6 +128,13 @@ at next boot. The `FactoryDataProvider` offers a default restore mechanism and support for registering additional restore mechanisms or overwriting the default one. +Prior to factory data update, the old factory data is backed up in external +flash. If anything interrupts the update (e.g. power loss), there is a slight +chance the internal flash factory data section is erased and has to be restored +at next boot. The `FactoryDataProvider` offers a default restore mechanism and +support for registering additional restore mechanisms or overwriting the default +one. + Restore mechanisms are just functions that have this signature: `CHIP_ERROR (*)(void)`. Any such function can be registered through `FactoryDataProvider::RegisterRestoreMechanism`. @@ -138,12 +145,6 @@ The default restore mechanism is implemented as a weak function: overwritten at application level. When doing the actual restore, the mechanisms are called in the order they were registered. -The default restore mechanism is implemented as a weak function: -`FactoryDataDefaultRestoreMechanism`. It is registered in -`K32W0FactoryDataProvider::Init`, before factory data validation, and it can be -overwritten at application level. When doing the actual restore, the mechanisms -are called in the order they were registered. - Please note that the restore mechanisms registration order matters. Once a restore mechanism is successful (`CHIP_NO_ERROR` is returned), the restore process has finished and subsequent restore mechanisms will not be called. diff --git a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp index f8d8b4b5a0f8e6..16493144c632be 100644 --- a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp +++ b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp @@ -28,6 +28,13 @@ using namespace chip::DeviceLayer; using namespace ::chip::DeviceLayer::Internal; +#if USE_SMU2_AS_SYSTEM_MEMORY +// The attribute specifier should not be changed. +static chip::OTAImageProcessorImpl gImageProcessor __attribute__((section(".smu2"))); +#else +static chip::OTAImageProcessorImpl gImageProcessor; +#endif + namespace chip { CHIP_ERROR OTAImageProcessorImpl::Init(OTADownloader * downloader) @@ -96,16 +103,10 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) { 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; - } + + VerifyOrReturn(imageProcessor != nullptr, ChipLogError(SoftwareUpdate, "ImageProcessor context is null")); + + VerifyOrReturn(imageProcessor->mDownloader != nullptr, ChipLogError(SoftwareUpdate, "mDownloader is null")); GetRequestorInstance()->GetProviderLocation(imageProcessor->mBackupProviderLocation); @@ -168,11 +169,11 @@ CHIP_ERROR OTAImageProcessorImpl::SelectProcessor(ByteSpan & block) auto pair = mProcessorMap.find(header.tag); if (pair == mProcessorMap.end()) { - ChipLogError(SoftwareUpdate, "There is no registered processor for tag: %" PRIu32, header.tag); + ChipLogError(SoftwareUpdate, "There is no registered processor for tag: %lu", header.tag); return CHIP_OTA_PROCESSOR_NOT_REGISTERED; } - ChipLogDetail(SoftwareUpdate, "Selected processor with tag: %ld", pair->first); + ChipLogDetail(SoftwareUpdate, "Selected processor with tag: %lu", pair->first); mCurrentProcessor = pair->second; mCurrentProcessor->SetLength(header.length); mCurrentProcessor->SetWasSelected(true); @@ -185,7 +186,7 @@ CHIP_ERROR OTAImageProcessorImpl::RegisterProcessor(uint32_t tag, OTATlvProcesso auto pair = mProcessorMap.find(tag); if (pair != mProcessorMap.end()) { - ChipLogError(SoftwareUpdate, "A processor for tag %" PRIu32 " is already registered.", tag); + ChipLogError(SoftwareUpdate, "A processor for tag %lu is already registered.", tag); return CHIP_OTA_PROCESSOR_ALREADY_REGISTERED; } @@ -210,17 +211,10 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) { auto * imageProcessor = reinterpret_cast(context); - if (imageProcessor == nullptr) - { - ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); - return; - } - if (imageProcessor->mDownloader == nullptr) - { - ChipLogError(SoftwareUpdate, "mDownloader is null"); - return; - } + VerifyOrReturn(imageProcessor != nullptr, ChipLogError(SoftwareUpdate, "ImageProcessor context is null")); + + VerifyOrReturn(imageProcessor->mDownloader != nullptr, ChipLogError(SoftwareUpdate, "mDownloader is null")); CHIP_ERROR status; auto block = ByteSpan(imageProcessor->mBlock.data(), imageProcessor->mBlock.size()); @@ -243,7 +237,7 @@ void OTAImageProcessorImpl::HandleStatus(CHIP_ERROR status) if (status == CHIP_NO_ERROR || status == CHIP_ERROR_BUFFER_TOO_SMALL) { mParams.downloadedBytes += mBlock.size(); - FetchNextData(reinterpret_cast(this)); + FetchNextData(0); } else if (status == CHIP_OTA_FETCH_ALREADY_SCHEDULED) { @@ -294,8 +288,8 @@ CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage() ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSoftwareVersion(currentVersion)); if (currentVersion != targetVersion) { - ChipLogError(SoftwareUpdate, "Current sw version %" PRIu32 " is different than the expected sw version = %" PRIu32, - currentVersion, targetVersion); + ChipLogError(SoftwareUpdate, "Current sw version %lu is different than the expected sw version = %lu", currentVersion, + targetVersion); return CHIP_ERROR_INCORRECT_STATE; } @@ -414,8 +408,7 @@ void OTAImageProcessorImpl::FetchNextData(uint32_t context) OTAImageProcessorImpl & OTAImageProcessorImpl::GetDefaultInstance() { - static OTAImageProcessorImpl imageProcessor; - return imageProcessor; + return gImageProcessor; } } // namespace chip diff --git a/src/platform/nxp/k32w/common/OTATlvProcessor.h b/src/platform/nxp/k32w/common/OTATlvProcessor.h index 534da067148da8..1968f983eda14b 100644 --- a/src/platform/nxp/k32w/common/OTATlvProcessor.h +++ b/src/platform/nxp/k32w/common/OTATlvProcessor.h @@ -39,7 +39,8 @@ namespace chip { #define CHIP_OTA_PROCESSOR_IMG_COMMIT CHIP_ERROR_TLV_PROCESSOR(0x0A) #define CHIP_OTA_PROCESSOR_CB_NOT_REGISTERED CHIP_ERROR_TLV_PROCESSOR(0x0B) #define CHIP_OTA_PROCESSOR_EEPROM_OFFSET CHIP_ERROR_TLV_PROCESSOR(0x0C) -#define CHIP_OTA_PROCESSOR_START_IMAGE CHIP_ERROR_TLV_PROCESSOR(0x0D) +#define CHIP_OTA_PROCESSOR_EXTERNAL_STORAGE CHIP_ERROR_TLV_PROCESSOR(0x0D) +#define CHIP_OTA_PROCESSOR_START_IMAGE CHIP_ERROR_TLV_PROCESSOR(0x0E) // Descriptor constants inline constexpr size_t kVersionStringSize = 64; diff --git a/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp new file mode 100644 index 00000000000000..daac54fb5a16e7 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 2021-2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* this file behaves like a config.h, comes first */ +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +/*! App to Host message queue for the Host Task */ +messaging_t gApp2Host_TaskQueue; +/*! HCI to Host message queue for the Host Task */ +messaging_t gHci2Host_TaskQueue; +/*! Event for the Host Task Queue */ +OSA_EVENT_HANDLE_DEFINE(gHost_TaskEvent); + +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +BLEManagerImpl BLEManagerImpl::sInstance; + +BLEManagerCommon * BLEManagerImpl::GetImplInstance() +{ + return &BLEManagerImpl::sInstance; +} + +CHIP_ERROR BLEManagerImpl::InitHostController(ble_generic_cb_fp cb_fp) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + PLATFORM_InitBle(); + + (void) RNG_Init(); + RNG_SetPseudoRandomNoSeed(NULL); + + /* Has to be called after RNG_Init(), once seed is generated. */ + (void) Controller_SetRandomSeed(); + + /* Create BLE Host Task */ + VerifyOrExit(BLEManagerImpl::blekw_host_init() == CHIP_NO_ERROR, err = CHIP_ERROR_INCORRECT_STATE); + + VerifyOrExit(Hcit_Init(Ble_HciRecv) == gHciSuccess_c, err = CHIP_ERROR_INCORRECT_STATE); + + /* Set BD Address in Controller. Must be done after HCI init and before Host init. */ + Ble_SetBDAddr(); + + /* BLE Host Stack Init */ + VerifyOrExit(Ble_HostInitialize(cb_fp, Hcit_SendPacket) == gBleSuccess_c, err = CHIP_ERROR_INCORRECT_STATE); + + /* configure tx power to use in NBU specific to BLE */ + Controller_SetTxPowerLevelDbm(mAdvertisingDefaultTxPower_c, gAdvTxChannel_c); + Controller_SetTxPowerLevelDbm(mConnectionDefaultTxPower_c, gConnTxChannel_c); + Controller_ConfigureInvalidPduHandling(gLlInvalidPduHandlingType_c); + +exit: + return err; +} + +void BLEManagerImpl::Host_Task(osaTaskParam_t argument) +{ + Host_TaskHandler((void *) NULL); +} + +CHIP_ERROR BLEManagerImpl::blekw_host_init(void) +{ + /* Initialization of task related */ + if (KOSA_StatusSuccess != OSA_EventCreate((osa_event_handle_t) gHost_TaskEvent, TRUE)) + { + return CHIP_ERROR_NO_MEMORY; + } + + /* Initialization of task message queue */ + MSG_InitQueue(&gApp2Host_TaskQueue); + MSG_InitQueue(&gHci2Host_TaskQueue); + + /* Task creation */ + if (pdPASS != xTaskCreate(Host_Task, "hostTask", HOST_TASK_STACK_SIZE, (void *) 0, HOST_TASK_PRIORITY, NULL)) + { + return CHIP_ERROR_NO_MEMORY; + } + + return CHIP_NO_ERROR; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif /* CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE */ diff --git a/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h new file mode 100644 index 00000000000000..7aa4e9f1604b42 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h @@ -0,0 +1,99 @@ +/* + * + * Copyright (c) 2021-2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include "RNG_Interface.h" +#include "fwk_messaging.h" +#include "fwk_os_abs.h" +#include "fwk_platform_ble.h" +#include "hci_transport.h" + +#include "ble_init.h" +#include "controller_api.h" +#include "controller_interface.h" + +#include + +/* host task configuration */ +#define HOST_TASK_PRIORITY (4U) +#define HOST_TASK_STACK_SIZE (gHost_TaskStackSize_c / sizeof(StackType_t)) + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +using namespace chip::Ble; + +class BLEManagerImpl final : public BLEManagerCommon +{ +public: + // Allow the BLEManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend BLEManager; + + CHIP_ERROR InitHostController(ble_generic_cb_fp cb_fp) override; + BLEManagerCommon * GetImplInstance() override; + +private: + static BLEManagerImpl sInstance; + + static CHIP_ERROR blekw_host_init(void); + static void Host_Task(osaTaskParam_t argument); + + BleLayer * _GetBleLayer(void); + + // ===== Members for internal use by the following friends. + friend BLEManager & BLEMgr(void); + friend BLEManagerImpl & BLEMgrImpl(void); +}; + +/** + * Returns a reference to the public interface of the BLEManager singleton object. + * + * Internal components should use this to access features of the BLEManager object + * that are common to all platforms. + */ +inline BLEManager & BLEMgr(void) +{ + return BLEManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the BLEManager singleton object. + * + * Internal components can use this to gain access to features of the BLEManager + * that are specific to the K32W platforms. + */ +inline BLEManagerImpl & BLEMgrImpl(void) +{ + return BLEManagerImpl::sInstance; +} + +inline BleLayer * BLEManagerImpl::_GetBleLayer() +{ + return this; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif /* CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE */ diff --git a/src/platform/nxp/k32w/k32w1/BUILD.gn b/src/platform/nxp/k32w/k32w1/BUILD.gn new file mode 100644 index 00000000000000..effb6cb2fc9d1e --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/BUILD.gn @@ -0,0 +1,112 @@ +# 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/k32w1_sdk.gni") +import("${chip_root}/src/crypto/crypto.gni") +import("${chip_root}/src/platform/device.gni") +import("${k32w1_sdk_build_root}/k32w1_sdk.gni") + +assert(chip_device_platform == "k32w1") + +if (chip_enable_openthread) { + import("//build_overrides/openthread.gni") +} + +if (chip_crypto == "platform") { + import("//build_overrides/mbedtls.gni") +} + +static_library("k32w1") { + sources = [ + "../../../SingletonConfigurationManager.cpp", + "../common/BLEManagerCommon.cpp", + "../common/BLEManagerCommon.h", + "BLEManagerImpl.cpp", + "BLEManagerImpl.h", + "CHIPDevicePlatformConfig.h", + "CHIPDevicePlatformEvent.h", + "ConfigurationManagerImpl.cpp", + "ConfigurationManagerImpl.h", + "ConnectivityManagerImpl.cpp", + "ConnectivityManagerImpl.h", + "DefaultTestEventTriggerDelegate.cpp", + "DefaultTestEventTriggerDelegate.h", + "DiagnosticDataProviderImpl.cpp", + "DiagnosticDataProviderImpl.h", + "K32W1Config.cpp", + "K32W1Config.h", + "KeyValueStoreManagerImpl.cpp", + "KeyValueStoreManagerImpl.h", + "Logging.cpp", + "PlatformManagerImpl.cpp", + "PlatformManagerImpl.h", + "SystemTimeSupport.cpp", + "ble_function_mux.c", + "ram_storage.c", + "ram_storage.h", + ] + + public_deps = [ "${chip_root}/src/platform:platform_base" ] + + if (chip_with_low_power != 0) { + sources += [ "LowPowerHooks.cpp" ] + } + + if (chip_enable_ota_requestor) { + sources += [ + "../common/OTAImageProcessorImpl.cpp", + "../common/OTAImageProcessorImpl.h", + "../common/OTATlvProcessor.cpp", + "../common/OTATlvProcessor.h", + "OTAFirmwareProcessor.cpp", + "OTAFirmwareProcessor.h", + "OTAHooks.cpp", + ] + } + + if (chip_crypto == "platform") { + sources += [ + "CHIPCryptoPalK32W1.cpp", + "K32W1PersistentStorageOpKeystore.cpp", + "K32W1PersistentStorageOpKeystore.h", + ] + + public_deps += [ "${mbedtls_root}:mbedtls" ] + } + + deps = [] + + if (chip_enable_openthread) { + sources += [ + "../../../OpenThread/OpenThreadUtils.cpp", + "ThreadStackManagerImpl.cpp", + "ThreadStackManagerImpl.h", + ] + + if (chip_mdns == "platform") { + sources += [ + "../../../OpenThread/DnssdImpl.cpp", + "../../../OpenThread/OpenThreadDnssdImpl.cpp", + "../../../OpenThread/OpenThreadDnssdImpl.h", + ] + deps += [ "${chip_root}/src/lib/dnssd:platform_header" ] + } + } + + public_deps += [ "${chip_root}/src/crypto" ] + + public_configs = + [ "${chip_root}/src/lib/address_resolve:default_address_resolve_config" ] +} diff --git a/src/platform/nxp/k32w/k32w1/BlePlatformConfig.h b/src/platform/nxp/k32w/k32w1/BlePlatformConfig.h new file mode 100644 index 00000000000000..a003927c74626e --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/BlePlatformConfig.h @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + * Platform-specific configuration overrides for the CHIP BLE + * Layer on K32W platforms using the NXP SDK. + * + */ + +#pragma once + +// ==================== Platform Adaptations ==================== + +#define BLE_CONNECTION_OBJECT uint8_t +#define BLE_CONNECTION_UNINITIALIZED ((uint8_t) 0xFF) + +// ========== Platform-specific Configuration Overrides ========= + +/* none so far */ diff --git a/src/platform/nxp/k32w/k32w1/CHIPCryptoPalK32W1.cpp b/src/platform/nxp/k32w/k32w1/CHIPCryptoPalK32W1.cpp new file mode 100644 index 00000000000000..6aad4ae85ea0fc --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/CHIPCryptoPalK32W1.cpp @@ -0,0 +1,1004 @@ +/* + * + * 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 + * mbedTLS based implementation of CHIP crypto primitives + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "SecLib_ecp256.h" +#include "sss_crypto.h" + +namespace chip { +namespace Crypto { + +#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 + +typedef struct +{ + bool mInitialized; + bool mDRBGSeeded; + mbedtls_ctr_drbg_context mDRBGCtxt; + mbedtls_entropy_context mEntropy; +} EntropyContext; + +static EntropyContext gsEntropyContext; + +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 bool _isValidTagLength(size_t tag_length) +{ + if (tag_length == 8 || tag_length == 12 || tag_length == 16) + { + return true; + } + return false; +} + +static bool _isValidKeyLength(size_t length) +{ + // 16 bytes key for AES-CCM-128, 32 for AES-CCM-256 + if (length == 16 || length == 32) + { + return true; + } + return false; +} + +CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + uint8_t * tag, size_t tag_length) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 1; + + mbedtls_ccm_context context; + mbedtls_ccm_init(&context); + + VerifyOrExit(plaintext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(ciphertext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); + if (aad_length > 0) + { + VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + } + + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + // Encrypt + result = mbedtls_ccm_encrypt_and_tag(&context, plaintext_length, Uint8::to_const_uchar(nonce), nonce_length, + Uint8::to_const_uchar(aad), aad_length, Uint8::to_const_uchar(plaintext), + Uint8::to_uchar(ciphertext), Uint8::to_uchar(tag), tag_length); + _log_mbedTLS_error(result); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + mbedtls_ccm_free(&context); + 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 Aes128KeyHandle & key, const uint8_t * nonce, + size_t nonce_length, uint8_t * plaintext) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 1; + + mbedtls_ccm_context context; + mbedtls_ccm_init(&context); + + VerifyOrExit(plaintext != nullptr || ciphertext_len == 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(ciphertext != nullptr || ciphertext_len == 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + if (aad_len > 0) + { + VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + } + + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + // Decrypt + result = mbedtls_ccm_auth_decrypt(&context, ciphertext_len, Uint8::to_const_uchar(nonce), nonce_length, + Uint8::to_const_uchar(aad), aad_len, Uint8::to_const_uchar(ciphertext), + Uint8::to_uchar(plaintext), Uint8::to_const_uchar(tag), tag_length); + _log_mbedTLS_error(result); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + mbedtls_ccm_free(&context); + return error; +} + +CHIP_ERROR Hash_SHA256(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) +{ + // zero data length hash is supported. + VerifyOrReturnError(data != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + const int result = mbedtls_sha256(Uint8::to_const_uchar(data), data_length, Uint8::to_uchar(out_buffer), 0); +#else + const int result = mbedtls_sha256_ret(Uint8::to_const_uchar(data), data_length, Uint8::to_uchar(out_buffer), 0); +#endif + + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Hash_SHA1(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) +{ + // zero data length hash is supported. + VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + const int result = mbedtls_sha1(Uint8::to_const_uchar(data), data_length, Uint8::to_uchar(out_buffer)); +#else + const int result = mbedtls_sha1_ret(Uint8::to_const_uchar(data), data_length, Uint8::to_uchar(out_buffer)); +#endif + + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(mbedtls_sha256_context), + "kMAX_Hash_SHA256_Context_Size is too small for the size of underlying mbedtls_sha256_context"); + +static inline mbedtls_sha256_context * to_inner_hash_sha256_context(HashSHA256OpaqueContext * context) +{ + return SafePointerCast(context); +} + +Hash_SHA256_stream::Hash_SHA256_stream(void) +{ + mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); + mbedtls_sha256_init(context); +} + +Hash_SHA256_stream::~Hash_SHA256_stream(void) +{ + mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); + mbedtls_sha256_free(context); + Clear(); +} + +CHIP_ERROR Hash_SHA256_stream::Begin(void) +{ + mbedtls_sha256_context * const context = to_inner_hash_sha256_context(&mContext); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + const int result = mbedtls_sha256_starts(context, 0); +#else + const int result = mbedtls_sha256_starts_ret(context, 0); +#endif + + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Hash_SHA256_stream::AddData(const ByteSpan data) +{ + mbedtls_sha256_context * const context = to_inner_hash_sha256_context(&mContext); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + const int result = mbedtls_sha256_update(context, Uint8::to_const_uchar(data.data()), data.size()); +#else + const int result = mbedtls_sha256_update_ret(context, Uint8::to_const_uchar(data.data()), data.size()); +#endif + + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Hash_SHA256_stream::GetDigest(MutableByteSpan & out_buffer) +{ + mbedtls_sha256_context * context = to_inner_hash_sha256_context(&mContext); + + // Back-up context as we are about to finalize the hash to extract digest. + mbedtls_sha256_context previous_ctx; + mbedtls_sha256_init(&previous_ctx); + mbedtls_sha256_clone(&previous_ctx, context); + + // Pad + compute digest, then finalize context. It is restored next line to continue. + CHIP_ERROR result = Finish(out_buffer); + + // Restore context prior to finalization. + mbedtls_sha256_clone(context, &previous_ctx); + mbedtls_sha256_free(&previous_ctx); + + return result; +} + +CHIP_ERROR Hash_SHA256_stream::Finish(MutableByteSpan & out_buffer) +{ + VerifyOrReturnError(out_buffer.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + mbedtls_sha256_context * const context = to_inner_hash_sha256_context(&mContext); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + const int result = mbedtls_sha256_finish(context, Uint8::to_uchar(out_buffer.data())); +#else + const int result = mbedtls_sha256_finish_ret(context, Uint8::to_uchar(out_buffer.data())); +#endif + + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + out_buffer = out_buffer.SubSpan(0, kSHA256_Hash_Length); + + return CHIP_NO_ERROR; +} + +void Hash_SHA256_stream::Clear(void) +{ + mbedtls_platform_zeroize(this, sizeof(*this)); +} + +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); + + const mbedtls_md_info_t * const md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + VerifyOrReturnError(md != nullptr, CHIP_ERROR_INTERNAL); + + const int result = mbedtls_hkdf(md, Uint8::to_const_uchar(salt), salt_length, Uint8::to_const_uchar(secret), secret_length, + Uint8::to_const_uchar(info), info_length, Uint8::to_uchar(out_buffer), out_length); + _log_mbedTLS_error(result); + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_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); + + const mbedtls_md_info_t * const md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + VerifyOrReturnError(md != nullptr, CHIP_ERROR_INTERNAL); + + const int result = + mbedtls_md_hmac(md, Uint8::to_const_uchar(key), key_length, Uint8::to_const_uchar(message), message_length, out_buffer); + + _log_mbedTLS_error(result); + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_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) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + const mbedtls_md_info_t * md_info; + mbedtls_md_context_t md_ctxt; + constexpr int use_hmac = 1; + + bool free_md_ctxt = false; + + 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); + + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + VerifyOrExit(md_info != nullptr, error = CHIP_ERROR_INTERNAL); + + mbedtls_md_init(&md_ctxt); + free_md_ctxt = true; + + result = mbedtls_md_setup(&md_ctxt, md_info, use_hmac); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_pkcs5_pbkdf2_hmac(&md_ctxt, Uint8::to_const_uchar(password), plen, Uint8::to_const_uchar(salt), slen, + iteration_count, key_length, Uint8::to_uchar(output)); + + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + _log_mbedTLS_error(result); + + if (free_md_ctxt) + { + mbedtls_md_free(&md_ctxt); + } + + return error; +} + +static EntropyContext * get_entropy_context() +{ + if (!gsEntropyContext.mInitialized) + { + mbedtls_entropy_init(&gsEntropyContext.mEntropy); + mbedtls_ctr_drbg_init(&gsEntropyContext.mDRBGCtxt); + + gsEntropyContext.mInitialized = true; + } + + return &gsEntropyContext; +} + +static mbedtls_ctr_drbg_context * get_drbg_context() +{ + EntropyContext * const context = get_entropy_context(); + + mbedtls_ctr_drbg_context * const drbgCtxt = &context->mDRBGCtxt; + + if (!context->mDRBGSeeded) + { + const int status = mbedtls_ctr_drbg_seed(drbgCtxt, mbedtls_entropy_func, &context->mEntropy, nullptr, 0); + if (status != 0) + { + _log_mbedTLS_error(status); + return nullptr; + } + + context->mDRBGSeeded = true; + } + + return drbgCtxt; +} + +CHIP_ERROR add_entropy_source(entropy_source fn_source, void * p_source, size_t threshold) +{ + VerifyOrReturnError(fn_source != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + EntropyContext * const entropy_ctxt = get_entropy_context(); + VerifyOrReturnError(entropy_ctxt != nullptr, CHIP_ERROR_INTERNAL); + + const int result = + mbedtls_entropy_add_source(&entropy_ctxt->mEntropy, fn_source, p_source, threshold, MBEDTLS_ENTROPY_SOURCE_STRONG); + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + 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); + + mbedtls_ctr_drbg_context * const drbg_ctxt = get_drbg_context(); + VerifyOrReturnError(drbg_ctxt != nullptr, CHIP_ERROR_INTERNAL); + + const int result = mbedtls_ctr_drbg_random(drbg_ctxt, Uint8::to_uchar(out_buffer), out_length); + VerifyOrReturnError(result == 0, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +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; +} + +mbedtls_ecp_group_id MapECPGroupId(SupportedECPKeyTypes keyType) +{ + switch (keyType) + { + case SupportedECPKeyTypes::ECP256R1: + return MBEDTLS_ECP_DP_SECP256R1; + default: + return MBEDTLS_ECP_DP_NONE; + } +} + +static inline sss_sscp_object_t * to_keypair(P256KeypairContext * context) +{ + return SafePointerCast(context); +} + +static inline const sss_sscp_object_t * 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; + sss_sscp_asymmetric_t asyc; + size_t signatureSize = kP256_ECDSA_Signature_Length_Raw; + + VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t digest[kSHA256_Hash_Length]; + memset(&digest[0], 0, sizeof(digest)); + ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0])); + + sss_sscp_object_t * keypair = to_keypair(&mKeypair); + + VerifyOrExit((sss_sscp_asymmetric_context_init(&asyc, &g_sssSession, keypair, kAlgorithm_SSS_ECDSA_SHA256, kMode_SSS_Sign) == + kStatus_SSS_Success), + CHIP_ERROR_INTERNAL); + VerifyOrExit((sss_sscp_asymmetric_sign_digest(&asyc, digest, kP256_FE_Length, out_signature.Bytes(), &signatureSize) == + kStatus_SSS_Success), + CHIP_ERROR_INTERNAL); + VerifyOrExit(out_signature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, error = CHIP_ERROR_INTERNAL); + +exit: + (void) sss_sscp_asymmetric_context_free(&asyc); + return error; +} + +CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, const size_t msg_length, + const P256ECDSASignature & signature) const +{ +#if defined(MBEDTLS_ECDSA_C) + VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t digest[kSHA256_Hash_Length]; + memset(&digest[0], 0, sizeof(digest)); + ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0])); + + return ECDSA_validate_hash_signature(&digest[0], sizeof(digest), signature); +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +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; + + sss_sscp_object_t ecdsaPublic; + sss_sscp_asymmetric_t asyc; + bool bFreeAsyncCtx = false; + + size_t keySize = SSS_ECP_KEY_SZ(kP256_PrivateKey_Length); + + VerifyOrReturnError(sss_sscp_key_object_init(&ecdsaPublic, &g_keyStore) == kStatus_SSS_Success, CHIP_ERROR_INTERNAL); + + VerifyOrReturnError(sss_sscp_key_object_allocate_handle(&ecdsaPublic, 0u, kSSS_KeyPart_Public, kSSS_CipherType_EC_NIST_P, + keySize, SSS_KEYPROP_OPERATION_ASYM) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + + // The first byte of the public key is the uncompressed marker + VerifyOrExit(SSS_KEY_STORE_SET_KEY(&ecdsaPublic, Uint8::to_const_uchar(*this) + 1, Length() - 1, keySize * 8, + (uint32_t) kSSS_KeyPart_Public) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + + VerifyOrExit(sss_sscp_asymmetric_context_init(&asyc, &g_sssSession, &ecdsaPublic, kAlgorithm_SSS_ECDSA_SHA256, + kMode_SSS_Verify) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + + bFreeAsyncCtx = true; + VerifyOrExit(sss_sscp_asymmetric_verify_digest(&asyc, (uint8_t *) hash, hash_length, (uint8_t *) signature.ConstBytes(), + signature.Length()) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); +exit: + + if (bFreeAsyncCtx) + { + /* Need to be very careful, if we try to free something that is not initialized with success we will get an hw fault */ + (void) sss_sscp_asymmetric_context_free(&asyc); + } + (void) SSS_KEY_OBJ_FREE(&ecdsaPublic); + + return error; +} + +CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const +{ + + CHIP_ERROR error = CHIP_NO_ERROR; + size_t secret_length = (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(); + + sss_sscp_object_t * keypair = to_keypair(&mKeypair); + size_t coordinateLen = kP256_PrivateKey_Length; + size_t coordinateBitsLen = coordinateLen * 8; + size_t keySize = SSS_ECP_KEY_SZ(kP256_PrivateKey_Length); + + sss_sscp_derive_key_t dCtx; + sss_sscp_object_t pEcdhPubKey; + sss_sscp_object_t sharedSecret; + + bool bFreeSharedSecret = false; + bool bFreeDeriveContex = false; + + VerifyOrExit(mInitialized, error = CHIP_ERROR_WELL_UNINITIALIZED); + + /* Remote public key */ + VerifyOrReturnError(sss_sscp_key_object_init(&pEcdhPubKey, &g_keyStore) == kStatus_SSS_Success, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(sss_sscp_key_object_allocate_handle(&pEcdhPubKey, 0u, kSSS_KeyPart_Public, kSSS_CipherType_EC_NIST_P, + keySize, SSS_KEYPROP_OPERATION_KDF) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + + // The first byte of the public key is the uncompressed marker + VerifyOrExit(SSS_KEY_STORE_SET_KEY(&pEcdhPubKey, Uint8::to_const_uchar(remote_public_key) + 1, keySize, coordinateBitsLen, + kSSS_KeyPart_Public) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + + /* Shared secret */ + VerifyOrExit(sss_sscp_key_object_init(&sharedSecret, &g_keyStore) == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(sss_sscp_key_object_allocate_handle(&sharedSecret, 0u, kSSS_KeyPart_Default, kSSS_CipherType_AES, coordinateLen, + SSS_KEYPROP_OPERATION_NONE) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + bFreeSharedSecret = true; + + /* Secret Key generated inside SSS */ + VerifyOrExit(sss_sscp_derive_key_context_init(&dCtx, &g_sssSession, keypair, kAlgorithm_SSS_ECDH, + kMode_SSS_ComputeSharedSecret) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + bFreeDeriveContex = true; + + VerifyOrExit(sss_sscp_asymmetric_dh_derive_key(&dCtx, &pEcdhPubKey, &sharedSecret) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(SSS_KEY_STORE_GET_PUBKEY(&sharedSecret, out_secret.Bytes(), &coordinateLen, &coordinateBitsLen) == + kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + SuccessOrExit(error = out_secret.SetLength(secret_length)); + +exit: + (void) SSS_KEY_OBJ_FREE(&pEcdhPubKey); + + /* Need to be very careful, if we try to free something that is not initialized with success we will get a hw fault */ + if (bFreeSharedSecret) + (void) SSS_KEY_OBJ_FREE(&sharedSecret); + if (bFreeDeriveContex) + (void) sss_sscp_derive_key_context_free(&dCtx); + + 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(ECPKeyTarget key_target) +{ + + CHIP_ERROR error = CHIP_NO_ERROR; + + size_t keyBitsLen = kP256_PrivateKey_Length * 8; + size_t keySize = SSS_ECP_KEY_SZ(kP256_PrivateKey_Length); + + Clear(); + + sss_sscp_object_t * keypair = to_keypair(&mKeypair); + + VerifyOrReturnError(sss_sscp_key_object_init(keypair, &g_keyStore) == kStatus_SSS_Success, CHIP_ERROR_INTERNAL); + + VerifyOrReturnError(sss_sscp_key_object_allocate_handle( + keypair, 0x0u, kSSS_KeyPart_Pair, kSSS_CipherType_EC_NIST_P, 3 * kP256_PrivateKey_Length, + SSS_KEYPROP_OPERATION_KDF | SSS_KEYPROP_OPERATION_ASYM) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(SSS_ECP_GENERATE_KEY(keypair, keyBitsLen) == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + // The first byte of the public key is the uncompressed marker + Uint8::to_uchar(mPublicKey)[0] = 0x04; + + // Extract public key, write from the second byte + VerifyOrExit(SSS_KEY_STORE_GET_PUBKEY(keypair, Uint8::to_uchar(mPublicKey) + 1, &keySize, &keyBitsLen) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + + mInitialized = true; + +exit: + if (mInitialized != true) + (void) SSS_KEY_OBJ_FREE(keypair); + + return error; +} + +CHIP_ERROR P256Keypair::Serialize(P256SerializedKeypair & output) const +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) +{ + Encoding::BufferWriter bbuf(mPublicKey, mPublicKey.Length()); + CHIP_ERROR error = CHIP_NO_ERROR; + + Clear(); + + const uint8_t * privkey = input.ConstBytes() + mPublicKey.Length(); + sss_sscp_object_t * keypair = to_keypair(&mKeypair); + + VerifyOrExit(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + bbuf.Put(input.ConstBytes(), mPublicKey.Length()); + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY); + + /* must load plain text private key inside SSS */ + VerifyOrExit((sss_sscp_key_object_init(keypair, &g_keyStore) == kStatus_SSS_Success), error = CHIP_ERROR_INTERNAL); + + /* Allocate key handle */ + VerifyOrExit(sss_sscp_key_object_allocate_handle(keypair, 0x0u, kSSS_KeyPart_Private, kSSS_CipherType_EC_NIST_P, + kP256_PrivateKey_Length, SSS_KEYPROP_OPERATION_ASYM) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + + if (SSS_KEY_STORE_SET_KEY(keypair, privkey, kP256_PrivateKey_Length, kP256_PrivateKey_Length * 8, kSSS_KeyPart_Private) != + kStatus_SSS_Success) + { + (void) SSS_KEY_OBJ_FREE(keypair); + error = CHIP_ERROR_INTERNAL; + } + else + { + mInitialized = true; + } + +exit: + return error; +} +void P256Keypair::Clear() +{ + if (mInitialized) + { + sss_sscp_object_t * keypair = to_keypair(&mKeypair); + (void) SSS_KEY_OBJ_FREE(keypair); + mInitialized = false; + } +} + +P256Keypair::~P256Keypair() +{ + Clear(); +} + +CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const +{ + VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + + MutableByteSpan csr(out_csr, csr_length); + CHIP_ERROR err = GenerateCertificateSigningRequest(this, csr); + csr_length = (CHIP_NO_ERROR == err) ? csr.size() : 0; + return err; +} + +typedef struct Spake2p_Context +{ + ecp256Point_t M; + ecp256Point_t N; + ecp256Point_t X; + ecp256Point_t Y; + ecp256Point_t L; + ecp256Point_t Z; + ecp256Point_t V; + + big_int256_t w0; + big_int256_t w1; + big_int256_t xy; + big_int256_t 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)); + + M = &context->M; + N = &context->N; + X = &context->X; + Y = &context->Y; + L = &context->L; + V = &context->V; + Z = &context->Z; + + w0 = &context->w0; + w1 = &context->w1; + xy = &context->xy; + tempbn = &context->tempbn; + + return error; + +exit: + _log_mbedTLS_error(result); + Clear(); + return error; +} + +void Spake2p_P256_SHA256_HKDF_HMAC::Clear() +{ + VerifyOrReturn(state != CHIP_SPAKE2P_STATE::PREINIT); + + 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) +{ + secEcp256Status_t result; + uint32_t FE[SEC_ECP256_COORDINATE_WLEN]; + + result = ECP256_ModularReductionN(FE, in, in_len); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + result = ECP256_FieldLoad((uint32_t *) fe, (const uint8_t *) FE, in_len); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEWrite(const void * fe, uint8_t * out, size_t out_len) +{ + secEcp256Status_t result; + + result = ECP256_FieldWrite(out, (uint8_t *) fe); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEGenerate(void * fe) +{ + secEcp256Status_t result; + big_int256_t PrivateKey; + + result = ECP256_GeneratePrivateKey(&PrivateKey); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + result = ECP256_FieldWrite((uint8_t *) fe, (uint8_t *) &PrivateKey); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::FEMul(void * fer, const void * fe1, const void * fe2) +{ + secEcp256Status_t result; + + result = ECP256_ScalarMultiplicationModN((uint32_t *) fer, (const uint32_t *) fe1, (const uint32_t *) fe2); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointLoad(const uint8_t * in, size_t in_len, void * R) +{ + ECP256_PointLoad((ecp256Point_t *) R, in, false); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointWrite(const void * R, uint8_t * out, size_t out_len) +{ + ECP256_PointWrite(out, (ecp256Point_t *) R, false); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, const void * fe1) +{ + secEcp256Status_t result; + + result = ECP256_PointMult((ecp256Point_t *) R, (const uint8_t *) P1, (const uint8_t *) fe1); + VerifyOrReturnError(result == gSecEcp256Success_c, 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) +{ + secEcp256Status_t result; + + result = ECP256_DoublePointMulAdd(R, P1, fe1, P2, fe2); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointInvert(void * R) +{ + secEcp256Status_t result; + + result = ECP256_PointInvert((uint32_t *) R, (const uint32_t *) R); + VerifyOrReturnError(result == gSecEcp256Success_c, 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) +{ + secEcp256Status_t result; + ecp256Point_t gen_point; + uint32_t W1[SEC_ECP256_COORDINATE_WLEN]; + + result = ECP256_ModularReductionN(W1, w1in, w1in_len); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + result = ECP256_GeneratePublicKey((uint8_t *) &gen_point, (uint8_t *) &W1, NULL); + VerifyOrReturnError(result == gSecEcp256Success_c, CHIP_ERROR_INTERNAL); + + ECP256_PointWrite(Lout, (ecp256Point_t *) &gen_point, false); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointIsValid(void * R) +{ + VerifyOrReturnError(ECP256_PointValid((ecp256Point_t *) R), CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +} // namespace Crypto +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/CHIPDevicePlatformConfig.h b/src/platform/nxp/k32w/k32w1/CHIPDevicePlatformConfig.h new file mode 100644 index 00000000000000..60a1498cff9444 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/CHIPDevicePlatformConfig.h @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + * Platform-specific configuration overrides for the chip Device Layer + * on K32W platforms using the NXP SDK. + */ + +#pragma once + +// ==================== Platform Adaptations ==================== + +#define K32W_NO_ERRORS 0 +#define K32W_ENTRY_NOT_FOUND 1 + +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 + +#ifndef CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 +#endif + +#ifndef CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#define CHIP_DEVICE_CHIP0BLE_DEBUG 0 +#endif + +#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0 +// #define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_GLOBAL_EIDC_KEY 2 + +// ========== Platform-specific Configuration ========= + +// These are configuration options that are unique to the K32W platform. +// These can be overridden by the application as needed. + +/** + * @def CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY + * + * The priority of the SoftDevice observer event handler registered by the + * chip BleLayer. + */ +#ifndef CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY +#define CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY 3 +#endif // CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY + +/** + * @def CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG + * + * The SoftDevice BLE connection configuration tag used by the chip + * BleLayer. + */ +#ifndef CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG +#define CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG 1 +#endif // CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG + +/** + * @def CHIP_DEVICE_LAYER_OTA_REBOOT_DELAY + * + * The delay before rebooting after an OTA process was finished. + */ +#ifndef CHIP_DEVICE_LAYER_OTA_REBOOT_DELAY +#define CHIP_DEVICE_LAYER_OTA_REBOOT_DELAY 3000 +#endif // CHIP_DEVICE_LAYER_OTA_REBOOT_DELAY + +// ========== Platform-specific Configuration Overrides ========= +#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE +#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE (6 * 1024) +#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE + +#ifndef CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE +#define CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE 3072 +#endif // CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE + +// Max size of event queue +#define CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE 25 + +#ifndef CHIP_DEVICE_CONFIG_BLE_APP_TASK_NAME +#define CHIP_DEVICE_CONFIG_BLE_APP_TASK_NAME "BLE App Task" +#endif // CHIP_DEVICE_CONFIG_BLE_APP_TASK_NAME + +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY 0 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY 0 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY_FULL 0 + +#define CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED 1 + +#define CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART 0 + +#define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART 0 + +#define CHIP_DEVICE_CONFIG_THREAD_TASK_PRIORITY 3 + +#define CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY 2 + +#if CHIP_ENABLE_OPENTHREAD +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD 1 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT 1 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT 1 +#endif + +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS 1 diff --git a/src/platform/nxp/k32w/k32w1/CHIPDevicePlatformEvent.h b/src/platform/nxp/k32w/k32w1/CHIPDevicePlatformEvent.h new file mode 100644 index 00000000000000..e4acfb369c4bef --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/CHIPDevicePlatformEvent.h @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Defines platform-specific event types and data for the chip + * Device Layer on K32W061 platforms using the NXP SDK. + */ + +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { + +namespace DeviceEventType { + +/** + * Enumerates K32W1 platform-specific event types that are visible to the application. + */ +enum PublicPlatformSpecificEventTypes +{ + /* None currently defined */ +}; + +/** + * Enumerates K32W061 platform-specific event types that are internal to the chip Device Layer. + */ +enum InternalPlatformSpecificEventTypes +{ + /* None currently defined */ +}; + +} // namespace DeviceEventType + +/** + * Represents platform-specific event information for NXP K32W061 platforms. + */ + +struct ChipDevicePlatformEvent final +{ +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/CHIPPlatformConfig.h b/src/platform/nxp/k32w/k32w1/CHIPPlatformConfig.h new file mode 100644 index 00000000000000..b8ae07689e14bb --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/CHIPPlatformConfig.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + * Platform-specific configuration overrides for CHIP on + * NXP K32W platforms. + */ + +#pragma once + +#include + +// ==================== General Platform Adaptations ==================== + +#define CHIP_CONFIG_ABORT() abort() + +#define CHIP_CONFIG_PERSISTED_STORAGE_KEY_TYPE uint16_t +#define CHIP_CONFIG_PERSISTED_STORAGE_ENC_MSG_CNTR_ID 1 +#define CHIP_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH 2 + +#define CHIP_CONFIG_LIFETIIME_PERSISTED_COUNTER_KEY 0x01 + +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE (512) +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE (512) + +// ==================== Security Adaptations ==================== + +// FIXME: K32W currently set to CHIP (Does this use Entropy.cpp ?) + +// ==================== General Configuration Overrides ==================== + +#ifndef CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS +#define CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS 8 +#endif // CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS + +#ifndef CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS +#define CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS 8 +#endif // CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS + +#ifndef CHIP_LOG_FILTERING +#define CHIP_LOG_FILTERING 0 +#endif // CHIP_LOG_FILTERING + +#ifndef CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS +#define CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS 1 +#endif // CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS + +// ==================== WDM Configuration Overrides ==================== + +#ifndef WDM_MAX_NUM_SUBSCRIPTION_CLIENTS +#define WDM_MAX_NUM_SUBSCRIPTION_CLIENTS 2 +#endif // WDM_MAX_NUM_SUBSCRIPTION_CLIENTS + +#ifndef WDM_MAX_NUM_SUBSCRIPTION_HANDLERS +#define WDM_MAX_NUM_SUBSCRIPTION_HANDLERS 2 +#endif // WDM_MAX_NUM_SUBSCRIPTION_HANDLERS + +#ifndef WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT +#define WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT 2 +#endif // WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT diff --git a/src/platform/nxp/k32w/k32w1/ConfigurationManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/ConfigurationManagerImpl.cpp new file mode 100644 index 00000000000000..43aa7fa591b8f0 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ConfigurationManagerImpl.cpp @@ -0,0 +1,291 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides the implementation of the Device Layer ConfigurationManager object + * for K32W platforms using the NXP SDK. + */ + +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include + +// #include +#include "fsl_cmc.h" +#include "fsl_device_registers.h" + +namespace chip { +namespace DeviceLayer { + +using namespace ::chip::DeviceLayer::Internal; + +// TODO: Define a Singleton instance of CHIP Group Key Store here + +ConfigurationManagerImpl & ConfigurationManagerImpl::GetDefaultInstance() +{ + static ConfigurationManagerImpl sInstance; + return sInstance; +} + +CHIP_ERROR ConfigurationManagerImpl::Init() +{ + CHIP_ERROR err; + uint32_t rebootCount = 0; + + if (K32WConfig::ConfigValueExists(K32WConfig::kCounterKey_RebootCount)) + { + err = GetRebootCount(rebootCount); + SuccessOrExit(err); + + err = StoreRebootCount(rebootCount + 1); + SuccessOrExit(err); + } + else + { + // The first boot after factory reset of the Node. + err = StoreRebootCount(0); + SuccessOrExit(err); + } + + if (!K32WConfig::ConfigValueExists(K32WConfig::kCounterKey_TotalOperationalHours)) + { + err = StoreTotalOperationalHours(0); + SuccessOrExit(err); + } + + if (!K32WConfig::ConfigValueExists(K32WConfig::kCounterKey_BootReason)) + { + err = StoreBootReason(to_underlying(BootReasonType::kUnspecified)); + SuccessOrExit(err); + } + + // Initialize the generic implementation base class. + err = Internal::GenericConfigurationManagerImpl::Init(); + SuccessOrExit(err); + + // TODO: Initialize the global GroupKeyStore object here + + err = CHIP_NO_ERROR; + +exit: + return err; +} + +CHIP_ERROR ConfigurationManagerImpl::StoreSoftwareUpdateCompleted() +{ + /* Empty implementation*/ + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConfigurationManagerImpl::GetRebootCount(uint32_t & rebootCount) +{ + return ReadConfigValue(K32WConfig::kCounterKey_RebootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreRebootCount(uint32_t rebootCount) +{ + return WriteConfigValue(K32WConfig::kCounterKey_RebootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + return ReadConfigValue(K32WConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return WriteConfigValue(K32WConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::GetBootReason(uint32_t & bootReason) +{ + bootReason = to_underlying(BootReasonType::kUnspecified); + + uint32_t reason = CMC_GetSystemResetStatus(CMC0); + + if ((reason & CMC_SRS_POR_MASK) || (reason & CMC_SRS_PIN_MASK)) + { + bootReason = to_underlying(BootReasonType::kPowerOnReboot); + } + else if (reason & CMC_SRS_SW_MASK) + { + bootReason = to_underlying(BootReasonType::kSoftwareReset); + } + else if ((reason & CMC_SRS_WDOG0_MASK) || (reason & CMC_SRS_WDOG1_MASK)) + { + bootReason = to_underlying(BootReasonType::kSoftwareWatchdogReset); + } + else + { + bootReason = to_underlying(BootReasonType::kUnspecified); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConfigurationManagerImpl::StoreBootReason(uint32_t bootReason) +{ + return WriteConfigValue(K32WConfig::kCounterKey_BootReason, bootReason); +} + +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::ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key persistedStorageKey, + uint32_t & value) +{ + CHIP_ERROR err; + + err = K32WConfig::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 = K32WConfig::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 K32WConfig::ReadConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint32_t & val) +{ + return K32WConfig::ReadConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint64_t & val) +{ + return K32WConfig::ReadConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) +{ + return K32WConfig::ReadConfigValueStr(key, buf, bufSize, outLen); +} + +CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +{ + return K32WConfig::ReadConfigValueBin(key, buf, bufSize, outLen); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, bool val) +{ + return K32WConfig::WriteConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint32_t val) +{ + return K32WConfig::WriteConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint64_t val) +{ + return K32WConfig::WriteConfigValue(key, val); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str) +{ + return K32WConfig::WriteConfigValueStr(key, str); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str, size_t strLen) +{ + return K32WConfig::WriteConfigValueStr(key, str, strLen); +} + +CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) +{ + return K32WConfig::WriteConfigValueBin(key, data, dataLen); +} + +void ConfigurationManagerImpl::RunConfigUnitTest(void) +{ + K32WConfig::RunConfigUnitTest(); +} + +void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) +{ + CHIP_ERROR err; + + ChipLogProgress(DeviceLayer, "Performing factory reset"); + + err = K32WConfig::FactoryResetConfig(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "FactoryResetConfig() failed: %s", ErrorStr(err)); + } + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + + ThreadStackMgr().ErasePersistentInfo(); + +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD + + // Restart the system. + ChipLogProgress(DeviceLayer, "System restarting"); + + NVIC_SystemReset(); + + while (1) + { + } +} + +ConfigurationManager & ConfigurationMgrImpl() +{ + return ConfigurationManagerImpl::GetDefaultInstance(); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/ConfigurationManagerImpl.h b/src/platform/nxp/k32w/k32w1/ConfigurationManagerImpl.h new file mode 100644 index 00000000000000..26201d85f58a52 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ConfigurationManagerImpl.h @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation of the ConfigurationManager object + * for K32W platforms using the NXP SDK. + */ + +#pragma once + +#include "K32W1Config.h" +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the ConfigurationManager singleton object for the K32W platform. + */ +class ConfigurationManagerImpl final : public Internal::GenericConfigurationManagerImpl +{ +public: + // This returns an instance of this class. + static ConfigurationManagerImpl & GetDefaultInstance(); + CHIP_ERROR StoreSoftwareUpdateCompleted(); + +private: + // ===== Members that implement the ConfigurationManager public interface. + + CHIP_ERROR Init(void) override; + CHIP_ERROR GetPrimaryWiFiMACAddress(uint8_t * buf) override; + bool CanFactoryReset(void) override; + void InitiateFactoryReset(void) override; + CHIP_ERROR ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value) override; + CHIP_ERROR WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value) override; + CHIP_ERROR GetRebootCount(uint32_t & rebootCount) override; + CHIP_ERROR StoreRebootCount(uint32_t rebootCount) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours) override; + CHIP_ERROR GetBootReason(uint32_t & bootReasons) override; + CHIP_ERROR StoreBootReason(uint32_t bootReasons) override; + + // NOTE: Other public interface methods are implemented by GenericConfigurationManagerImpl<>. + + // ===== Members that implement the GenericConfigurationManagerImpl protected interface. + CHIP_ERROR ReadConfigValue(Key key, bool & val) override; + CHIP_ERROR ReadConfigValue(Key key, uint32_t & val) override; + CHIP_ERROR ReadConfigValue(Key key, uint64_t & val) override; + CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) override; + CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) override; + CHIP_ERROR WriteConfigValue(Key key, bool val) override; + CHIP_ERROR WriteConfigValue(Key key, uint32_t val) override; + CHIP_ERROR WriteConfigValue(Key key, uint64_t val) override; + CHIP_ERROR WriteConfigValueStr(Key key, const char * str) override; + CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen) override; + CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) override; + void RunConfigUnitTest(void) override; + + // ===== Private members reserved for use by this class only. + + static void DoFactoryReset(intptr_t arg); +}; + +inline CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * buf) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Returns the platform-specific implementation of the ConfigurationManager object. + * + * Applications can use this to gain access to features of the ConfigurationManager + * that are specific to the selected platform. + */ +ConfigurationManager & ConfigurationMgrImpl(); + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/ConnectivityManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/ConnectivityManagerImpl.cpp new file mode 100644 index 00000000000000..3182a874fbf41c --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ConnectivityManagerImpl.cpp @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include + +#if CHIP_SYSTEM_CONFIG_USE_LWIP +#include +#include +#include +#include +#endif + +#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/nxp/k32w/k32w1/ConnectivityManagerImpl.h b/src/platform/nxp/k32w/k32w1/ConnectivityManagerImpl.h new file mode 100644 index 00000000000000..4b8708d3dc604b --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ConnectivityManagerImpl.h @@ -0,0 +1,105 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + +#include +#include +#include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include +#else +#include +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#else +#include +#endif +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the ConnectivityManager singleton object for NXP K32W platforms. + */ +class ConnectivityManagerImpl final : public ConnectivityManager, +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + public Internal::GenericConnectivityManagerImpl_BLE, +#else + public Internal::GenericConnectivityManagerImpl_NoBLE, +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + public Internal::GenericConnectivityManagerImpl_Thread, +#else + public Internal::GenericConnectivityManagerImpl_NoThread, +#endif + public Internal::GenericConnectivityManagerImpl_NoWiFi, + public Internal::GenericConnectivityManagerImpl_UDP, +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + public Internal::GenericConnectivityManagerImpl_TCP, +#endif + public Internal::GenericConnectivityManagerImpl +{ + // Allow the ConnectivityManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class ConnectivityManager; + +private: + // ===== Members that implement the ConnectivityManager abstract interface. + + CHIP_ERROR _Init(void); + void _OnPlatformEvent(const ChipDeviceEvent * event); + + // ===== Members for internal use by the following friends. + + friend ConnectivityManager & ConnectivityMgr(void); + friend ConnectivityManagerImpl & ConnectivityMgrImpl(void); + + static ConnectivityManagerImpl sInstance; +}; + +/** + * Returns the public interface of the ConnectivityManager singleton object. + * + * Chip applications should use this to access features of the ConnectivityManager object + * that are common to all platforms. + */ +inline ConnectivityManager & ConnectivityMgr(void) +{ + return ConnectivityManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the ConnectivityManager singleton object. + * + * Chip applications can use this to gain access to features of the ConnectivityManager + * that are specific to the ESP32 platform. + */ +inline ConnectivityManagerImpl & ConnectivityMgrImpl(void) +{ + return ConnectivityManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/DefaultTestEventTriggerDelegate.cpp b/src/platform/nxp/k32w/k32w1/DefaultTestEventTriggerDelegate.cpp new file mode 100644 index 00000000000000..1a01acfdb69385 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/DefaultTestEventTriggerDelegate.cpp @@ -0,0 +1,42 @@ +/* + * + * 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 "DefaultTestEventTriggerDelegate.h" + +#include +#include + +namespace chip { + +bool DefaultTestEventTriggerDelegate::DoesEnableKeyMatch(const ByteSpan & enableKey) const +{ + return !mEnableKey.empty() && mEnableKey.data_equal(enableKey); +} + +CHIP_ERROR DefaultTestEventTriggerDelegate::HandleEventTrigger(uint64_t eventTrigger) +{ + if (eventTrigger == kQueryTrigger) + { + ChipLogProgress(DeviceLayer, "DefaultTestEventTriggerDelegate: event triggered"); + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INVALID_ARGUMENT; +} + +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/DefaultTestEventTriggerDelegate.h b/src/platform/nxp/k32w/k32w1/DefaultTestEventTriggerDelegate.h new file mode 100644 index 00000000000000..cf71fb37d96470 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/DefaultTestEventTriggerDelegate.h @@ -0,0 +1,39 @@ +/* + * + * 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 + +namespace chip { + +class DefaultTestEventTriggerDelegate : public TestEventTriggerDelegate +{ +public: + static constexpr uint64_t kQueryTrigger = 1234; + + explicit DefaultTestEventTriggerDelegate(const ByteSpan & enableKey) : mEnableKey(enableKey) {} + + bool DoesEnableKeyMatch(const ByteSpan & enableKey) const override; + CHIP_ERROR HandleEventTrigger(uint64_t eventTrigger) override; + +private: + ByteSpan mEnableKey; +}; + +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/DiagnosticDataProviderImpl.cpp b/src/platform/nxp/k32w/k32w1/DiagnosticDataProviderImpl.cpp new file mode 100644 index 00000000000000..5bc354351e4fb7 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/DiagnosticDataProviderImpl.cpp @@ -0,0 +1,232 @@ +/* + * + * 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. + */ + +/** + * @file + * Provides an implementation of the DiagnosticDataProvider object + * for k32w1 platform. + */ + +#include + +#include +#include +#include + +#if CHIP_SYSTEM_CONFIG_USE_LWIP +#include +#endif + +extern "C" void xPortResetHeapMinimumEverFreeHeapSize(void); + +#include + +#include + +using namespace ::chip::app::Clusters::GeneralDiagnostics; + +namespace chip { +namespace DeviceLayer { + +DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() +{ + static DiagnosticDataProviderImpl sInstance; + return sInstance; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree) +{ + size_t freeHeapSize; + + freeHeapSize = xPortGetFreeHeapSize(); + currentHeapFree = static_cast(freeHeapSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeapUsed) +{ + size_t freeHeapSize; + size_t usedHeapSize; + + freeHeapSize = xPortGetFreeHeapSize(); + usedHeapSize = MinimalHeapSize_c - freeHeapSize; + + currentHeapUsed = static_cast(usedHeapSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) +{ + size_t highWatermarkHeapSize; + + highWatermarkHeapSize = MinimalHeapSize_c - xPortGetMinimumEverFreeHeapSize(); + currentHeapHighWatermark = static_cast(highWatermarkHeapSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetThreadMetrics(ThreadMetrics ** threadMetricsOut) +{ + /* Obtain all available task information */ + TaskStatus_t * taskStatusArray; + ThreadMetrics * head = nullptr; + unsigned long arraySize, x, dummy; + + arraySize = uxTaskGetNumberOfTasks(); + + taskStatusArray = (TaskStatus_t *) pvPortMalloc(arraySize * sizeof(TaskStatus_t)); + + if (taskStatusArray != NULL) + { + /* Generate raw status information about each task. */ + arraySize = uxTaskGetSystemState(taskStatusArray, arraySize, &dummy); + /* For each populated position in the taskStatusArray array, + format the raw data as human readable ASCII data. */ + + for (x = 0; x < arraySize; x++) + { + ThreadMetrics * thread = (ThreadMetrics *) pvPortMalloc(sizeof(ThreadMetrics)); + + strncpy(thread->NameBuf, taskStatusArray[x].pcTaskName, kMaxThreadNameLength - 1); + thread->NameBuf[kMaxThreadNameLength] = '\0'; + thread->name.Emplace(CharSpan::fromCharString(thread->NameBuf)); + thread->id = taskStatusArray[x].xTaskNumber; + + thread->stackFreeMinimum.Emplace(taskStatusArray[x].usStackHighWaterMark); + + /* Unsupported metrics */ + thread->stackFreeCurrent.ClearValue(); + thread->stackSize.ClearValue(); + + thread->Next = head; + head = thread; + } + + *threadMetricsOut = head; + /* The array is no longer needed, free the memory it consumes. */ + vPortFree(taskStatusArray); + } + + return CHIP_NO_ERROR; +} + +void DiagnosticDataProviderImpl::ReleaseThreadMetrics(ThreadMetrics * threadMetrics) +{ + while (threadMetrics) + { + ThreadMetrics * del = threadMetrics; + threadMetrics = threadMetrics->Next; + vPortFree(del); + } +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount) +{ + uint32_t count = 0; + + CHIP_ERROR err = ConfigurationMgr().GetRebootCount(count); + + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(count <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rebootCount = static_cast(count); + } + + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetUpTime(uint64_t & upTime) +{ + System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp(); + System::Clock::Timestamp startTime = PlatformMgrImpl().GetStartTime(); + + if (currentTime >= startTime) + { + upTime = std::chrono::duration_cast(currentTime - startTime).count(); + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + uint64_t upTime = 0; + + if (GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalHours = 0; + if (ConfigurationMgr().GetTotalOperationalHours(totalHours) == CHIP_NO_ERROR) + { + VerifyOrReturnError(upTime / 3600 <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + totalOperationalHours = totalHours + static_cast(upTime / 3600); + return CHIP_NO_ERROR; + } + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(BootReasonType & bootReason) +{ + uint32_t reason = 0; + + CHIP_ERROR err = ConfigurationMgr().GetBootReason(reason); + + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(reason <= UINT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + bootReason = static_cast(reason); + } + + return err; +} + +DiagnosticDataProvider & GetDiagnosticDataProviderImpl() +{ + return DiagnosticDataProviderImpl::GetDefaultInstance(); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp) +{ + NetworkInterface * ifp = new NetworkInterface(); + + const char * threadNetworkName = otThreadGetNetworkName(ThreadStackMgrImpl().OTInstance()); + ifp->name = Span(threadNetworkName, strlen(threadNetworkName)); + ifp->isOperational = true; + ifp->offPremiseServicesReachableIPv4.SetNull(); + ifp->offPremiseServicesReachableIPv6.SetNull(); + ifp->type = InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_THREAD; + uint8_t macBuffer[ConfigurationManager::kPrimaryMACAddressLength]; + ConfigurationMgr().GetPrimary802154MACAddress(macBuffer); + ifp->hardwareAddress = ByteSpan(macBuffer, ConfigurationManager::kPrimaryMACAddressLength); + ifp->Next = nullptr; + + *netifpp = ifp; + return CHIP_NO_ERROR; +} + +void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp) +{ + while (netifp) + { + NetworkInterface * del = netifp; + netifp = netifp->Next; + delete del; + } +} +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/DiagnosticDataProviderImpl.h b/src/platform/nxp/k32w/k32w1/DiagnosticDataProviderImpl.h new file mode 100644 index 00000000000000..78cca26b3683ee --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/DiagnosticDataProviderImpl.h @@ -0,0 +1,66 @@ +/* + * + * 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. + */ + +/** + * @file + * Provides an implementation of the DiagnosticDataProvider object. + */ + +#pragma once + +#include + +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the PlatformManager singleton object for Linux platforms. + */ +class DiagnosticDataProviderImpl : public DiagnosticDataProvider +{ +public: + static DiagnosticDataProviderImpl & GetDefaultInstance(); + + // ===== Methods that implement the PlatformManager abstract interface. + + bool SupportsWatermarks() override { return true; } + CHIP_ERROR GetCurrentHeapFree(uint64_t & currentHeapFree) override; + CHIP_ERROR GetCurrentHeapUsed(uint64_t & currentHeapUsed) override; + CHIP_ERROR GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) override; + CHIP_ERROR GetThreadMetrics(ThreadMetrics ** threadMetricsOut) override; + void ReleaseThreadMetrics(ThreadMetrics * threadMetrics) override; + + CHIP_ERROR GetRebootCount(uint16_t & rebootCount) override; + CHIP_ERROR GetUpTime(uint64_t & upTime) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR GetBootReason(BootReasonType & bootReason) override; + CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override; + void ReleaseNetworkInterfaces(NetworkInterface * netifp) override; +}; + +/** + * Returns the platform-specific implementation of the DiagnosticDataProvider singleton object. + * + * Applications can use this to gain access to features of the DiagnosticDataProvider + * that are specific to the selected platform. + */ +DiagnosticDataProvider & GetDiagnosticDataProviderImpl(); + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/InetPlatformConfig.h b/src/platform/nxp/k32w/k32w1/InetPlatformConfig.h new file mode 100644 index 00000000000000..e59c31f75eac37 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/InetPlatformConfig.h @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + * Platform-specific configuration overrides for the CHIP Inet + * Layer on K32W platforms using the NXP SDK. + * + */ + +#pragma once + +// ==================== Platform Adaptations ==================== + +#ifndef INET_CONFIG_ENABLE_IPV4 +#error Inet IPv4 configuration should be configured at build generation time +#endif + +// ========== Platform-specific Configuration Overrides ========= + +#ifndef INET_CONFIG_NUM_TCP_ENDPOINTS +#define INET_CONFIG_NUM_TCP_ENDPOINTS 4 +#endif // INET_CONFIG_NUM_TCP_ENDPOINTS + +#ifndef INET_CONFIG_NUM_UDP_ENDPOINTS +#define INET_CONFIG_NUM_UDP_ENDPOINTS 4 +#endif // INET_CONFIG_NUM_UDP_ENDPOINTS diff --git a/src/platform/nxp/k32w/k32w1/K32W1Config.cpp b/src/platform/nxp/k32w/k32w1/K32W1Config.cpp new file mode 100644 index 00000000000000..ee41809dcca7b9 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/K32W1Config.cpp @@ -0,0 +1,435 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 Google LLC. + * Copyright (c) 2018 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 + * Utilities for accessing persisted device configuration on + * platforms based on the NXP K32W SDK. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include + +#include +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#endif + +#if (defined(K32W_LOG_ENABLED) && (K32W_LOG_ENABLED > 0)) +// #include "fsl_component_log.h" +// #include "fsl_component_log_backend_debugconsole.h" +#endif +#include "FreeRTOS.h" +#include "FunctionLib.h" +#include "NVM_Interface.h" + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +#ifndef CHIP_PLAT_NVM_SUPPORT +#define CHIP_PLAT_NVM_SUPPORT 0 +#endif + +#ifndef CHIP_PLAT_NVM_STATIC_ALLOC +#define CHIP_PLAT_NVM_STATIC_ALLOC 1 +#endif + +#define CHIP_CONFIG_RAM_BUFFER_SIZE 10240 + +#ifndef NVM_ID_CHIP_CONFIG_DATA +#define NVM_ID_CHIP_CONFIG_DATA 0xf104 +#endif + +#if 0 +typedef struct +{ + uint16_t chipConfigRamBufferLen; + uint8_t chipConfigRamBuffer[3072]; +} ChipConfigRamStruct_t; +static ChipConfigRamStruct_t *chipConfigRamStruct; +#endif + +#if CHIP_PLAT_NVM_STATIC_ALLOC +static uint8_t chipConfigRamBuffer[CHIP_CONFIG_RAM_BUFFER_SIZE] = { 0 }; +#endif + +static ramBufferDescriptor * ramDescr; + +#define RAM_DESC_HEADER_SIZE (sizeof(ramDescr->ramBufferLen + ramDescr->ramBufferMaxLen)) + +#if CHIP_PLAT_NVM_SUPPORT +NVM_RegisterDataSet((void *) chipConfigRamBuffer, 1, sizeof(chipConfigRamBuffer), NVM_ID_CHIP_CONFIG_DATA, gNVM_MirroredInRam_c); +#endif + +static rsError AddToRamStorage(ramBufferDescriptor * pBuffer, uint16_t aKey, const uint8_t * aValue, uint16_t aValueLength) +{ + rsError err; + +#if !CHIP_PLAT_NVM_STATIC_ALLOC + uint32_t allocSize = pBuffer->ramBufferMaxLen; + + if (allocSize <= pBuffer->ramBufferLen + aValueLength) + { + while (allocSize < pBuffer->ramBufferLen + aValueLength) + { + /* Need to realocate the memory buffer, increase size by 512B until nvm data fits */ + allocSize += 512; + } + + pBuffer->ramBufferLen = allocSize; + allocSize += RAM_DESC_HEADER_SIZE; + + pBuffer = (ramBufferDescriptor *) realloc((void *) pBuffer, allocSize); + VerifyOrExit((NULL != pBuffer), err = RS_ERROR_NO_BUFS); + } +#endif + + err = ramStorageSet(pBuffer, aKey, aValue, aValueLength); + +#if !CHIP_PLAT_NVM_STATIC_ALLOC +exit: +#endif + + return err; +} + +CHIP_ERROR K32WConfig::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + bool bLoadDataFromNvm = true; + uint32_t allocSize = CHIP_CONFIG_RAM_BUFFER_SIZE; + + /* Initialise the Persistent Data Manager */ +#if CHIP_PLAT_NVM_SUPPORT + /* Init the NVM module */ + NvModuleInit(); +#endif + +#if CHIP_PLAT_NVM_STATIC_ALLOC + ramDescr = (ramBufferDescriptor *) chipConfigRamBuffer; +#else + ramDescr = (ramBufferDescriptor *) malloc(allocSize); + VerifyOrExit((NULL != ramDescr), err = CHIP_ERROR_NO_MEMORY); +#endif + + ramDescr->ramBufferLen = 0; + + if (bLoadDataFromNvm) + { + /* Try to load the dataset in RAM */ +#if CHIP_PLAT_NVM_SUPPORT + NvRestoreDataSet((void *) ramDescr, 0); +#endif + } + + ramDescr->ramBufferMaxLen = allocSize - RAM_DESC_HEADER_SIZE; + +#if !CHIP_PLAT_NVM_STATIC_ALLOC +exit: +#endif + + return err; +} + +CHIP_ERROR K32WConfig::ReadConfigValue(Key key, bool & val) +{ + CHIP_ERROR err; + bool tempVal; + rsError status; + uint16_t sizeToRead = sizeof(tempVal); + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = ramStorageGet(ramDescr, key, 0, (uint8_t *) &tempVal, &sizeToRead); + SuccessOrExit(err = MapRamStorageStatus(status)); + val = tempVal; + +exit: + return err; +} + +CHIP_ERROR K32WConfig::ReadConfigValue(Key key, uint32_t & val) +{ + CHIP_ERROR err; + uint32_t tempVal; + rsError status; + uint16_t sizeToRead = sizeof(tempVal); + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = ramStorageGet(ramDescr, key, 0, (uint8_t *) &tempVal, &sizeToRead); + SuccessOrExit(err = MapRamStorageStatus(status)); + val = tempVal; + +exit: + return err; +} + +CHIP_ERROR K32WConfig::ReadConfigValue(Key key, uint64_t & val) +{ + CHIP_ERROR err; + uint32_t tempVal; + rsError status; + uint16_t sizeToRead = sizeof(tempVal); + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = ramStorageGet(ramDescr, key, 0, (uint8_t *) &tempVal, &sizeToRead); + SuccessOrExit(err = MapRamStorageStatus(status)); + val = tempVal; + +exit: + return err; +} + +CHIP_ERROR K32WConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) +{ + CHIP_ERROR err; + rsError status; + uint16_t sizeToRead = bufSize; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + + // We can call ramStorageGet with null pointer to only retrieve the size + status = ramStorageGet(ramDescr, key, 0, (uint8_t *) buf, &sizeToRead); + SuccessOrExit(err = MapRamStorageStatus(status)); + outLen = sizeToRead; + +exit: + return err; +} + +CHIP_ERROR K32WConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +{ + return ReadConfigValueStr(key, (char *) buf, bufSize, outLen); +} + +CHIP_ERROR K32WConfig::ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val) +{ + Key key = kMinConfigKey_ChipCounter + counterIdx; + return ReadConfigValue(key, val); +} + +CHIP_ERROR K32WConfig::WriteConfigValue(Key key, bool val) +{ + CHIP_ERROR err; + rsError status; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(bool)); + SuccessOrExit(err = MapRamStorageStatus(status)); + +#if CHIP_PLAT_NVM_SUPPORT + NvSaveOnIdle(ramDescr, false); +#endif + // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); + +exit: + return err; +} + +CHIP_ERROR K32WConfig::WriteConfigValueSync(Key key, bool val) +{ + CHIP_ERROR err; + rsError status; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(bool)); + SuccessOrExit(err = MapRamStorageStatus(status)); + +#if CHIP_PLAT_NVM_SUPPORT + NvSyncSave(ramDescr, false); +#endif + // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); + +exit: + return err; +} + +CHIP_ERROR K32WConfig::WriteConfigValue(Key key, uint32_t val) +{ + CHIP_ERROR err; + rsError status; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(uint32_t)); + SuccessOrExit(err = MapRamStorageStatus(status)); + +#if CHIP_PLAT_NVM_SUPPORT + NvSaveOnIdle(ramDescr, false); +#endif + // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); + +exit: + return err; +} + +CHIP_ERROR K32WConfig::WriteConfigValue(Key key, uint64_t val) +{ + CHIP_ERROR err; + rsError status; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(uint64_t)); + SuccessOrExit(err = MapRamStorageStatus(status)); + +#if CHIP_PLAT_NVM_SUPPORT + NvSaveOnIdle(ramDescr, false); +#endif + // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); + +exit: + return err; +} + +CHIP_ERROR K32WConfig::WriteConfigValueStr(Key key, const char * str) +{ + return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0); +} + +CHIP_ERROR K32WConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen) +{ + CHIP_ERROR err; + rsError status; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + + if (str != NULL) + { + status = AddToRamStorage(ramDescr, key, (uint8_t *) str, strLen); + SuccessOrExit(err = MapRamStorageStatus(status)); + +#if CHIP_PLAT_NVM_SUPPORT + NvSaveOnIdle(ramDescr, false); +#endif + } + else + { + err = ClearConfigValue(key); + SuccessOrExit(err); + } + +exit: + return err; +} + +CHIP_ERROR K32WConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) +{ + return WriteConfigValueStr(key, (char *) data, dataLen); +} + +CHIP_ERROR K32WConfig::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val) +{ + Key key = kMinConfigKey_ChipCounter + counterIdx; + return WriteConfigValue(key, val); +} + +CHIP_ERROR K32WConfig::ClearConfigValue(Key key) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + rsError status; + + VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. + status = ramStorageDelete(ramDescr, key, 0); + SuccessOrExit(err = MapRamStorageStatus(status)); + +#if CHIP_PLAT_NVM_SUPPORT + NvSaveOnIdle(ramDescr, false); +#endif + +exit: + return err; +} + +bool K32WConfig::ConfigValueExists(Key key) +{ + rsError status; + uint16_t sizeToRead; + bool found = false; + + if (ValidConfigKey(key)) + { + status = ramStorageGet(ramDescr, key, 0, NULL, &sizeToRead); + found = (status == RS_ERROR_NONE && sizeToRead != 0); + } + return found; +} + +CHIP_ERROR K32WConfig::FactoryResetConfig(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + FactoryResetConfigInternal(kMinConfigKey_ChipConfig, kMaxConfigKey_ChipConfig); + FactoryResetConfigInternal(kMinConfigKey_KVSKey, kMaxConfigKey_KVSKey); + FactoryResetConfigInternal(kMinConfigKey_KVSValue, kMaxConfigKey_KVSValue); + +#if CHIP_PLAT_NVM_SUPPORT + /* Save in flash now */ + NvSyncSave(ramDescr, false); +#endif + + return err; +} + +void K32WConfig::FactoryResetConfigInternal(Key firstKey, Key lastKey) +{ + for (Key key = firstKey; key <= lastKey; key++) + { + ramStorageDelete(ramDescr, key, 0); + } +} + +CHIP_ERROR K32WConfig::MapRamStorageStatus(rsError rsStatus) +{ + CHIP_ERROR err; + + switch (rsStatus) + { + case RS_ERROR_NONE: + err = CHIP_NO_ERROR; + break; + case RS_ERROR_NOT_FOUND: + err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + break; + default: + err = CHIP_ERROR_BUFFER_TOO_SMALL; + break; + } + + return err; +} + +bool K32WConfig::ValidConfigKey(Key key) +{ + // Returns true if the key is in the valid CHIP Config PDM key range. + if ((key >= kMinConfigKey_ChipFactory) && (key <= kMaxConfigKey_KVSValue)) + { + return true; + } + + return false; +} + +void K32WConfig::RunConfigUnitTest() {} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/K32W1Config.h b/src/platform/nxp/k32w/k32w1/K32W1Config.h new file mode 100644 index 00000000000000..a14b4d5cd10fdd --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/K32W1Config.h @@ -0,0 +1,144 @@ +/* + * + * 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 + * Utilities for accessing persisted device configuration on + * platforms based on the K32W1 SDK. + */ + +#pragma once + +#include + +#include + +#include "FreeRTOS.h" +#include "NVM_Interface.h" + +#include "ram_storage.h" + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +constexpr inline uint16_t K32WConfigKey(uint8_t chipId, uint8_t nvmId) +{ + return static_cast(chipId) << 8 | nvmId; +} + +/** + * This implementation uses the NVM component as the underlying storage layer. + * + * NOTE: This class is designed to be mixed-in to the concrete subclass of the + * GenericConfigurationManagerImpl<> template. When used this way, the class + * naturally provides implementations for the delegated members referenced by + * the template class (e.g. the ReadConfigValue() method). + */ +class K32WConfig +{ +public: + // Category ids used by the CHIP Device Layer + static constexpr uint8_t kFileId_ChipFactory = 0x01; /**< Category containing persistent config values set at + * manufacturing time. Retained during factory reset. */ + static constexpr uint8_t kFileId_ChipConfig = 0x02; /**< Catyegory containing dynamic config values set at runtime. + * Cleared during factory reset. */ + static constexpr uint8_t kFileId_ChipCounter = 0x03; /**< Category containing dynamic counter values set at runtime. + * Retained during factory reset. */ + static constexpr uint8_t kFileId_KVSKey = 0x04; /**< Category containing KVS set at runtime. + * Cleared during factory reset. */ + static constexpr uint8_t kFileId_KVSValue = 0x05; /**< Category containing KVS values set at runtime. + * Cleared during factory reset. */ + + using Key = uint16_t; + + // Key definitions for well-known configuration values. + // Factory config keys + static constexpr Key kConfigKey_SerialNum = K32WConfigKey(kFileId_ChipFactory, 0x00); + static constexpr Key kConfigKey_MfrDeviceId = K32WConfigKey(kFileId_ChipFactory, 0x01); + static constexpr Key kConfigKey_MfrDeviceCert = K32WConfigKey(kFileId_ChipFactory, 0x02); + static constexpr Key kConfigKey_MfrDevicePrivateKey = K32WConfigKey(kFileId_ChipFactory, 0x03); + static constexpr Key kConfigKey_ManufacturingDate = K32WConfigKey(kFileId_ChipFactory, 0x04); + static constexpr Key kConfigKey_SetupPinCode = K32WConfigKey(kFileId_ChipFactory, 0x05); + static constexpr Key kConfigKey_MfrDeviceICACerts = K32WConfigKey(kFileId_ChipFactory, 0x06); + static constexpr Key kConfigKey_HardwareVersion = K32WConfigKey(kFileId_ChipFactory, 0x07); + static constexpr Key kConfigKey_SetupDiscriminator = K32WConfigKey(kFileId_ChipFactory, 0x08); + static constexpr Key kConfigKey_Spake2pIterationCount = K32WConfigKey(kFileId_ChipFactory, 0x09); + static constexpr Key kConfigKey_Spake2pSalt = K32WConfigKey(kFileId_ChipFactory, 0x0A); + static constexpr Key kConfigKey_Spake2pVerifier = K32WConfigKey(kFileId_ChipFactory, 0x0B); + + // CHIP Config Keys + static constexpr Key kConfigKey_ServiceConfig = K32WConfigKey(kFileId_ChipConfig, 0x01); + static constexpr Key kConfigKey_PairedAccountId = K32WConfigKey(kFileId_ChipConfig, 0x02); + static constexpr Key kConfigKey_ServiceId = K32WConfigKey(kFileId_ChipConfig, 0x03); + static constexpr Key kConfigKey_LastUsedEpochKeyId = K32WConfigKey(kFileId_ChipConfig, 0x05); + static constexpr Key kConfigKey_FailSafeArmed = K32WConfigKey(kFileId_ChipConfig, 0x06); + static constexpr Key kConfigKey_RegulatoryLocation = K32WConfigKey(kFileId_ChipConfig, 0x07); + static constexpr Key kConfigKey_CountryCode = K32WConfigKey(kFileId_ChipConfig, 0x08); + static constexpr Key kConfigKey_UniqueId = K32WConfigKey(kFileId_ChipConfig, 0x0A); + static constexpr Key kConfigKey_SoftwareVersion = K32WConfigKey(kFileId_ChipConfig, 0x0B); + + // CHIP Counter Keys + static constexpr Key kCounterKey_RebootCount = K32WConfigKey(kFileId_ChipCounter, 0x00); + static constexpr Key kCounterKey_UpTime = K32WConfigKey(kFileId_ChipCounter, 0x01); + static constexpr Key kCounterKey_TotalOperationalHours = K32WConfigKey(kFileId_ChipCounter, 0x02); + static constexpr Key kCounterKey_BootReason = K32WConfigKey(kFileId_ChipCounter, 0x03); + + // Set key id limits for each group. + static constexpr Key kMinConfigKey_ChipFactory = K32WConfigKey(kFileId_ChipFactory, 0x00); + static constexpr Key kMaxConfigKey_ChipFactory = K32WConfigKey(kFileId_ChipFactory, 0xFF); + static constexpr Key kMinConfigKey_ChipConfig = K32WConfigKey(kFileId_ChipConfig, 0x00); + static constexpr Key kMaxConfigKey_ChipConfig = K32WConfigKey(kFileId_ChipConfig, 0xFF); + static constexpr Key kMinConfigKey_ChipCounter = K32WConfigKey(kFileId_ChipCounter, 0x00); + static constexpr Key kMaxConfigKey_ChipCounter = K32WConfigKey(kFileId_ChipCounter, 0xFF); // Allows 32 Counters to be created. + static constexpr Key kMinConfigKey_KVSKey = K32WConfigKey(kFileId_KVSKey, 0x00); + static constexpr Key kMaxConfigKey_KVSKey = K32WConfigKey(kFileId_KVSKey, 0xFF); + static constexpr Key kMinConfigKey_KVSValue = K32WConfigKey(kFileId_KVSValue, 0x00); + static constexpr Key kMaxConfigKey_KVSValue = K32WConfigKey(kFileId_KVSValue, 0xFF); + + static CHIP_ERROR Init(void); + + // Configuration methods used by the GenericConfigurationManagerImpl<> template. + static CHIP_ERROR ReadConfigValue(Key key, bool & val); + static CHIP_ERROR ReadConfigValue(Key key, uint32_t & val); + static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val); + static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen); + static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen); + static CHIP_ERROR ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val); + static CHIP_ERROR WriteConfigValue(Key key, bool val); + static CHIP_ERROR WriteConfigValueSync(Key key, bool val); + static CHIP_ERROR WriteConfigValue(Key key, uint32_t val); + static CHIP_ERROR WriteConfigValue(Key key, uint64_t val); + static CHIP_ERROR WriteConfigValueStr(Key key, const char * str); + static CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen); + static CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen); + static CHIP_ERROR WriteConfigValueCounter(uint8_t counterIdx, uint32_t val); + static CHIP_ERROR ClearConfigValue(Key key); + static bool ConfigValueExists(Key key); + static CHIP_ERROR FactoryResetConfig(void); + static bool ValidConfigKey(Key key); + + static void RunConfigUnitTest(void); + +private: + static CHIP_ERROR MapRamStorageStatus(rsError rsStatus); + static void FactoryResetConfigInternal(Key firstKey, Key lastKey); +}; + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/K32W1PersistentStorageOpKeystore.cpp b/src/platform/nxp/k32w/k32w1/K32W1PersistentStorageOpKeystore.cpp new file mode 100644 index 00000000000000..18c1ff41a79963 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/K32W1PersistentStorageOpKeystore.cpp @@ -0,0 +1,333 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "K32W1PersistentStorageOpKeystore.h" + +#include "sss_crypto.h" + +namespace chip { + +using namespace chip::Crypto; + +CHIP_ERROR P256KeypairSSS::Initialize(Crypto::ECPKeyTarget key_target) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + size_t keyBitsLen = kP256_PrivateKey_Length * 8; + size_t keySize = SSS_ECP_KEY_SZ(kP256_PrivateKey_Length); + + Clear(); + + VerifyOrReturnError(sss_sscp_key_object_init(&mKeyObj, &g_keyStore) == kStatus_SSS_Success, CHIP_ERROR_INTERNAL); + + VerifyOrReturnError(sss_sscp_key_object_allocate_handle( + &mKeyObj, 0x0u, kSSS_KeyPart_Pair, kSSS_CipherType_EC_NIST_P, 3 * kP256_PrivateKey_Length, + SSS_KEYPROP_OPERATION_KDF | SSS_KEYPROP_OPERATION_ASYM) == kStatus_SSS_Success, + error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(SSS_ECP_GENERATE_KEY(&mKeyObj, keyBitsLen) == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + // The first byte of the public key is the uncompressed marker + Uint8::to_uchar(mPublicKey)[0] = 0x04; + + // Extract public key, write from the second byte + VerifyOrExit(SSS_KEY_STORE_GET_PUBKEY(&mKeyObj, Uint8::to_uchar(mPublicKey) + 1, &keySize, &keyBitsLen) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + + mInitialized = true; + +exit: + if (mInitialized != true) + (void) SSS_KEY_OBJ_FREE(&mKeyObj); + + return error; +} + +CHIP_ERROR P256KeypairSSS::ExportBlob(P256SerializedKeypairSSS & output) const +{ + VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + + size_t keyBlobLen = output.Capacity(); + VerifyOrReturnError(sss_sscp_key_store_export_key(&g_keyStore, &mKeyObj, output.Bytes(), &keyBlobLen, + kSSS_blobType_ELKE_blob) == kStatus_SSS_Success, + CHIP_ERROR_INTERNAL); + output.SetLength(keyBlobLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR P256KeypairSSS::ImportBlob(P256SerializedKeypairSSS & input) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + if (false == mInitialized) + { + VerifyOrExit((sss_sscp_key_object_init(&mKeyObj, &g_keyStore) == kStatus_SSS_Success), error = CHIP_ERROR_INTERNAL); + + /* Allocate key handle */ + VerifyOrExit( + (sss_sscp_key_object_allocate_handle(&mKeyObj, 0x0u, kSSS_KeyPart_Pair, kSSS_CipherType_EC_NIST_P, + 3 * kP256_PrivateKey_Length, SSS_KEYPROP_OPERATION_ASYM) == kStatus_SSS_Success), + error = CHIP_ERROR_INTERNAL); + } + + VerifyOrExit((sss_sscp_key_store_import_key(&g_keyStore, &mKeyObj, input.Bytes(), input.Length(), kP256_PrivateKey_Length * 8, + kSSS_blobType_ELKE_blob) == kStatus_SSS_Success), + error = CHIP_ERROR_INTERNAL); + + mInitialized = true; + +exit: + return error; +} + +CHIP_ERROR P256KeypairSSS::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + sss_sscp_asymmetric_t asyc; + size_t signatureSize = kP256_ECDSA_Signature_Length_Raw; + + VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t digest[kSHA256_Hash_Length]; + memset(&digest[0], 0, sizeof(digest)); + ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0])); + + VerifyOrExit((sss_sscp_asymmetric_context_init(&asyc, &g_sssSession, &mKeyObj, kAlgorithm_SSS_ECDSA_SHA256, kMode_SSS_Sign) == + kStatus_SSS_Success), + error = CHIP_ERROR_INTERNAL); + VerifyOrExit((sss_sscp_asymmetric_sign_digest(&asyc, digest, kP256_FE_Length, out_signature.Bytes(), &signatureSize) == + kStatus_SSS_Success), + error = CHIP_ERROR_INTERNAL); + VerifyOrExit(out_signature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, error = CHIP_ERROR_INTERNAL); + +exit: + (void) sss_sscp_asymmetric_context_free(&asyc); + return error; +} + +CHIP_ERROR P256KeypairSSS::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const +{ + VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + + MutableByteSpan csr(out_csr, csr_length); + CHIP_ERROR err = GenerateCertificateSigningRequest(this, csr); + csr_length = (CHIP_NO_ERROR == err) ? csr.size() : 0; + return err; +} + +void P256KeypairSSS::Clear() +{ + if (mInitialized) + { + (void) SSS_KEY_OBJ_FREE(&mKeyObj); + mInitialized = false; + } +} + +P256KeypairSSS::~P256KeypairSSS() +{ + Clear(); +} + +bool K32W1PersistentStorageOpKeystore::HasOpKeypairForFabric(FabricIndex fabricIndex) const +{ + VerifyOrReturnError(mStorage != nullptr, 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; + } + + P256SerializedKeypairSSS buf; + + uint16_t keySize = static_cast(buf.Capacity()); + CHIP_ERROR err = + mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), buf.Bytes(), keySize); + + return (err == CHIP_NO_ERROR && (keySize == SSS_KEY_PAIR_BLOB_SIZE)); +} + +CHIP_ERROR K32W1PersistentStorageOpKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex, + MutableByteSpan & outCertificateSigningRequest) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + 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::kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL); + + // Replace previous pending keypair, if any was previously allocated + ResetPendingKey(); + + mPendingKeypair = Platform::New(); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY); + + mPendingKeypair->Initialize(Crypto::ECPKeyTarget::ECDSA); + size_t csrLength = outCertificateSigningRequest.size(); + CHIP_ERROR err = mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength); + if (err != CHIP_NO_ERROR) + { + ResetPendingKey(); + return err; + } + + outCertificateSigningRequest.reduce_size(csrLength); + mPendingFabricIndex = fabricIndex; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR K32W1PersistentStorageOpKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex, + const Crypto::P256PublicKey & nocPublicKey) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + 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 K32W1PersistentStorageOpKeystore::CommitOpKeypairForFabric(FabricIndex fabricIndex) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + 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); + + P256SerializedKeypairSSS tmpKeyBlob; + uint16_t keyBlobLen = tmpKeyBlob.Capacity(); + + mPendingKeypair->ExportBlob(tmpKeyBlob); + ReturnErrorOnFailure( + mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), tmpKeyBlob.Bytes(), keyBlobLen)); + + // If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key. + ResetPendingKey(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR K32W1PersistentStorageOpKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Remove pending state if matching + if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex)) + { + RevertPendingKeypair(); + } + + CHIP_ERROR err = mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName()); + if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + err = CHIP_ERROR_INVALID_FABRIC_INDEX; + } + + return err; +} + +void K32W1PersistentStorageOpKeystore::RevertPendingKeypair() +{ + VerifyOrReturn(mStorage != nullptr); + + // Just reset the pending key, we never stored anything + ResetPendingKey(); +} + +CHIP_ERROR K32W1PersistentStorageOpKeystore::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex)) + { + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL); + // We have an override key: sign with it! + return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature); + } + + P256SerializedKeypairSSS keyBlob; + uint16_t keyBlobLen = keyBlob.Capacity(); + keyBlob.SetLength(keyBlobLen); + + if (fabricIndex != mCachedFabricIndex) + { + error = + mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), keyBlob.Bytes(), keyBlobLen); + keyBlob.SetLength(keyBlobLen); + + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + error = CHIP_ERROR_INVALID_FABRIC_INDEX; + } + ReturnErrorOnFailure(error); + + if (nullptr == mCachedKeypair) + { + mCachedKeypair = Platform::New(); + VerifyOrReturnError(mCachedKeypair != nullptr, CHIP_ERROR_NO_MEMORY); + } + + VerifyOrReturnError(mCachedKeypair->ImportBlob(keyBlob) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + } + + return mCachedKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature); +} + +Crypto::P256Keypair * K32W1PersistentStorageOpKeystore::AllocateEphemeralKeypairForCASE() +{ + // DO NOT CUT AND PASTE without considering the ReleaseEphemeralKeypair(). + // If allocating a derived class, then `ReleaseEphemeralKeypair` MUST + // de-allocate the derived class after up-casting the base class pointer. + return Platform::New(); +} + +void K32W1PersistentStorageOpKeystore::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) +{ + // DO NOT CUT AND PASTE without considering the AllocateEphemeralKeypairForCASE(). + // This must delete the same concrete class as allocated in `AllocateEphemeralKeypairForCASE` + Platform::Delete(keypair); +} + +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/K32W1PersistentStorageOpKeystore.h b/src/platform/nxp/k32w/k32w1/K32W1PersistentStorageOpKeystore.h new file mode 100644 index 00000000000000..6402c235527ff0 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/K32W1PersistentStorageOpKeystore.h @@ -0,0 +1,181 @@ +/* + * 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. + */ + +/** + * @file + * Platform-specific implementation of the persistent operational keystore for K32W1 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "sss_crypto.h" + +namespace chip { + +#define SSS_KEY_PAIR_BLOB_SIZE 120 + +typedef Crypto::SensitiveDataBuffer P256SerializedKeypairSSS; + +class P256KeypairSSS : public Crypto::P256Keypair +{ +public: + P256KeypairSSS() {} + ~P256KeypairSSS() override; + + /** + * @brief Initialize the keypair. + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Initialize(Crypto::ECPKeyTarget key_target) override; + + CHIP_ERROR ExportBlob(P256SerializedKeypairSSS & output) const; + + CHIP_ERROR ImportBlob(P256SerializedKeypairSSS & input); + + /** + * @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, Crypto::P256ECDSASignature & out_signature) const override; + + const Crypto::P256PublicKey & Pubkey() const override { return mPublicKey; } + + /** Release resources associated with this key pair */ + void Clear(); + +private: + Crypto::P256PublicKey mPublicKey; + mutable sss_sscp_object_t mKeyObj; + bool mInitialized = false; +}; + +/** + * @brief OperationalKeystore implementation making use of PersistentStorageDelegate + * to load/store keypairs. This is the legacy behavior of `FabricTable` prior + * to refactors to use `OperationalKeystore` and exists as a baseline example + * of how to use the interface. + * + */ +class K32W1PersistentStorageOpKeystore : public Crypto::OperationalKeystore +{ +public: + K32W1PersistentStorageOpKeystore() = default; + virtual ~K32W1PersistentStorageOpKeystore() { Finish(); } + + // Non-copyable + K32W1PersistentStorageOpKeystore(K32W1PersistentStorageOpKeystore const &) = delete; + void operator=(K32W1PersistentStorageOpKeystore const &) = delete; + + /** + * @brief Initialize the Operational Keystore to map to a given storage delegate. + * + * @param storage Pointer to persistent storage delegate to use. Must outlive this instance. + * @retval CHIP_NO_ERROR on success + * @retval CHIP_ERROR_INCORRECT_STATE if already initialized + */ + CHIP_ERROR Init(PersistentStorageDelegate * storage) + { + VerifyOrReturnError(mStorage == nullptr, CHIP_ERROR_INCORRECT_STATE); + mPendingFabricIndex = kUndefinedFabricIndex; + mIsExternallyOwnedKeypair = false; + mStorage = storage; + mPendingKeypair = nullptr; + mIsPendingKeypairActive = false; + return CHIP_NO_ERROR; + } + + /** + * @brief Finalize the keystore, so that subsequent operations fail + */ + void Finish() + { + VerifyOrReturn(mStorage != nullptr); + + ResetPendingKey(); + mStorage = nullptr; + } + + 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 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, + Crypto::P256ECDSASignature & outSignature) const override; + Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() override; + void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) override; + +protected: + void ResetPendingKey() + { + if (!mIsExternallyOwnedKeypair && (mPendingKeypair != nullptr)) + { + Platform::Delete(mPendingKeypair); + } + if (mCachedKeypair != nullptr) + { + Platform::Delete(mCachedKeypair); + } + mPendingKeypair = nullptr; + mCachedKeypair = nullptr; + mIsExternallyOwnedKeypair = false; + mIsPendingKeypairActive = false; + mPendingFabricIndex = kUndefinedFabricIndex; + mCachedFabricIndex = kUndefinedFabricIndex; + } + + PersistentStorageDelegate * mStorage = nullptr; + + // This pending fabric index is `kUndefinedFabricIndex` if there isn't a pending keypair override for a given fabric. + FabricIndex mPendingFabricIndex = kUndefinedFabricIndex; + P256KeypairSSS * mPendingKeypair = nullptr; + bool mIsPendingKeypairActive = false; + + // Optimize loading the keyblob from storage all the time + mutable P256KeypairSSS * mCachedKeypair = nullptr; + mutable FabricIndex mCachedFabricIndex = kUndefinedFabricIndex; + + // If overridding NewOpKeypairForFabric method in a subclass, set this to true in + // `NewOpKeypairForFabric` if the mPendingKeypair should not be deleted when no longer in use. + bool mIsExternallyOwnedKeypair = false; +}; + +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/KeyValueStoreManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..00f6a9314398bc --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,225 @@ +/* + * + * 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 + * Platform-specific key value storage implementation for K32W + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include +#include + +#include + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +/* TODO: adjust these values */ +constexpr size_t kMaxNumberOfKeys = 150; +constexpr size_t kMaxKeyValueBytes = 255; + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; + +uint16_t GetStringKeyId(const char * key, uint16_t * freeId) +{ + CHIP_ERROR err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + uint8_t keyId = 0; + uint8_t nvmIdKvsKey = chip::DeviceLayer::Internal::K32WConfig::kFileId_KVSKey; + bool bFreeIdxFound = false; + char keyString[kMaxKeyValueBytes] = { 0 }; + size_t keyStringSize = 0; + uint16_t nvmInternalId; + + for (keyId = 0; keyId < kMaxNumberOfKeys; keyId++) + { + nvmInternalId = chip::DeviceLayer::Internal::K32WConfigKey(nvmIdKvsKey, keyId); + err = + chip::DeviceLayer::Internal::K32WConfig::ReadConfigValueStr(nvmInternalId, keyString, kMaxKeyValueBytes, keyStringSize); + + if (err == CHIP_NO_ERROR) + { + if (strcmp(key, keyString) == 0) + { + // found the entry we are looking for + break; + } + } + else if ((NULL != freeId) && (false == bFreeIdxFound)) + { + bFreeIdxFound = true; + *freeId = keyId; + } + } + return keyId; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, + size_t offset_bytes) +{ + CHIP_ERROR err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + uint8_t nvmIdKvsValue = chip::DeviceLayer::Internal::K32WConfig::kFileId_KVSValue; + size_t read_bytes = 0; + uint8_t keyId = 0; + uint16_t nvmInternalId = 0; + + VerifyOrExit((key != NULL) && (value != NULL), err = CHIP_ERROR_INVALID_ARGUMENT); + + keyId = GetStringKeyId(key, NULL); + + if (keyId < kMaxNumberOfKeys) + { + // This is the ID of the actual data + nvmInternalId = chip::DeviceLayer::Internal::K32WConfigKey(nvmIdKvsValue, keyId); + ChipLogProgress(DeviceLayer, "KVS, get the value of Matter key [%s] with NVM id: %i", key, nvmInternalId); + err = chip::DeviceLayer::Internal::K32WConfig::ReadConfigValueBin(nvmInternalId, (uint8_t *) value, value_size, read_bytes); + + // According to Get api read_bytes_size can be null + if (read_bytes_size) + { + *read_bytes_size = read_bytes; + } + } + else + { + ChipLogProgress(DeviceLayer, "KVS, error in getting the value of Matter key [%s]. Key not found in persistent storage.", + key); + } + +exit: + ConvertError(err); + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size) +{ + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + bool_t putKey = false; + uint8_t nvmIdKvsKey = chip::DeviceLayer::Internal::K32WConfig::kFileId_KVSKey; + uint8_t nvmIdKvsValue = chip::DeviceLayer::Internal::K32WConfig::kFileId_KVSValue; + uint16_t nvmInternalId = 0; + uint16_t freeKeyId; + uint8_t keyId; + + VerifyOrExit((key != NULL) && (value != NULL), err = CHIP_ERROR_INVALID_ARGUMENT); + + keyId = GetStringKeyId(key, &freeKeyId); + + // Key does not exist. Write both key and value in persistent storage. + if (kMaxNumberOfKeys == keyId) + { + putKey = true; + keyId = freeKeyId; + } + + nvmInternalId = chip::DeviceLayer::Internal::K32WConfigKey(nvmIdKvsValue, keyId); + ChipLogProgress(DeviceLayer, "KVS, save in flash the value of the Matter key [%s] with NVM id: %i", key, nvmInternalId); + + err = chip::DeviceLayer::Internal::K32WConfig::WriteConfigValueBin(nvmInternalId, (uint8_t *) value, value_size); + + /* save the 'key' in flash such that it can be retrieved later on */ + if (err == CHIP_NO_ERROR) + { + if (true == putKey) + { + nvmInternalId = chip::DeviceLayer::Internal::K32WConfigKey(nvmIdKvsKey, keyId); + ChipLogProgress(DeviceLayer, "KVS, save in flash the Matter key [%s] with NVM id: %i", key, nvmInternalId); + + err = chip::DeviceLayer::Internal::K32WConfig::WriteConfigValueStr(nvmInternalId, key, strlen(key) + 1); + + if (err != CHIP_NO_ERROR) + { + ChipLogProgress(DeviceLayer, "KVS, Error while saving in flash the Matter key [%s] with NVM id: %i", key, + nvmInternalId); + } + } + } + else + { + ChipLogProgress(DeviceLayer, "KVS, Error while saving in flash the value of the Matter key [%s] with NVM id: %i", key, + nvmInternalId); + } + +exit: + ConvertError(err); + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) +{ + CHIP_ERROR err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + uint8_t nvmIdKvsKey = chip::DeviceLayer::Internal::K32WConfig::kFileId_KVSKey; + uint8_t nvmIdKvsValue = chip::DeviceLayer::Internal::K32WConfig::kFileId_KVSValue; + uint8_t keyId = 0; + uint16_t nvmInternalId = 0; + + VerifyOrExit((key != NULL), err = CHIP_ERROR_INVALID_ARGUMENT); + + keyId = GetStringKeyId(key, NULL); + + if (keyId < kMaxNumberOfKeys) + { + // entry exists so we can remove it + nvmInternalId = chip::DeviceLayer::Internal::K32WConfigKey(nvmIdKvsKey, keyId); + + ChipLogProgress(DeviceLayer, "KVS, delete from flash the Matter key [%s] with NVM id: %i", key, nvmInternalId); + err = chip::DeviceLayer::Internal::K32WConfig::ClearConfigValue(nvmInternalId); + + /* also delete the 'key string' from flash */ + if (err == CHIP_NO_ERROR) + { + nvmInternalId = chip::DeviceLayer::Internal::K32WConfigKey(nvmIdKvsValue, keyId); + ChipLogProgress(DeviceLayer, "KVS, delete from flash the value of the Matter key [%s] with NVM id: %i", key, + nvmInternalId); + + err = chip::DeviceLayer::Internal::K32WConfig::ClearConfigValue(nvmInternalId); + + if (err != CHIP_NO_ERROR) + { + ChipLogProgress(DeviceLayer, + "KVS, Error while deleting from flash the value of the Matter key [%s] with NVM id: %i", key, + nvmInternalId); + } + } + else + { + ChipLogProgress(DeviceLayer, "KVS, Error while deleting from flash the Matter key [%s] with NVM id: %i", key, + nvmInternalId); + } + } +exit: + ConvertError(err); + return err; +} + +void KeyValueStoreManagerImpl::ConvertError(CHIP_ERROR & err) +{ + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/KeyValueStoreManagerImpl.h b/src/platform/nxp/k32w/k32w1/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..df942779fe4bc2 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/KeyValueStoreManagerImpl.h @@ -0,0 +1,83 @@ + +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for K32W + */ + +#pragma once + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +class KeyValueStoreManagerImpl final : public KeyValueStoreManager +{ + // Allow the KeyValueStoreManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class KeyValueStoreManager; + +public: + // NOTE: Currently this platform does not support partial and offset reads + // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, size_t offset); + + CHIP_ERROR _Delete(const char * key); + + CHIP_ERROR _Put(const char * key, const void * value, size_t value_size); + +private: + // ===== Members for internal use by the following friends. + friend KeyValueStoreManager & KeyValueStoreMgr(); + friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + + // Reading config values uses the K32WConfig API, which returns CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND + // error if a key was not found. Convert this error to the correct error KeyValueStoreManagerImpl + // should return: CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND + void ConvertError(CHIP_ERROR & err); + + static KeyValueStoreManagerImpl sInstance; +}; + +/** + * Returns the public interface of the KeyValueStoreManager singleton object. + * + * Chip applications should use this to access features of the KeyValueStoreManager object + * that are common to all platforms. + */ +inline KeyValueStoreManager & KeyValueStoreMgr(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the KeyValueStoreManager singleton object. + * + * Chip applications can use this to gain access to features of the KeyValueStoreManager + * that are specific to the K32W platform. + */ +inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/Logging.cpp b/src/platform/nxp/k32w/k32w1/Logging.cpp new file mode 100644 index 00000000000000..62b5d114379f3a --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/Logging.cpp @@ -0,0 +1,198 @@ +/* See Project CHIP LICENSE file for licensing information. */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "fsl_debug_console.h" +#include + +#define K32W_LOG_MODULE_NAME chip +#define EOL_CHARS "\r\n" /* End of Line Characters */ +#define EOL_CHARS_LEN 2 /* Length of EOL */ + +/* maximum value for uint32_t is 4294967295 - 10 bytes + 2 bytes for the brackets */ +static constexpr uint8_t timestamp_max_len_bytes = 12; + +/* one byte for the category + 2 bytes for the brackets */ +static constexpr uint8_t category_max_len_bytes = 3; + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#include +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD + +static bool isLogInitialized; +extern "C" uint32_t otPlatAlarmMilliGetNow(void); +extern "C" void otPlatUartSendBlocking(const uint8_t * aBuf, uint32_t len); + +namespace chip { +namespace Logging { +namespace Platform { + +void GetMessageString(char * buf, uint8_t bufLen, const char * module, uint8_t category) +{ + int writtenLen = 0; + const char * categoryString; + + /* bufLen must accommodate the length of the timestamp + length of the category + + * length of the module + 2 bytes for the module's brackets + + * 1 byte for the terminating character. + */ + assert(bufLen >= (timestamp_max_len_bytes + category_max_len_bytes + (strlen(module) + 2) + 1)); + + writtenLen = snprintf(buf, bufLen, "[%ld]", otPlatAlarmMilliGetNow()); + bufLen -= writtenLen; + buf += writtenLen; + + if (category != kLogCategory_None) + { + switch (category) + { + case kLogCategory_Error: + categoryString = "E"; + break; + case kLogCategory_Progress: + categoryString = "P"; + break; + case kLogCategory_Detail: + categoryString = "D"; + break; + default: + categoryString = "U"; + } + + writtenLen = snprintf(buf, bufLen, "[%s]", categoryString); + bufLen -= writtenLen; + buf += writtenLen; + } + + writtenLen = snprintf(buf, bufLen, "[%s]", module); +} + +} // namespace Platform +} // namespace Logging +} // namespace chip + +void FillPrefix(char * buf, uint8_t bufLen, const char * module, uint8_t category) +{ + chip::Logging::Platform::GetMessageString(buf, bufLen, module, category); +} + +namespace chip { +namespace DeviceLayer { + +/** + * Called whenever a log message is emitted by CHIP or LwIP. + * + * This function is intended be overridden by the application to, e.g., + * schedule output of queued log entries. + */ +void __attribute__((weak)) OnLogOutput(void) {} + +} // namespace DeviceLayer +} // namespace chip + +void ENFORCE_FORMAT(1, 0) GenericLog(const char * format, va_list arg, const char * module, uint8_t category) +{ + +#if K32W_LOG_ENABLED + + char formattedMsg[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE - 1] = { 0 }; + size_t prefixLen, writtenLen; + + if (!isLogInitialized) + { + isLogInitialized = true; + otPlatUartEnable(); + } + + /* Prefix is composed of [Time Reference][Debug String][Module Name String] */ + FillPrefix(formattedMsg, CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE - 1, module, category); + prefixLen = strlen(formattedMsg); + + // Append the log message. + writtenLen = vsnprintf(formattedMsg + prefixLen, CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE - prefixLen - EOL_CHARS_LEN, format, arg); + VerifyOrDie(writtenLen > 0); + memcpy(formattedMsg + prefixLen + writtenLen, EOL_CHARS, EOL_CHARS_LEN); + + otPlatUartSendBlocking((const uint8_t *) formattedMsg, strlen(formattedMsg)); + + // Let the application know that a log message has been emitted. + chip::DeviceLayer::OnLogOutput(); + +#endif // K32W_LOG_ENABLED +} + +namespace chip { +namespace Logging { +namespace Platform { + +/** + * CHIP log output function. + */ +void ENFORCE_FORMAT(3, 0) LogV(const char * module, uint8_t category, const char * msg, va_list v) +{ + (void) module; + (void) category; + +#if K32W_LOG_ENABLED + GenericLog(msg, v, module, category); + // Let the application know that a log message has been emitted. + DeviceLayer::OnLogOutput(); + +#endif // K32W_LOG_ENABLED +} + +} // namespace Platform +} // namespace Logging +} // namespace chip + +#undef K32W_LOG_MODULE_NAME +#define K32W_LOG_MODULE_NAME lwip + +#if CHIP_SYSTEM_CONFIG_USE_LWIP +/** + * LwIP log output function. + */ +extern "C" void ENFORCE_FORMAT(1, 2) LwIPLog(const char * msg, ...) +{ + +#if K32W_LOG_ENABLED + va_list v; + const char * module = "LWIP"; + + va_start(v, msg); + GenericLog(msg, v, module, chip::Logging::kLogCategory_None); + va_end(v); +#endif +} +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + +#undef K32W_LOG_MODULE_NAME +#define K32W_LOG_MODULE_NAME thread + +extern "C" void ENFORCE_FORMAT(3, 4) otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char * aFormat, ...) +{ + +#if K32W_LOG_ENABLED + va_list v; + const char * module = "OT"; + + (void) aLogLevel; + (void) aLogRegion; + + va_start(v, aFormat); + GenericLog(aFormat, v, module, chip::Logging::kLogCategory_None); + va_end(v); +#endif +} + +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD diff --git a/src/platform/nxp/k32w/k32w1/LowPowerHooks.cpp b/src/platform/nxp/k32w/k32w1/LowPowerHooks.cpp new file mode 100644 index 00000000000000..752344e5e42cae --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/LowPowerHooks.cpp @@ -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. + */ + +/** + * @file + * Provides a glue layer between Matter and NXP-SDK Low Power + */ + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + +#include +#include + +extern "C" void PWR_DisallowDeviceToSleep(void); +extern "C" void PWR_AllowDeviceToSleep(void); + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +extern "C" void App_AllowDeviceToSleep() +{ + PWR_AllowDeviceToSleep(); +} + +extern "C" void App_DisallowDeviceToSleep() +{ + PWR_DisallowDeviceToSleep(); +} + +#endif diff --git a/src/platform/nxp/k32w/k32w1/OTAFirmwareProcessor.cpp b/src/platform/nxp/k32w/k32w1/OTAFirmwareProcessor.cpp new file mode 100644 index 00000000000000..528261b12b5e59 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/OTAFirmwareProcessor.cpp @@ -0,0 +1,126 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "OtaSupport.h" + +namespace chip { + +CHIP_ERROR OTAFirmwareProcessor::Init() +{ + ReturnErrorCodeIf(mCallbackProcessDescriptor == nullptr, CHIP_OTA_PROCESSOR_CB_NOT_REGISTERED); + mAccumulator.Init(sizeof(Descriptor)); + + ReturnErrorCodeIf(gOtaSuccess_c != OTA_SelectExternalStoragePartition(), CHIP_OTA_PROCESSOR_EXTERNAL_STORAGE); + + otaResult_t ota_status; + ota_status = OTA_ServiceInit(&mPostedOperationsStorage[0], NB_PENDING_TRANSACTIONS * TRANSACTION_SZ); + + ReturnErrorCodeIf(ota_status != gOtaSuccess_c, CHIP_OTA_PROCESSOR_CLIENT_INIT); + ReturnErrorCodeIf(gOtaSuccess_c != OTA_StartImage(mLength - sizeof(Descriptor)), CHIP_OTA_PROCESSOR_START_IMAGE); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::Clear() +{ + OTATlvProcessor::ClearInternal(); + mAccumulator.Clear(); + mDescriptorProcessed = false; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block) +{ + otaResult_t status; + static uint32_t ulEraseLen = 0; + static uint32_t ulCrtAddr = 0; + + if (!mDescriptorProcessed) + { + ReturnErrorOnFailure(ProcessDescriptor(block)); + } + + ulCrtAddr += block.size(); + + if (ulCrtAddr >= ulEraseLen) + { + ulEraseLen += 0x1000; // flash sector size + + status = OTA_MakeHeadRoomForNextBlock(block.size(), OTAImageProcessorImpl::FetchNextData, 0); + if (gOtaSuccess_c != status) + { + ChipLogError(SoftwareUpdate, "Failed to make room for next block. Status: %d", status); + return CHIP_OTA_PROCESSOR_MAKE_ROOM; + } + } + else + { + OTAImageProcessorImpl::FetchNextData(0); + } + + status = OTA_PushImageChunk((uint8_t *) block.data(), (uint16_t) block.size(), NULL, NULL); + if (gOtaSuccess_c != status) + { + ChipLogError(SoftwareUpdate, "Failed to write image block. Status: %d", status); + return CHIP_OTA_PROCESSOR_PUSH_CHUNK; + } + + return CHIP_OTA_FETCH_ALREADY_SCHEDULED; +} + +CHIP_ERROR OTAFirmwareProcessor::ProcessDescriptor(ByteSpan & block) +{ + ReturnErrorOnFailure(mAccumulator.Accumulate(block)); + ReturnErrorOnFailure(mCallbackProcessDescriptor(static_cast(mAccumulator.data()))); + + mDescriptorProcessed = true; + mAccumulator.Clear(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::ApplyAction() +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::AbortAction() +{ + OTA_CancelImage(); + Clear(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFirmwareProcessor::ExitAction() +{ + if (OTA_CommitImage(NULL) != gOtaSuccess_c) + { + ChipLogError(SoftwareUpdate, "Failed to commit firmware image."); + return CHIP_OTA_PROCESSOR_IMG_COMMIT; + } + + return CHIP_NO_ERROR; +} + +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/OTAFirmwareProcessor.h b/src/platform/nxp/k32w/k32w1/OTAFirmwareProcessor.h new file mode 100644 index 00000000000000..c06a2342ba08d6 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/OTAFirmwareProcessor.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "OtaPrivate.h" +#include +#include + +/* Posted Operations Size Info */ +#define NB_PENDING_TRANSACTIONS 12 +#define TRANSACTION_SZ (sizeof(FLASH_TransactionOpNode_t)) + +namespace chip { + +class OTAFirmwareProcessor : public OTATlvProcessor +{ +public: + struct Descriptor + { + uint32_t version; + char versionString[kVersionStringSize]; + char buildDate[kBuildDateSize]; + }; + + CHIP_ERROR Init() override; + CHIP_ERROR Clear() override; + CHIP_ERROR ApplyAction() override; + CHIP_ERROR AbortAction() override; + CHIP_ERROR ExitAction() override; + +private: + CHIP_ERROR ProcessInternal(ByteSpan & block) override; + CHIP_ERROR ProcessDescriptor(ByteSpan & block); + + OTADataAccumulator mAccumulator; + bool mDescriptorProcessed = false; + + alignas(4) uint8_t mPostedOperationsStorage[NB_PENDING_TRANSACTIONS * TRANSACTION_SZ]; +}; + +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/OTAHooks.cpp b/src/platform/nxp/k32w/k32w1/OTAHooks.cpp new file mode 100644 index 00000000000000..b672ed8322177d --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/OTAHooks.cpp @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include + +#include "OtaSupport.h" + +#ifndef CONFIG_CHIP_K32W1_MAX_ENTRIES_TEST +#define CONFIG_CHIP_K32W1_MAX_ENTRIES_TEST 0 +#endif + +#ifndef CONFIG_CHIP_K32W1_OTA_ABORT_HOOK +#define CONFIG_CHIP_K32W1_OTA_ABORT_HOOK 0 +#endif + +#define APPLICATION_PROCESSOR_TAG 1 + +extern "C" void HAL_ResetMCU(void); + +#define ResetMCU HAL_ResetMCU + +#if USE_SMU2_AS_SYSTEM_MEMORY +// The attribute specifier should not be changed. +static chip::OTAFirmwareProcessor gApplicationProcessor __attribute__((section(".smu2"))); +#else +static chip::OTAFirmwareProcessor gApplicationProcessor; +#endif + +CHIP_ERROR ProcessDescriptor(void * descriptor) +{ + auto desc = static_cast(descriptor); + ChipLogDetail(SoftwareUpdate, "Descriptor: %ld, %s, %s", desc->version, desc->versionString, desc->buildDate); + + return CHIP_NO_ERROR; +} + +extern "C" WEAK CHIP_ERROR OtaHookInit() +{ +#if CONFIG_CHIP_K32W1_MAX_ENTRIES_TEST + static chip::OTAFirmwareProcessor processors[8]; +#endif + + gApplicationProcessor.RegisterDescriptorCallback(ProcessDescriptor); + + auto & imageProcessor = chip::OTAImageProcessorImpl::GetDefaultInstance(); + ReturnErrorOnFailure(imageProcessor.RegisterProcessor(APPLICATION_PROCESSOR_TAG, &gApplicationProcessor)); + +#if CONFIG_CHIP_K32W1_MAX_ENTRIES_TEST + for (auto i = 0; i < 8; i++) + { + processors[i].RegisterDescriptorCallback(ProcessDescriptor); + ReturnErrorOnFailure(imageProcessor.RegisterProcessor(i + 4, &processors[i])); + } +#endif // CONFIG_CHIP_K32W1_MAX_ENTRIES_TEST + + return CHIP_NO_ERROR; +} + +extern "C" WEAK void OtaHookReset() +{ + // Process all idle saves + NvShutdown(); + // Set the bootloader flags + OTA_SetNewImageFlag(); + ResetMCU(); +} + +extern "C" WEAK void OtaHookAbort() +{ + /* + Disclaimer: This is not default behavior and it was not checked against + Matter specification compliance. You should use this at your own discretion. + + Use CONFIG_CHIP_K32W1_OTA_ABORT_HOOK to enable/disable this feature (disabled by default). + This hook is called inside OTAImageProcessorImpl::HandleAbort to schedule a retry (when enabled). + */ +#if CONFIG_CHIP_K32W1_OTA_ABORT_HOOK + auto & imageProcessor = chip::OTAImageProcessorImpl::GetDefaultInstance(); + auto & providerLocation = imageProcessor.GetBackupProvider(); + + if (providerLocation.HasValue()) + { + auto * requestor = chip::GetRequestorInstance(); + requestor->SetCurrentProviderLocation(providerLocation.Value()); + if (requestor->GetCurrentUpdateState() == chip::OTARequestorInterface::OTAUpdateStateEnum::kIdle) + { + chip::DeviceLayer::SystemLayer().ScheduleLambda([requestor] { requestor->TriggerImmediateQueryInternal(); }); + } + else + { + ChipLogError(SoftwareUpdate, "OTA requestor not in kIdle"); + } + } + else + { + ChipLogError(SoftwareUpdate, "Backup provider info not available"); + } +#endif +} diff --git a/src/platform/nxp/k32w/k32w1/PlatformManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/PlatformManagerImpl.cpp new file mode 100644 index 00000000000000..53e68779bcecd2 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/PlatformManagerImpl.cpp @@ -0,0 +1,140 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation of the PlatformManager object + * for K32W platforms using the NXP K32W SDK. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include +#include + +#if CHIP_SYSTEM_CONFIG_USE_LWIP +#include +#endif + +#include "fsl_component_mem_manager.h" +#include "fwk_platform.h" +#include + +extern uint8_t __data_end__[], m_data0_end[]; +memAreaCfg_t data0Heap = { .start_address = (void *) __data_end__, .end_address = (void *) m_data0_end }; + +#if defined(gAppHighSystemClockFrequency_d) && (gAppHighSystemClockFrequency_d > 0) && defined(USE_SMU2_AS_SYSTEM_MEMORY) +extern "C" void APP_SysInitHook(void) +{ + // NBU has to be initialized before calling this function + PLATFORM_SetNbuConstraintFrequency(PLATFORM_NBU_MIN_FREQ_64MHZ); + // Disable low-power on NBU + PLATFORM_DisableControllerLowPower(); +} +#endif + +namespace chip { +namespace DeviceLayer { + +PlatformManagerImpl PlatformManagerImpl::sInstance; + +CHIP_ERROR PlatformManagerImpl::InitBoardFwk(void) +{ + mem_status_t memSt = kStatus_MemSuccess; + + SecLib_Init(); + + memSt = MEM_RegisterExtendedArea(&data0Heap, NULL, 0U); + VerifyOrReturnError(memSt == kStatus_MemSuccess, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +static int app_entropy_source(void * data, unsigned char * output, size_t len, size_t * olen) +{ + otError otErr = otPlatEntropyGet(output, (uint16_t) len); + + if (otErr != OT_ERROR_NONE) + { + return -1; + } + + *olen = len; + return 0; +} + +CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Initialize the configuration system. + err = Internal::K32WConfig::Init(); + SuccessOrExit(err); + + SetConfigurationMgr(&ConfigurationManagerImpl::GetDefaultInstance()); + + mStartTime = System::SystemClock().GetMonotonicTimestamp(); + +#if CHIP_SYSTEM_CONFIG_USE_LWIP + // Initialize LwIP. + tcpip_init(NULL, NULL); +#endif + + err = chip::Crypto::add_entropy_source(app_entropy_source, NULL, 16); + SuccessOrExit(err); + + // 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(); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/PlatformManagerImpl.h b/src/platform/nxp/k32w/k32w1/PlatformManagerImpl.h new file mode 100644 index 00000000000000..70ece1cdf11f3c --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/PlatformManagerImpl.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation of the PlatformManager object + * for K32W platforms using the NXP SDK. + */ + +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the PlatformManager singleton object for the K32W platform. + */ +class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_FreeRTOS +{ + // Allow the PlatformManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend PlatformManager; + + // Allow the generic implementation base class to call helper methods on + // this class. +#ifndef DOXYGEN_SHOULD_SKIP_THIS + friend Internal::GenericPlatformManagerImpl_FreeRTOS; +#endif + +public: + // ===== Platform-specific members that may be accessed directly by the application. + + System::Clock::Timestamp GetStartTime() { return mStartTime; } + CHIP_ERROR InitBoardFwk(void); + +private: + // ===== Methods that implement the PlatformManager abstract interface. + + CHIP_ERROR _InitChipStack(void); + void _Shutdown(); + + // ===== Members for internal use by the following friends. + + friend PlatformManager & PlatformMgr(void); + friend PlatformManagerImpl & PlatformMgrImpl(void); + friend class Internal::BLEManagerImpl; + + System::Clock::Timestamp mStartTime = System::Clock::kZero; + + static PlatformManagerImpl sInstance; + + using Internal::GenericPlatformManagerImpl_FreeRTOS::PostEventFromISR; +}; + +/** + * Returns the public interface of the PlatformManager singleton object. + * + * chip applications should use this to access features of the PlatformManager object + * that are common to all platforms. + */ +inline PlatformManager & PlatformMgr(void) +{ + return PlatformManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the PlatformManager singleton object. + * + * chip applications can use this to gain access to features of the PlatformManager + * that are specific to the K32W platform. + */ +inline PlatformManagerImpl & PlatformMgrImpl(void) +{ + return PlatformManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/SoftwareUpdateManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/SoftwareUpdateManagerImpl.cpp new file mode 100644 index 00000000000000..c464bb327c24a6 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/SoftwareUpdateManagerImpl.cpp @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ +/* this file behaves like a config.h, comes first */ +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_UPDATE_MANAGER + +#include +#include + +#include +#include + +namespace chip { +namespace DeviceLayer { + +SoftwareUpdateManagerImpl SoftwareUpdateManagerImpl::sInstance; + +CHIP_ERROR SoftwareUpdateManagerImpl::_Init(void) +{ + Internal::GenericSoftwareUpdateManagerImpl_BDX::DoInit(); + Internal::GenericSoftwareUpdateManagerImpl::DoInit(); + + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_UPDATE_MANAGER diff --git a/src/platform/nxp/k32w/k32w1/SoftwareUpdateManagerImpl.h b/src/platform/nxp/k32w/k32w1/SoftwareUpdateManagerImpl.h new file mode 100644 index 00000000000000..f04025435928d5 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/SoftwareUpdateManagerImpl.h @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + +#if CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_UPDATE_MANAGER + +#include +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the SoftwareUpdateManager singleton object for the + * NXP K32W platforms. + */ +class SoftwareUpdateManagerImpl final : public SoftwareUpdateManager, + public Internal::GenericSoftwareUpdateManagerImpl, + public Internal::GenericSoftwareUpdateManagerImpl_BDX +{ + // Allow the SoftwareUpdateManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class SoftwareUpdateManager; + + // Allow the GenericSoftwareUpdateManagerImpl base class to access helper methods + // and types defined on this class. + friend class Internal::GenericSoftwareUpdateManagerImpl; + + // Allow the GenericSoftwareUpdateManagerImpl_BDX base class to access helper methods + // and types defined on this class. + friend class Internal::GenericSoftwareUpdateManagerImpl_BDX; + +public: + // ===== Members for internal use by the following friends. + + friend ::chip::DeviceLayer::SoftwareUpdateManager & SoftwareUpdateMgr(void); + friend SoftwareUpdateManagerImpl & SoftwareUpdateMgrImpl(void); + + static SoftwareUpdateManagerImpl sInstance; + +private: + // ===== Members that implement the SoftwareUpdateManager abstract interface. + + CHIP_ERROR _Init(void); +}; + +/** + * Returns a reference to the public interface of the SoftwareUpdateManager singleton object. + * + * Internal components should use this to access features of the SoftwareUpdateManager object + * that are common to all platforms. + */ +inline SoftwareUpdateManager & SoftwareUpdateMgr(void) +{ + return SoftwareUpdateManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the SoftwareUpdateManager singleton object. + * + * Internal components can use this to gain access to features of the SoftwareUpdateManager + * that are specific to the K32W platform. + */ +inline SoftwareUpdateManagerImpl & SoftwareUpdateMgrImpl(void) +{ + return SoftwareUpdateManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_UPDATE_MANAGER diff --git a/src/platform/nxp/k32w/k32w1/SystemPlatformConfig.h b/src/platform/nxp/k32w/k32w1/SystemPlatformConfig.h new file mode 100644 index 00000000000000..bda39157039697 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/SystemPlatformConfig.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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 + * Platform-specific configuration overrides for the CHIP System + * Layer on NXP K32W Platforms. + * + */ + +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { +struct ChipDeviceEvent; +} // namespace DeviceLayer +} // namespace chip + +// ==================== Platform Adaptations ==================== +#define CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME 1 +#define CHIP_SYSTEM_CONFIG_EVENT_OBJECT_TYPE const struct ::chip::DeviceLayer::ChipDeviceEvent * +#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE 0 + +// ========== Platform-specific Configuration Overrides ========= diff --git a/src/platform/nxp/k32w/k32w1/SystemTimeSupport.cpp b/src/platform/nxp/k32w/k32w1/SystemTimeSupport.cpp new file mode 100644 index 00000000000000..a61c5d648bc039 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/SystemTimeSupport.cpp @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2020-2023 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. + */ + +/** + * @file + * Provides implementations of the CHIP System Layer platform + * time/clock functions that are suitable for use on the K32W1 platform. + */ +/* this file behaves like a config.h, comes first */ +#include + +extern "C" uint32_t otPlatAlarmMicroGetNow(void); + +namespace chip { +namespace System { +namespace Clock { + +namespace Internal { +ClockImpl gClockImpl; +} // namespace Internal + +namespace { + +uint64_t sBootTimeUS = 0; + +} // unnamed namespace + +Microseconds64 ClockImpl::GetMonotonicMicroseconds64(void) +{ + return Clock::Microseconds64(otPlatAlarmMicroGetNow()); +} + +Milliseconds64 ClockImpl::GetMonotonicMilliseconds64(void) +{ + return std::chrono::duration_cast(GetMonotonicMicroseconds64()); +} + +uint64_t GetClock_Monotonic(void) +{ + return otPlatAlarmMicroGetNow(); +} + +uint64_t GetClock_MonotonicMS(void) +{ + return (otPlatAlarmMicroGetNow() / 1000); +} + +uint64_t GetClock_MonotonicHiRes(void) +{ + return GetClock_Monotonic(); +} + +CHIP_ERROR ClockImpl::GetClock_RealTime(Clock::Microseconds64 & aCurTime) +{ + // TODO(19081): This platform does not properly error out if wall clock has + // not been set. For now, short circuit this. + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#if 0 + if (sBootTimeUS == 0) + { + return CHIP_ERROR_REAL_TIME_NOT_SYNCED; + } + aCurTime = Clock::Microseconds64(sBootTimeUS + GetClock_Monotonic()); + return CHIP_NO_ERROR; +#endif +} + +CHIP_ERROR ClockImpl::GetClock_RealTimeMS(Clock::Milliseconds64 & aCurTime) +{ + if (sBootTimeUS == 0) + { + return CHIP_ERROR_REAL_TIME_NOT_SYNCED; + } + aCurTime = Clock::Milliseconds64((sBootTimeUS + GetClock_Monotonic()) / 1000); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ClockImpl::SetClock_RealTime(Clock::Microseconds64 aNewCurTime) +{ + uint64_t timeSinceBootUS = GetClock_Monotonic(); + if (aNewCurTime.count() > timeSinceBootUS) + { + sBootTimeUS = aNewCurTime.count() - timeSinceBootUS; + } + else + { + sBootTimeUS = 0; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR InitClock_RealTime() +{ + Clock::Microseconds64 curTime = + Clock::Microseconds64((static_cast(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD) * UINT64_C(1000000))); + // Use CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD as the initial value of RealTime. + // Then the RealTime obtained from GetClock_RealTime will be always valid. + // + // TODO(19081): This is broken because it causes the platform to report + // that it does have wall clock time when it actually doesn't. + return System::SystemClock().SetClock_RealTime(curTime); +} + +} // namespace Clock +} // namespace System +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/ThreadStackManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/ThreadStackManagerImpl.cpp new file mode 100644 index 00000000000000..7bf96771fb78d7 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ThreadStackManagerImpl.cpp @@ -0,0 +1,127 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation of the ThreadStackManager object for + * K32W platforms using the NXP SDK and the OpenThread + * stack. + * + */ + +/* this file behaves like a config.h, comes first */ +#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; +} + +void ThreadStackManagerImpl::ProcessThreadActivity() +{ + /* reuse thread task for ble processing. + * by doing this, we avoid allocating a new stack for short-lived + * BLE processing (e.g.: only during Matter commissioning) + */ + auto * bleManager = &chip::DeviceLayer::Internal::BLEMgrImpl(); + bleManager->DoBleProcessing(); + + otTaskletsProcess(OTInstance()); + otSysProcessDrivers(OTInstance()); +} + +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(); +} + +extern "C" void * pvPortCallocRtos(size_t num, size_t size) +{ + size_t totalAllocSize = (size_t) (num * size); + + if (size && totalAllocSize / size != num) + return nullptr; + + void * p = pvPortMalloc(totalAllocSize); + + if (p) + { + memset(p, 0, totalAllocSize); + } + + return p; +} + +extern "C" void * otPlatCAlloc(size_t aNum, size_t aSize) +{ + return CHIPPlatformMemoryCalloc(aNum, aSize); +} + +extern "C" void otPlatFree(void * aPtr) +{ + return CHIPPlatformMemoryFree(aPtr); +} + +extern "C" void * otPlatRealloc(void * p, size_t aSize) +{ + return CHIPPlatformMemoryRealloc(p, aSize); +} diff --git a/src/platform/nxp/k32w/k32w1/ThreadStackManagerImpl.h b/src/platform/nxp/k32w/k32w1/ThreadStackManagerImpl.h new file mode 100644 index 00000000000000..5f7adcefec6cb1 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ThreadStackManagerImpl.h @@ -0,0 +1,121 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation of the ThreadStackManager object + * for K32W platforms using the NXP SDK and the OpenThread stack. + */ + +#pragma once + +#include +#include +#include +#include + +extern "C" void otSysEventSignalPending(void); + +namespace chip { +namespace DeviceLayer { + +class ThreadStackManager; +class ThreadStackManagerImpl; +namespace Internal { +extern int GetEntropy_K32W(uint8_t * buf, size_t bufSize); +} + +/** + * Concrete implementation of the ThreadStackManager singleton object for K32W platforms + * using the NXP SDK and the OpenThread stack. + */ +class ThreadStackManagerImpl final : public ThreadStackManager, + public Internal::GenericThreadStackManagerImpl_OpenThread, + public Internal::GenericThreadStackManagerImpl_FreeRTOS +{ + // Allow the ThreadStackManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class ThreadStackManager; + + // Allow the generic implementation base classes to call helper methods on + // this class. +#ifndef DOXYGEN_SHOULD_SKIP_THIS + friend Internal::GenericThreadStackManagerImpl_OpenThread; + friend Internal::GenericThreadStackManagerImpl_OpenThread; + friend Internal::GenericThreadStackManagerImpl_FreeRTOS; +#endif + + // Allow glue functions called by OpenThread to call helper methods on this + // class. + friend void ::otTaskletsSignalPending(otInstance * otInst); + friend void ::otSysEventSignalPending(void); + +public: + // ===== Platform-specific members that may be accessed directly by the application. + + using ThreadStackManager::InitThreadStack; + CHIP_ERROR InitThreadStack(otInstance * otInst); + + using ThreadStackManager::ProcessThreadActivity; + void ProcessThreadActivity(); + +private: + // ===== Methods that implement the ThreadStackManager abstract interface. + + CHIP_ERROR _InitThreadStack(void); + + // ===== Members for internal use by the following friends. + + friend ThreadStackManager & ::chip::DeviceLayer::ThreadStackMgr(void); + friend ThreadStackManagerImpl & ::chip::DeviceLayer::ThreadStackMgrImpl(void); + friend int Internal::GetEntropy_K32W(uint8_t * buf, size_t bufSize); + + static ThreadStackManagerImpl sInstance; + + static bool IsInitialized(); + + // ===== Private members for use by this class only. + + ThreadStackManagerImpl() = default; +}; + +/** + * Returns the public interface of the ThreadStackManager singleton object. + * + * chip applications should use this to access features of the ThreadStackManager object + * that are common to all platforms. + */ +inline ThreadStackManager & ThreadStackMgr(void) +{ + return ThreadStackManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the ThreadStackManager singleton object. + * + * chip applications can use this to gain access to features of the ThreadStackManager + * that are specific to K32W platforms. + */ +inline ThreadStackManagerImpl & ThreadStackMgrImpl(void) +{ + return ThreadStackManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/args.gni b/src/platform/nxp/k32w/k32w1/args.gni new file mode 100644 index 00000000000000..4170e95ea6f632 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/args.gni @@ -0,0 +1,50 @@ +# 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/k32w1_sdk.gni") +import("//build_overrides/openthread.gni") + +declare_args() { + chip_with_ot_cli = 0 + chip_with_low_power = 0 + sdk_release = 1 +} + +chip_device_platform = "k32w1" + +lwip_platform = "k32w1" + +chip_inet_config_enable_ipv4 = false + +chip_inet_config_enable_tcp_endpoint = false + +chip_build_tests = false + +chip_detail_logging = true +chip_progress_logging = true + +chip_mdns = "platform" + +chip_system_config_use_open_thread_inet_endpoints = true +chip_with_lwip = false +mbedtls_target = "${chip_root}/third_party/nxp/k32w1_sdk:mbedtls" +openthread_external_mbedtls = mbedtls_target + +openthread_project_core_config_file = "OpenThreadConfig.h" +openthread_core_config_platform_check_file = + "openthread-core-k32w1-config-check.h" +openthread_core_config_deps = [ "${chip_root}/examples/platform/nxp/k32w/k32w1:openthread_core_config_k32w1_chip_examples" ] + +openthread_external_platform = "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w1:libopenthread-k32w1" diff --git a/src/platform/nxp/k32w/k32w1/ble_function_mux.c b/src/platform/nxp/k32w/k32w1/ble_function_mux.c new file mode 100644 index 00000000000000..ed3a643b8bdb9b --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ble_function_mux.c @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation for BLE Host NVM functions + */ +#include "assert.h" +#include "ble_constants.h" +#include "fsl_os_abstraction.h" +#include "gap_interface.h" +#include "gatt_database.h" + +#include "ble_constants.h" +#include "gatt_db_dynamic.h" + +#include "ble_function_mux.h" + +/* Security Manager */ +#define smpEdiv 0x1F99 +#define mcEncryptionKeySize_c 16 + +/* LTK */ +static uint8_t smpLtk[gcSmpMaxLtkSize_c] = { 0xD6, 0x93, 0xE8, 0xA4, 0x23, 0x55, 0x48, 0x99, + 0x1D, 0x77, 0x61, 0xE6, 0x63, 0x2B, 0x10, 0x8E }; + +/* RAND*/ +static uint8_t smpRand[gcSmpMaxRandSize_c] = { 0x26, 0x1E, 0xF6, 0x09, 0x97, 0x2E, 0xAD, 0x7E }; + +/* IRK */ +static uint8_t smpIrk[gcSmpIrkSize_c] = { 0x0A, 0x2D, 0xF4, 0x65, 0xE3, 0xBD, 0x7B, 0x49, + 0x1E, 0xB4, 0xC0, 0x95, 0x95, 0x13, 0x46, 0x73 }; + +/* CSRK */ +static uint8_t smpCsrk[gcSmpCsrkSize_c] = { 0x90, 0xD5, 0x06, 0x95, 0x92, 0xED, 0x91, 0xD7, + 0xA8, 0x9E, 0x2C, 0xDC, 0x4A, 0x93, 0x5B, 0xF9 }; + +gapSmpKeys_t gSmpKeys = { + .cLtkSize = mcEncryptionKeySize_c, + .aLtk = (void *) smpLtk, + .aIrk = (void *) smpIrk, + .aCsrk = (void *) smpCsrk, + .aRand = (void *) smpRand, + .cRandSize = gcSmpMaxRandSize_c, + .ediv = smpEdiv, +}; + +/******************************************************************************* + * Functions needed by the BLE stack + ******************************************************************************/ +void App_NvmRead(uint8_t mEntryIdx, void * pBondHeader, void * pBondDataDynamic, void * pBondDataStatic, void * pBondDataDeviceInfo, + void * pBondDataDescriptor, uint8_t mDescriptorIndex) +{ + NOT_USED(mEntryIdx); + NOT_USED(pBondHeader); + NOT_USED(pBondDataDynamic); + NOT_USED(pBondDataStatic); + NOT_USED(pBondDataDeviceInfo); + NOT_USED(pBondDataDescriptor); + NOT_USED(mDescriptorIndex); +} + +void App_NvmWrite(uint8_t mEntryIdx, void * pBondHeader, void * pBondDataDynamic, void * pBondDataStatic, + void * pBondDataDeviceInfo, void * pBondDataDescriptor, uint8_t mDescriptorIndex) +{ + NOT_USED(mEntryIdx); + NOT_USED(pBondHeader); + NOT_USED(pBondDataDynamic); + NOT_USED(pBondDataStatic); + NOT_USED(pBondDataDeviceInfo); + NOT_USED(pBondDataDescriptor); + NOT_USED(mDescriptorIndex); +} + +void App_NvmErase(uint8_t mEntryIdx) +{ + NOT_USED(mEntryIdx); +} diff --git a/src/platform/nxp/k32w/k32w1/ble_function_mux.h b/src/platform/nxp/k32w/k32w1/ble_function_mux.h new file mode 100644 index 00000000000000..8b9417d8b54e13 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ble_function_mux.h @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020 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. + */ + +/** + * @file + * Provides an implementation for BLE Host NVM functions + */ + +#ifndef BLE_FUNCTION_MUX_H +#define BLE_FUNCTION_MUX_H + +typedef enum +{ + kBleFuncMux_AppMode_None, + kBleFuncMux_AppMode_Ota +} ble_func_mux_app_mode_t; + +#endif diff --git a/src/platform/nxp/k32w/k32w1/gatt_db.h b/src/platform/nxp/k32w/k32w1/gatt_db.h new file mode 100644 index 00000000000000..604fcfb61a7ba1 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/gatt_db.h @@ -0,0 +1,30 @@ +PRIMARY_SERVICE(service_gatt, gBleSig_GenericAttributeProfile_d) +CHARACTERISTIC(char_service_changed, gBleSig_GattServiceChanged_d, (gGattCharPropRead_c | gGattCharPropNotify_c)) +VALUE(value_service_changed, gBleSig_GattServiceChanged_d, (gPermissionNone_c), 4, 0x00, 0x00, 0x00, 0x00) +CCCD(cccd_service_changed) + +PRIMARY_SERVICE(service_gap, gBleSig_GenericAccessProfile_d) +CHARACTERISTIC(char_device_name, gBleSig_GapDeviceName_d, (gGattCharPropRead_c)) +VALUE(value_device_name, gBleSig_GapDeviceName_d, (gPermissionFlagReadable_c), 16, "NXP_ELOCK_DEMO") +CHARACTERISTIC(char_appearance, gBleSig_GapAppearance_d, (gGattCharPropRead_c)) +VALUE(value_appearance, gBleSig_GapAppearance_d, (gPermissionFlagReadable_c), 2, 0x00, 0x00) + +PRIMARY_SERVICE(service_chipoble, gChipoBleService_d) +CHARACTERISTIC_UUID128(chipoble_rx, uuid_chipoble_rx, (gGattCharPropWrite_c)) +VALUE_UUID128_VARLEN(value_chipoble_rx, uuid_chipoble_rx, (gPermissionFlagWritable_c), gAttMaxMtu_c - 3, gAttMaxMtu_c - 3, 0x00) +CHARACTERISTIC_UUID128(chipoble_tx, uuid_chipoble_tx, (gGattCharPropIndicate_c | gGattCharPropRead_c)) +VALUE_UUID128_VARLEN(value_chipoble_tx, uuid_chipoble_tx, (gPermissionFlagReadable_c), gAttMaxMtu_c - 3, gAttMaxMtu_c - 3, 0x00) +CCCD(cccd_chipoble_tx) +CHARACTERISTIC_UUID128(chipoble_c3, uuid_chipoble_c3, (gGattCharPropRead_c)) +VALUE_UUID128_VARLEN(value_chipoble_c3, uuid_chipoble_c3, (gPermissionFlagReadable_c), gAttMaxReadDataSize_d(gAttMaxValueLength_c), + gAttMaxReadDataSize_d(gAttMaxValueLength_c), 0x00) + +PRIMARY_SERVICE(service_device_info, gBleSig_DeviceInformationService_d) +CHARACTERISTIC(char_model_no, gBleSig_ModelNumberString_d, (gGattCharPropRead_c)) +VALUE(value_model_no, gBleSig_ModelNumberString_d, (gPermissionFlagReadable_c), 15, "Chip ELock Demo") +CHARACTERISTIC(char_serial_no, gBleSig_SerialNumberString_d, (gGattCharPropRead_c)) +VALUE(value_serial_no, gBleSig_SerialNumberString_d, (gPermissionFlagReadable_c), 7, "BLESN01") +CHARACTERISTIC(char_fw_rev, gBleSig_FirmwareRevisionString_d, (gGattCharPropRead_c)) +VALUE(value_fw_rev, gBleSig_FirmwareRevisionString_d, (gPermissionFlagReadable_c), 5, "1.1.1") +CHARACTERISTIC(char_sw_rev, gBleSig_SoftwareRevisionString_d, (gGattCharPropRead_c)) +VALUE(value_sw_rev, gBleSig_SoftwareRevisionString_d, (gPermissionFlagReadable_c), 5, "1.1.4") diff --git a/src/platform/nxp/k32w/k32w1/gatt_uuid128.h b/src/platform/nxp/k32w/k32w1/gatt_uuid128.h new file mode 100644 index 00000000000000..938968b1943ce2 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/gatt_uuid128.h @@ -0,0 +1,26 @@ +/* +* Declare all custom 128-bit UUIDs here using the format: +* +* UUID128(name, bytes) +* +* where: +* -name : an unique tag for the newly defined UUID; + will be used to reference this UUID when defining + services and characteristics in <> +* -bytes: 16 bytes representing the 128-bit value +* +* One definition per line. No semicolon required after each definition. +* +* example: +* UUID128(uuid_service_robot_characteristics, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, +0xCD, 0xEF) +* UUID128(uuid_char_robot_direction, 0x12, 0x34, 0x50, 0x00, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, +0xEF) +*/ +/* Services */ + +#define gChipoBleService_d 0xFFF6 + +UUID128(uuid_chipoble_tx, 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18) +UUID128(uuid_chipoble_rx, 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18) +UUID128(uuid_chipoble_c3, 0x04, 0x8f, 0x21, 0x83, 0x8a, 0x74, 0x7d, 0xb8, 0xf2, 0x45, 0x72, 0x87, 0x38, 0x02, 0x63, 0x64) diff --git a/src/platform/nxp/k32w/k32w1/k32w1-chip-mbedtls-config.h b/src/platform/nxp/k32w/k32w1/k32w1-chip-mbedtls-config.h new file mode 100644 index 00000000000000..f3d9949f730df0 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/k32w1-chip-mbedtls-config.h @@ -0,0 +1,131 @@ +/* + * + * 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. + */ + +// Spans multiple lines to avoid being processed by unifdef +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#include "openthread-core-config.h" + +#include +#include + +#include +#include +#include + +#undef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf + +#define MBEDTLS_AES_C +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CCM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CMAC_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECJPAKE_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_HAVE_ASM +#define MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +#define MBEDTLS_MD_C +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_SHA224_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define MBEDTLS_SSL_EXPORT_KEYS +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_PROTO_DTLS +#define MBEDTLS_SSL_TLS_C + +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#define MBEDTLS_SSL_COOKIE_C +#define MBEDTLS_SSL_SRV_C +#endif + +#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_BASE64_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C +#endif + +#if OPENTHREAD_CONFIG_ECDSA_ENABLE +#define MBEDTLS_BASE64_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_WRITE_C +#endif + +#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_HEAP_EXTERNAL_ENABLE +#define MBEDTLS_PLATFORM_STD_CALLOC otPlatCAlloc /**< Default allocator to use, can be undefined */ +#define MBEDTLS_PLATFORM_STD_FREE otPlatFree /**< Default free to use, can be undefined */ +#else +#define MBEDTLS_MEMORY_BUFFER_ALLOC_C +#endif + +#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_IN_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + +// Spans multiple lines to avoid being processed by unifdef +#if defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "mbedtls/check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/src/platform/nxp/k32w/k32w1/ram_storage.c b/src/platform/nxp/k32w/k32w1/ram_storage.c new file mode 100644 index 00000000000000..189d8be9f8db1e --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ram_storage.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2022, 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 + * RAM buffer structure used for keeping NVM records. + */ +#include +#include +#include + +#include "FunctionLib.h" +#include "ram_storage.h" + +#ifndef RAM_STORAGE_LOG +#define RAM_STORAGE_LOG 0 +#endif + +#if RAM_STORAGE_LOG +#include "fsl_debug_console.h" +#define RAM_STORAGE_PRINTF(...) \ + PRINTF("[%s] ", __FUNCTION__); \ + PRINTF(__VA_ARGS__); \ + PRINTF("\n\r"); +#else +#define RAM_STORAGE_PRINTF(...) +#endif + +rsError ramStorageAdd(ramBufferDescriptor * pBuffer, uint16_t aKey, const uint8_t * aValue, uint16_t aValueLength) +{ + rsError error = RS_ERROR_NONE; + struct settingsBlock currentBlock = { 0 }; + const uint16_t newBlockLength = sizeof(struct settingsBlock) + aValueLength; + + assert(pBuffer); + if (pBuffer->ramBufferLen + newBlockLength <= pBuffer->ramBufferMaxLen) + { + currentBlock.key = aKey; + currentBlock.length = aValueLength; + + memcpy(&pBuffer->pRamBuffer[pBuffer->ramBufferLen], ¤tBlock, sizeof(struct settingsBlock)); + memcpy(&pBuffer->pRamBuffer[pBuffer->ramBufferLen + sizeof(struct settingsBlock)], aValue, aValueLength); + pBuffer->ramBufferLen += newBlockLength; + + error = RS_ERROR_NONE; + } + else + { + error = RS_ERROR_NO_BUFS; + } + + RAM_STORAGE_PRINTF("key = %d lengthWriten = %d err = %d", aKey, aValueLength, error); + + return error; +} + +rsError ramStorageGet(const ramBufferDescriptor * pBuffer, uint16_t aKey, int aIndex, uint8_t * aValue, uint16_t * aValueLength) +{ + uint16_t i = 0; + uint16_t valueLength = 0; + uint16_t readLength = 0; + int currentIndex = 0; + struct settingsBlock currentBlock = { 0 }; + rsError error = RS_ERROR_NOT_FOUND; + + assert(pBuffer); + while (i < pBuffer->ramBufferLen) + { + memcpy(¤tBlock, &pBuffer->pRamBuffer[i], sizeof(struct settingsBlock)); + + if (aKey == currentBlock.key) + { + if (currentIndex == aIndex) + { + readLength = currentBlock.length; + + // Perform read only if an input buffer was passed in + if (aValue != NULL && aValueLength != NULL) + { + // Adjust read length if input buffer size is smaller + if (readLength > *aValueLength) + { + readLength = *aValueLength; + } + + memcpy(aValue, &pBuffer->pRamBuffer[i + sizeof(struct settingsBlock)], readLength); + } + + valueLength = currentBlock.length; + error = RS_ERROR_NONE; + break; + } + + currentIndex++; + } + + i += sizeof(struct settingsBlock) + currentBlock.length; + } + + if (aValueLength != NULL) + { + *aValueLength = valueLength; + } + + RAM_STORAGE_PRINTF("key = %d err = %d", aKey, error); + + return error; +} + +rsError ramStorageSet(ramBufferDescriptor * pBuffer, uint16_t aKey, const uint8_t * aValue, uint16_t aValueLength) +{ + uint16_t i = 0; + uint16_t currentBlockLength = 0; + struct settingsBlock currentBlock = { 0 }; + bool_t alreadyExists = FALSE; + rsError error = RS_ERROR_NONE; + + while (i < pBuffer->ramBufferLen) + { + memcpy(¤tBlock, &pBuffer->pRamBuffer[i], sizeof(struct settingsBlock)); + currentBlockLength = sizeof(struct settingsBlock) + currentBlock.length; + + if (aKey == currentBlock.key) + { + /* unlikely: the updated value has a different length */ + if (currentBlock.length != aValueLength) + { + ramStorageDelete(pBuffer, aKey, -1); + break; + } + + memcpy(&pBuffer->pRamBuffer[i + sizeof(struct settingsBlock)], aValue, aValueLength); + alreadyExists = TRUE; + break; + } + else + { + i += currentBlockLength; + } + } + + if (!alreadyExists) + { + error = ramStorageAdd(pBuffer, aKey, aValue, aValueLength); + } + + return error; +} + +rsError ramStorageDelete(ramBufferDescriptor * pBuffer, uint16_t aKey, int aIndex) +{ + uint16_t i = 0; + int currentIndex = 0; + uint16_t nextBlockStart = 0; + uint16_t currentBlockLength = 0; + struct settingsBlock currentBlock = { 0 }; + rsError error = RS_ERROR_NOT_FOUND; + bool_t found = FALSE; + + assert(pBuffer); + while (i < pBuffer->ramBufferLen) + { + memcpy(¤tBlock, &pBuffer->pRamBuffer[i], sizeof(struct settingsBlock)); + currentBlockLength = sizeof(struct settingsBlock) + currentBlock.length; + + if (aKey == currentBlock.key) + { + if ((currentIndex == aIndex) || (aIndex == -1)) + { + currentIndex++; + + nextBlockStart = i + currentBlockLength; + + if (nextBlockStart < pBuffer->ramBufferLen) + { + memmove(&pBuffer->pRamBuffer[i], &pBuffer->pRamBuffer[nextBlockStart], pBuffer->ramBufferLen - nextBlockStart); + } + + assert(pBuffer->ramBufferLen >= currentBlockLength); + pBuffer->ramBufferLen -= currentBlockLength; + found = TRUE; + + error = RS_ERROR_NONE; + } + + if (found && (aIndex != -1)) + { + break; + } + } + + if (!found) + { + i += currentBlockLength; + } + found = FALSE; + } + RAM_STORAGE_PRINTF("key = %d err = %d", aKey, error); + return error; +} diff --git a/src/platform/nxp/k32w/k32w1/ram_storage.h b/src/platform/nxp/k32w/k32w1/ram_storage.h new file mode 100644 index 00000000000000..77cdca10b4f7f1 --- /dev/null +++ b/src/platform/nxp/k32w/k32w1/ram_storage.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022, 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. + */ + +#ifndef RAM_STORAGE_K32W_H_ +#define RAM_STORAGE_K32W_H_ + +#include + +typedef enum +{ + RS_ERROR_NONE, + RS_ERROR_NOT_FOUND, + RS_ERROR_NO_BUFS +} rsError; + +/* the structure used for keeping the records has the same structure both in RAM and in NVM: + * ramBufferLen | ramBufferMaxLen | settingsBlock+Data | .... | settingsBlock+Data + * + * ramBufferLen shows how much of the RAM buffer is currently occupied with settingsBlock structures + * ramBufferMaxLen shows the total malloc'ed size. Dynamic re-allocation is possible + */ +typedef struct +{ + uint16_t ramBufferLen; + uint16_t ramBufferMaxLen; + uint8_t pRamBuffer[1]; +} ramBufferDescriptor; + +struct settingsBlock +{ + uint16_t key; + uint16_t length; +} __attribute__((packed)); + +#if defined(PDM_USE_DYNAMIC_MEMORY) && PDM_USE_DYNAMIC_MEMORY && defined(OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE) && \ + OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#define ENABLE_STORAGE_DYNAMIC_MEMORY 1 +#else +#define ENABLE_STORAGE_DYNAMIC_MEMORY 0 +#endif + +/* increment size for dynamic memory re-allocation in case the + * initial RAM buffer size gets insufficient + */ +#define kRamBufferReallocSize 512 +#define kRamBufferMaxAllocSize 10240 + +#define kRamDescHeaderSize offsetof(ramBufferDescriptor, pRamBuffer) + +#ifdef __cplusplus +extern "C" { +#endif + +/* search RAM Buffer for aKey and return its value in aValue. aValueLength will contain the length of aValueLength */ +rsError ramStorageGet(const ramBufferDescriptor * pBuffer, uint16_t aKey, int aIndex, uint8_t * aValue, uint16_t * aValueLength); + +/* search RAM buffer for aKey and set its value to aValue (having aValueLength length) + * - aValue and aValueLength can be NULL - the function checks only for the existence of aKey + * - if only aValue is NULL and aKey exists in the RAM buffer - the function will return its value in aValueLength + */ +rsError ramStorageSet(ramBufferDescriptor * pBuffer, uint16_t aKey, const uint8_t * aValue, uint16_t aValueLength); + +/* adds a settingsBlock (aKey:aValue) to the end of the RAM Buffer: + * - doesn't check if aKey already exists in the RAM Buffer + * - aValueLength can be 0 + */ +rsError ramStorageAdd(ramBufferDescriptor * pBuffer, uint16_t aKey, const uint8_t * aValue, uint16_t aValueLength); + +/* search RAM Buffer for aKey (with aIndex) and delete it: + * - if aIndex is -1 then all the occurrences of aKey are deleted + */ +rsError ramStorageDelete(ramBufferDescriptor * pBuffer, uint16_t aKey, int aIndex); + +#ifdef __cplusplus +} +#endif + +#endif /* RAM_STORAGE_K32W_H_ */ diff --git a/src/system/BUILD.gn b/src/system/BUILD.gn index 8882854b675f42..6c036a73d920b6 100644 --- a/src/system/BUILD.gn +++ b/src/system/BUILD.gn @@ -56,6 +56,8 @@ if (chip_device_platform == "cc13x2_26x2") { import("${qpg_sdk_build_root}/qpg_sdk.gni") } else if (chip_device_platform == "k32w0") { import("//build_overrides/k32w0_sdk.gni") +} else if (chip_device_platform == "k32w1") { + import("//build_overrides/k32w1_sdk.gni") } else if (chip_device_platform == "psoc6") { import("//build_overrides/psoc6.gni") } else if (chip_device_platform == "cyw30739") { @@ -176,6 +178,9 @@ source_set("system_config_header") { if (chip_device_platform == "k32w0") { public_deps += [ "${k32w0_sdk_build_root}:k32w0_sdk" ] } + if (chip_device_platform == "k32w1") { + public_deps += [ "${k32w1_sdk_build_root}:k32w1_sdk" ] + } if (chip_device_platform == "cyw30739") { public_deps += [ "${cyw30739_sdk_build_root}:cyw30739_sdk" ] } diff --git a/third_party/nxp/k32w1_sdk/BUILD.gn b/third_party/nxp/k32w1_sdk/BUILD.gn new file mode 100644 index 00000000000000..8173cdd0df7863 --- /dev/null +++ b/third_party/nxp/k32w1_sdk/BUILD.gn @@ -0,0 +1,81 @@ +# 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/k32w1_sdk.gni") +import("//build_overrides/mbedtls.gni") + +import("${k32w1_sdk_build_root}/k32w1_sdk.gni") +import("${mbedtls_root}/mbedtls.gni") + +declare_args() { + # Build target to use for k32w1 SDK. Use this to set global SDK defines. + k32w1_sdk_target = "" +} + +assert(k32w1_sdk_target != "", "k32w1_sdk_target must be specified") + +group("k32w1_sdk") { + public_deps = [ k32w1_sdk_target ] +} + +config("mbedtls_k32w1_config") { + defines = [ + "MBEDTLS_CONFIG_FILE=", + "MBEDTLS_USER_CONFIG_FILE=", + + # These options should really be in the config.h... + "MBEDTLS_FREESCALE_FREERTOS_CALLOC_ALT=1", + "MBEDTLS_THREADING_C=1", + "MBEDTLS_THREADING_ALT=1", + "MBEDTLS_X509_CSR_WRITE_C", + "MBEDTLS_X509_CREATE_C", + "MBEDTLS_PEM_WRITE_C", + "MBEDTLS_HKDF_C", + "MBEDTLS_ERROR_C", + "MBEDTLS_PKCS5_C", + + "MBEDTLS_ECP_FIXED_POINT_OPTIM=0", # To reduce peak memory usage + "MBEDTLS_MPI_WINDOW_SIZE=1", + "MBEDTLS_ECP_WINDOW_SIZE=2", + "MBEDTLS_MPI_MAX_SIZE=32", # Maximum number of bytes for usable MPIs. + "MBEDTLS_ECP_MAX_BITS=256", # Maximum bit size of groups */ + "MBEDTLS_ENTROPY_MAX_SOURCES=1", # Maximum number of sources supported + + "MBEDTLS_ENTROPY_HARDWARE_ALT", + ] + + if (chip_mdns == "none") { + defines += [ + "MBEDTLS_PK_WRITE_C", + "MBEDTLS_OID_C", + "MBEDTLS_BASE64_C", + ] + } + + include_dirs = [ chip_root ] +} + +mbedtls_target("mbedtls") { + sources = [ + "${k32w1_sdk_root}/middleware/mbedtls/port/sssapi/ccm_alt.c", + "${k32w1_sdk_root}/middleware/mbedtls/port/sssapi/entropy_poll_alt.c", + ] + + public_configs = [ ":mbedtls_k32w1_config" ] + + public_deps = [ + ":k32w1_sdk", + "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w1:openthread_mbedtls_config_k32w1", + ] +} diff --git a/third_party/nxp/k32w1_sdk/Jlink_Script/K32W1.jlink b/third_party/nxp/k32w1_sdk/Jlink_Script/K32W1.jlink new file mode 100644 index 00000000000000..9d9e4264c1b7d9 --- /dev/null +++ b/third_party/nxp/k32w1_sdk/Jlink_Script/K32W1.jlink @@ -0,0 +1,6 @@ +r +h +loadfile chip-k32w1-light-example.srec +r +g +q \ No newline at end of file diff --git a/third_party/nxp/k32w1_sdk/k32w1_executable.gni b/third_party/nxp/k32w1_sdk/k32w1_executable.gni new file mode 100644 index 00000000000000..bc78dfc13bf95c --- /dev/null +++ b/third_party/nxp/k32w1_sdk/k32w1_executable.gni @@ -0,0 +1,34 @@ +# 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_root}/toolchain/flashable_executable.gni") + +template("k32w1_executable") { + output_base_name = get_path_info(invoker.output_name, "name") + objcopy_image_name = output_base_name + ".srec" + objcopy_image_format = "srec" + objcopy = "arm-none-eabi-objcopy" + + # Copy flashing dependencies to the output directory so that the output + # is collectively self-contained; this allows flashing to work reliably + # even if the build and flashing steps take place on different machines + # or in different containers. + + flashable_executable(target_name) { + forward_variables_from(invoker, "*") + } +} diff --git a/third_party/nxp/k32w1_sdk/k32w1_sdk.gni b/third_party/nxp/k32w1_sdk/k32w1_sdk.gni new file mode 100644 index 00000000000000..14f355b9da068c --- /dev/null +++ b/third_party/nxp/k32w1_sdk/k32w1_sdk.gni @@ -0,0 +1,495 @@ +# 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/k32w1_sdk.gni") +import("//build_overrides/mbedtls.gni") +import("//build_overrides/openthread.gni") + +import("${build_root}/config/compiler/compiler.gni") +import("${chip_root}/src/crypto/crypto.gni") +import("${chip_root}/src/lib/core/core.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/nxp/k32w/k32w1/args.gni") + +declare_args() { + # Location of the k32w1 SDK. + k32w1_sdk_root = getenv("NXP_K32W1_SDK_ROOT") + use_smu2_as_system_memory = false +} + +openthread_nxp_root = "${chip_root}/third_party/openthread/ot-nxp" + +assert(k32w1_sdk_root != "", "k32w1_sdk_root must be specified") + +assert(!(use_smu2_as_system_memory && !chip_openthread_ftd), + "SMU2 can be used as system memory only with OT-FTD suppport") + +# Defines an k32w1 SDK build target. +# +# Parameters: +# k32w1_sdk_root - The location of the k32w1 SDK. +# sources - Extra source files to build. +template("k32w1_sdk") { + if (defined(invoker.k32w1_sdk_root)) { + k32w1_sdk_root = invoker.k32w1_sdk_root + } + + assert(chip_with_low_power == 0 || + (chip_with_low_power == 1 && chip_with_ot_cli == 0), + "Please disable low power if openthread CLI is needed!") + + sdk_target_name = target_name + + config("${sdk_target_name}_config") { + include_dirs = [] + if (defined(invoker.include_dirs)) { + include_dirs += invoker.include_dirs + } + + # We want to treat SDK headers as system headers, so that warnings in those + # headers are not fatal. Therefore don't add them directly to include_dirs; + # we will add them to cflags below instead. + _sdk_include_dirs = [ + "${k32w1_sdk_root}/devices/K32W1480", + "${k32w1_sdk_root}/CMSIS/Core/Include", + "${k32w1_sdk_root}/platform/drivers/snt", + "${k32w1_sdk_root}/platform/drivers/spc", + "${k32w1_sdk_root}/platform/drivers/ccm32k", + "${k32w1_sdk_root}/platform/drivers/wuu", + "${k32w1_sdk_root}/platform/drivers/cmc", + "${k32w1_sdk_root}/platform/drivers/lpspi", + "${k32w1_sdk_root}/components/osa", + "${k32w1_sdk_root}/components/lists", + "${k32w1_sdk_root}/components/messaging", + "${k32w1_sdk_root}/components/mem_manager", + "${k32w1_sdk_root}/components/panic", + "${k32w1_sdk_root}/components/serial_manager", + "${k32w1_sdk_root}/components/uart", + "${k32w1_sdk_root}/components/gpio", + "${k32w1_sdk_root}/components/led", + "${k32w1_sdk_root}/components/button", + "${k32w1_sdk_root}/components/timer_manager", + "${k32w1_sdk_root}/components/time_stamp", + "${k32w1_sdk_root}/components/timer", + "${k32w1_sdk_root}/components/rpmsg", + "${k32w1_sdk_root}/components/internal_flash", + "${k32w1_sdk_root}/components/reset", + "${k32w1_sdk_root}/components/flash/nor/lpspi", + "${k32w1_sdk_root}/components/flash/nor", + "${k32w1_sdk_root}/components/power_manager/boards", + "${k32w1_sdk_root}/components/power_manager/boards/K32W148-EVK", + "${k32w1_sdk_root}/components/power_manager/core", + + "${k32w1_sdk_root}/middleware/wireless/framework/DBG", + "${k32w1_sdk_root}/middleware/wireless/framework/Common", + "${k32w1_sdk_root}/middleware/wireless/framework/FunctionLib", + "${k32w1_sdk_root}/middleware/wireless/framework/HWParameter", + "${k32w1_sdk_root}/middleware/wireless/framework/SecLib", + "${k32w1_sdk_root}/middleware/wireless/framework/RNG", + "${k32w1_sdk_root}/middleware/wireless/framework/Sensors", + "${k32w1_sdk_root}/middleware/wireless/framework/LowPower", + "${k32w1_sdk_root}/middleware/wireless/framework/NVM/Source", + "${k32w1_sdk_root}/middleware/wireless/framework/NVM/Interface", + "${k32w1_sdk_root}/middleware/wireless/framework/ModuleInfo", + "${k32w1_sdk_root}/middleware/wireless/framework/OtaSupport/Interface", + "${k32w1_sdk_root}/middleware/wireless/framework/OtaSupport/Source", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/include", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/configs", + "${openthread_nxp_root}/third_party/k32w1_sdk", + + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/include", + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/include/platform/k32w1", + "${k32w1_sdk_root}/middleware/multicore/mcmgr/src", + + "${k32w1_sdk_root}/middleware/wireless/ble_controller/interface", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/hci_transport/interface", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/port", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/gatt_db", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/gatt_db/macros", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/host/config", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/host/interface", + + "${k32w1_sdk_root}/middleware/mbedtls/port/sssapi", + "${k32w1_sdk_root}/middleware/mbedtls/port/ksdk", + "${k32w1_sdk_root}/middleware/mbedtls/include/mbedtls", + "${k32w1_sdk_root}/middleware/mbedtls/include", + "${k32w1_sdk_root}/middleware/secure-subsystem/inc", + "${k32w1_sdk_root}/middleware/secure-subsystem/inc/snt", + "${k32w1_sdk_root}/middleware/secure-subsystem/port/kw45_k4w1", + + "${k32w1_sdk_root}/middleware/wireless/XCVR/drv", + "${k32w1_sdk_root}/middleware/wireless/XCVR/drv/nb2p4ghz", + "${k32w1_sdk_root}/middleware/wireless/XCVR/drv/nb2p4ghz/configs/gen45", + "${k32w1_sdk_root}/middleware/wireless/ieee-802.15.4/ieee_802_15_4/phy/interface", + "${k32w1_sdk_root}/middleware/wireless/ieee-802.15.4/utils", + + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/include", + "${k32w1_sdk_root}/rtos/freertos/libraries/3rdparty/mbedtls_config", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/portable/GCC/ARM_CM33_NTZ/non_secure", + + "${chip_root}/src/platform/nxp/k32w/k32w1", + ] + + if (sdk_release == 1) { + _sdk_include_dirs += [ + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/matter", + "${k32w1_sdk_root}/devices/K32W1480/drivers", + "${k32w1_sdk_root}/devices/K32W1480/utilities", + "${k32w1_sdk_root}/devices/K32W1480/utilities/debug_console", + "${k32w1_sdk_root}/devices/K32W1480/utilities/str", + "${k32w1_sdk_root}/devices/K32W1480/utilities/format", + ] + } else { + _sdk_include_dirs += [ + "${k32w1_sdk_root}/devices/KW45B41Z83/drivers", + "${k32w1_sdk_root}/devices/KW45B41Z83/drivers/romapi", + "${k32w1_sdk_root}/platform/drivers/common", + "${k32w1_sdk_root}/platform/drivers/flash_k4", + "${k32w1_sdk_root}/platform/drivers/gpio", + "${k32w1_sdk_root}/platform/drivers/lpuart", + "${k32w1_sdk_root}/platform/drivers/ltc", + "${k32w1_sdk_root}/platform/drivers/port", + "${k32w1_sdk_root}/platform/drivers/lptmr", + "${k32w1_sdk_root}/platform/drivers/ccm32k", + "${k32w1_sdk_root}/platform/drivers/imu", + "${k32w1_sdk_root}/platform/drivers/crc", + "${k32w1_sdk_root}/platform/utilities/misc_utilities", + "${k32w1_sdk_root}/platform/utilities/debug_console", + "${k32w1_sdk_root}/platform/utilities/str", + ] + } + + libs = [ + "${k32w1_sdk_root}/middleware/wireless/bluetooth/host/lib/lib_ble_host_matter_cm33_gcc.a", + "${k32w1_sdk_root}/middleware/wireless/framework/SecLib/lib_crypto_m33.a", + ] + + defines = [ + "gMainThreadPriority_c=5", + "CPU_K32W1480VFTA", + "__STARTUP_CLEAR_BSS", + "SERIAL_MANAGER_NON_BLOCKING_MODE=1", + "SERIAL_USE_CONFIGURE_STRUCTURE=1", + "SDK_COMPONENT_INTEGRATION=1", + "SERIAL_PORT_TYPE_UART=1", + "gSerialManagerMaxInterfaces_c=1", + "SDK_OS_FREE_RTOS", + "gAppHighSystemClockFrequency_d=1", + + "USE_NBU=1", + "KW45_A0_SUPPORT=0", + "HAL_RPMSG_SELECT_ROLE=0", + "TM_ENABLE_TIME_STAMP=1", + "FSL_OSA_TASK_ENABLE=1", + "FSL_OSA_MAIN_FUNC_ENABLE=1", + "gAspCapability_d=1", + "gNvStorageIncluded_d=1", + "gUnmirroredFeatureSet_d=1", + "gNvFragmentation_Enabled_d=1", + "gAppButtonCnt_c=2", + "gAppLowpowerEnabled_d=1", + "BUTTON_SHORT_PRESS_THRESHOLD=1500", + "BUTTON_LONG_PRESS_THRESHOLD=2500", + "SSS_CONFIG_FILE=\"fsl_sss_config_snt.h\"", + "SSCP_CONFIG_FILE=\"fsl_sscp_config_snt.h\"", + + "SDK_DEBUGCONSOLE=1", + "NO_SYSCORECLK_UPD=0", + "USE_RTOS=1", + "USE_SDK_OSA=0", + "FSL_RTOS_FREE_RTOS=1", + "MinimalHeapSize_c=0x8C00", + "gMemManagerLightExtendHeapAreaUsage=0", + "DEBUG_SERIAL_INTERFACE_INSTANCE=0", + "APP_SERIAL_INTERFACE_INSTANCE=1", + + "configFRTOS_MEMORY_SCHEME=4", + "osCustomStartup=1", + + "ENABLE_RAM_VECTOR_TABLE=1", + + "CHIP_ENABLE_OPENTHREAD=1", + "gUseHciTransportDownward_d=1", + "gAppMaxConnections_c=1", + "gL2caMaxLeCbChannels_c=2", + "gGapSimultaneousEAChainedReports_c=0", + "gTmrStackTimers_c= 3 + gAppMaxConnections_c * 2 + gL2caMaxLeCbChannels_c + gGapSimultaneousEAChainedReports_c", + "gAppUseBonding_d=0", + "gAppUsePairing_d=0", + "gAppUsePrivacy_d=0", + "gGattUseUpdateDatabaseCopyProc_c=0", + "gBleBondIdentityHeaderSize_c=56", + "gPasskeyValue_c=999999", + "gMainThreadStackSize_c=3096", + "gHost_TaskStackSize_c=2400", + "gBleSetMacAddrFromVendorCommand_d=1", + "gLoggingActive_d=0", + "gLogRingPlacementOffset_c=0xF000", + "CHIP_PLAT_NVM_SUPPORT=1", + "mAdvertisingDefaultTxPower_c=0", # default advertising TX power + "mConnectionDefaultTxPower_c=0", # default connection TX power + "BLE_HIGH_TX_POWER=0", # when enabled overwrite default tx power with + # following values gAdvertisingPowerLeveldBm_c and + # gConnectPowerLeveldBm_c + "gAdvertisingPowerLeveldBm_c=0", + "gConnectPowerLeveldBm_c=0", + ] + + if (chip_with_low_power == 1 && chip_logging == true) { + print( + "WARNING: enabling logs in low power might break the LP timings. Use at your own risk!") + print("WARNING: set chip_logging=false to disable logging.") + } + + if (chip_mdns == "platform") { + defines += [ + "OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE=1", + "OPENTHREAD_CONFIG_ECDSA_ENABLE=1", + "OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE=1", + "OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE=1", + ] + } + + if (chip_with_ot_cli == 1) { + defines += [ "CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI=1" ] + } + + if (use_smu2_as_system_memory) { + defines += [ + "__STARTUP_CLEAR_SMU2", + "USE_SMU2_AS_SYSTEM_MEMORY", + ] + } + + if (chip_with_low_power == 1) { + defines += [ + "chip_with_low_power=1", + "cPWR_UsePowerDownMode=1", + "gAppLowpowerEnabled_d=1", + ] + + if (chip_logging == false) { + defines += [ + "K32W_LOG_ENABLED=0", + "gUartDebugConsole_d=0", + ] + } else { + defines += [ + "K32W_LOG_ENABLED=1", + "OSA_USED=1", + "gUartDebugConsole_d=1", + ] + } + } else { + defines += [ + "gAppLedCnt_c=2", + "K32W_LOG_ENABLED=1", + "gUartDebugConsole_d=1", + ] + } + + if (defined(invoker.defines)) { + defines += invoker.defines + } + + cflags = [ + "-Wno-unused-function", + "-Wno-conversion", + "-Wno-sign-compare", + "-Wno-clobbered", + "-Wno-implicit-fallthrough", + "-fno-optimize-strlen", + "-mthumb", + "-MMD", + "-MP", + ] + + cflags += [ + # TODO After upgrading the compiler we started to see new error from address + # warning. To allow PR that rolls up compiler we have suppress this warning + # as an error temporarily. + # see https://github.com/project-chip/connectedhomeip/issues/26221 + "-Wno-error=address", + ] + + # Now add our "system-header" include dirs + foreach(include_dir, _sdk_include_dirs) { + cflags += [ "-isystem" + rebase_path(include_dir, root_build_dir) ] + } + } + + # TODO - Break up this monolith and make it configurable. + source_set(sdk_target_name) { + forward_variables_from(invoker, "*") + + if (!defined(sources)) { + sources = [] + } + + if (sdk_release == 1) { + sources += [ + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_ccm32k.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_clock.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_cmc.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_crc.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_gpio.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_imu.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_k4_controller.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_k4_flash.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_lpspi.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_lptmr.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_lpuart.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_ltc.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_snt.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_spc.c", + "${k32w1_sdk_root}/devices/K32W1480/drivers/fsl_wuu.c", + "${k32w1_sdk_root}/devices/K32W1480/utilities/debug_console/fsl_debug_console.c", + "${k32w1_sdk_root}/devices/K32W1480/utilities/fsl_assert.c", + "${k32w1_sdk_root}/devices/K32W1480/utilities/str/fsl_str.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/matter/ble_init.c", + ] + } else { + sources += [ + "${k32w1_sdk_root}/devices/KW45B41Z83/drivers/fsl_clock.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/ble_init.c", + "${k32w1_sdk_root}/platform/drivers/ccm32k/fsl_ccm32k.c", + "${k32w1_sdk_root}/platform/drivers/cmc/fsl_cmc.c", + "${k32w1_sdk_root}/platform/drivers/crc/fsl_crc.c", + "${k32w1_sdk_root}/platform/drivers/flash_k4/fsl_k4_controller.c", + "${k32w1_sdk_root}/platform/drivers/flash_k4/fsl_k4_flash.c", + "${k32w1_sdk_root}/platform/drivers/gpio/fsl_gpio.c", + "${k32w1_sdk_root}/platform/drivers/imu/fsl_imu.c", + "${k32w1_sdk_root}/platform/drivers/lpspi/fsl_lpspi.c", + "${k32w1_sdk_root}/platform/drivers/lptmr/fsl_lptmr.c", + "${k32w1_sdk_root}/platform/drivers/lpuart/fsl_lpuart.c", + "${k32w1_sdk_root}/platform/drivers/ltc/fsl_ltc.c", + "${k32w1_sdk_root}/platform/drivers/snt/fsl_snt.c", + "${k32w1_sdk_root}/platform/drivers/spc/fsl_spc.c", + "${k32w1_sdk_root}/platform/drivers/wuu/fsl_wuu.c", + "${k32w1_sdk_root}/platform/utilities/assert/fsl_assert.c", + "${k32w1_sdk_root}/platform/utilities/debug_console/fsl_debug_console.c", + "${k32w1_sdk_root}/platform/utilities/str/fsl_str.c", + ] + } + + sources += [ + "${k32w1_sdk_root}/components/button/fsl_component_button.c", + "${k32w1_sdk_root}/components/flash//nor/lpspi/fsl_lpspi_mem_adapter.c", + "${k32w1_sdk_root}/components/flash//nor/lpspi/fsl_lpspi_nor_flash.c", + "${k32w1_sdk_root}/components/gpio/fsl_adapter_gpio.c", + "${k32w1_sdk_root}/components/internal_flash/fsl_adapter_k4_flash.c", + "${k32w1_sdk_root}/components/led/fsl_component_led.c", + "${k32w1_sdk_root}/components/lists/fsl_component_generic_list.c", + "${k32w1_sdk_root}/components/mem_manager/fsl_component_mem_manager_light.c", + "${k32w1_sdk_root}/components/messaging/fsl_component_messaging.c", + "${k32w1_sdk_root}/components/osa/fsl_os_abstraction_free_rtos.c", + "${k32w1_sdk_root}/components/panic/fsl_component_panic.c", + "${k32w1_sdk_root}/components/power_manager/boards/K32W148-EVK/fsl_pm_board.c", + "${k32w1_sdk_root}/components/power_manager/core/fsl_pm_core.c", + "${k32w1_sdk_root}/components/reset/fsl_adapter_reset.c", + "${k32w1_sdk_root}/components/rpmsg/fsl_adapter_rpmsg.c", + "${k32w1_sdk_root}/components/serial_manager/fsl_component_serial_manager.c", + "${k32w1_sdk_root}/components/serial_manager/fsl_component_serial_port_uart.c", + "${k32w1_sdk_root}/components/time_stamp/fsl_adapter_lptmr_time_stamp.c", + "${k32w1_sdk_root}/components/timer/fsl_adapter_lptmr.c", + "${k32w1_sdk_root}/components/timer_manager/fsl_component_timer_manager.c", + "${k32w1_sdk_root}/components/uart/fsl_adapter_lpuart.c", + "${k32w1_sdk_root}/devices/K32W1480/gcc/startup_K32W1480.S", + "${k32w1_sdk_root}/devices/K32W1480/system_K32W1480.c", + "${k32w1_sdk_root}/middleware/multicore/mcmgr/src/mcmgr.c", + "${k32w1_sdk_root}/middleware/multicore/mcmgr/src/mcmgr_imu_internal.c", + "${k32w1_sdk_root}/middleware/multicore/mcmgr/src/mcmgr_internal_core_api_k32w1.c", + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/common/llist.c", + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c", + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/rpmsg_lite/porting/platform/k32w1/rpmsg_platform.c", + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c", + "${k32w1_sdk_root}/middleware/multicore/rpmsg_lite/lib/virtio/virtqueue.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/port/kw45_k4w1/sss_aes.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/port/kw45_k4w1/sss_aes_cmac.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/port/kw45_k4w1/sss_ecdh.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/port/kw45_k4w1/sss_init.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/port/kw45_k4w1/sss_sha256.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/src/sscp/fsl_sscp_mu.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/src/sscp/fsl_sss_mgmt.c", + "${k32w1_sdk_root}/middleware/secure-subsystem/src/sscp/fsl_sss_sscp.c", + "${k32w1_sdk_root}/middleware/wireless/ble_controller/src/controller_api.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/ble_conn_manager.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/application/common/gatt_db/gatt_database.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/hci_transport/source/hcit_generic_adapter_interface.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/host/config/ble_globals.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/port/fwk_generic_list.c", + "${k32w1_sdk_root}/middleware/wireless/bluetooth/port/fwk_timer_manager.c", + "${k32w1_sdk_root}/middleware/wireless/framework/Common/rtos/freertos/heap_mem_manager.c", + "${k32w1_sdk_root}/middleware/wireless/framework/FunctionLib/FunctionLib.c", + "${k32w1_sdk_root}/middleware/wireless/framework/HWParameter/HWParameter.c", + "${k32w1_sdk_root}/middleware/wireless/framework/LowPower/PWR.c", + "${k32w1_sdk_root}/middleware/wireless/framework/LowPower/PWR_systicks.c", + "${k32w1_sdk_root}/middleware/wireless/framework/NVM/Source/NV_Flash.c", + "${k32w1_sdk_root}/middleware/wireless/framework/OtaSupport/Source/OtaExternalFlash.c", + "${k32w1_sdk_root}/middleware/wireless/framework/OtaSupport/Source/OtaSupport.c", + "${k32w1_sdk_root}/middleware/wireless/framework/RNG/RNG.c", + "${k32w1_sdk_root}/middleware/wireless/framework/SecLib/SecLib_sss.c", + "${k32w1_sdk_root}/middleware/wireless/framework/Sensors/sensors.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/clock_config.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/pin_mux.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/app_services_init.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_comp.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_dcdc.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_extflash.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_lp.c", + "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/hardware_init.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform_ble.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform_extflash.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform_ics.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform_lowpower.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform_ot.c", + "${k32w1_sdk_root}/middleware/wireless/framework/platform/kw45_k32w1/fwk_platform_ota.c", + "${k32w1_sdk_root}/middleware/wireless/ieee-802.15.4/ieee_802_15_4/phy/source/PhyTime.c", + "${k32w1_sdk_root}/middleware/wireless/ieee-802.15.4/ieee_802_15_4/phy/source/SerialDevice/ASP.c", + "${k32w1_sdk_root}/middleware/wireless/ieee-802.15.4/ieee_802_15_4/phy/source/SerialDevice/Phy.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/croutine.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/event_groups.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/list.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/portable/GCC/ARM_CM33_NTZ/non_secure/port.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/queue.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/stream_buffer.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/tasks.c", + "${k32w1_sdk_root}/rtos/freertos/freertos_kernel/timers.c", + ] + + if (chip_with_low_power == 1) { + sources += [] + } + + if (!defined(public_deps)) { + public_deps = [] + } + + public_deps += [ "${openthread_root}/src/core:libopenthread_core_headers" ] + + if (!defined(public_configs)) { + public_configs = [] + } + + public_configs += [ ":${sdk_target_name}_config" ] + } +} diff --git a/third_party/openthread/ot-nxp b/third_party/openthread/ot-nxp index d533504a90f231..72b9cbf7e9edb4 160000 --- a/third_party/openthread/ot-nxp +++ b/third_party/openthread/ot-nxp @@ -1 +1 @@ -Subproject commit d533504a90f2312ba3cfe94f716f3ee9b59d4209 +Subproject commit 72b9cbf7e9edb4d687855be75474ee59628831a1 diff --git a/third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn b/third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn index 0bf402053b8e80..a67158170d0a18 100644 --- a/third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn +++ b/third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn @@ -38,6 +38,7 @@ config("openthread_k32w0_config") { "OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE=1", "OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE=1", "K32W0_RADIO_NUM_OF_RX_BUFS=16", + "OPENTHREAD_PLATFORM_CORE_CONFIG_FILE=\"app/project_include/OpenThreadConfig.h\"", ] } diff --git a/third_party/openthread/platforms/nxp/k32w/k32w1/BUILD.gn b/third_party/openthread/platforms/nxp/k32w/k32w1/BUILD.gn new file mode 100644 index 00000000000000..341c8960ede578 --- /dev/null +++ b/third_party/openthread/platforms/nxp/k32w/k32w1/BUILD.gn @@ -0,0 +1,76 @@ +# 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/k32w1_sdk.gni") +import("//build_overrides/openthread.gni") +import("${chip_root}/third_party/nxp/k32w1_sdk/k32w1_sdk.gni") + +openthread_nxp_root = "${chip_root}/third_party/openthread/ot-nxp" + +config("openthread_k32w1_config") { + include_dirs = [ "${openthread_nxp_root}/src/k32w1/k32w1" ] + include_dirs += [ "${chip_root}/examples/platform/nxp/k32w/k32w1" ] + + defines = [ + "OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE=1", + "OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE=1", + "MBEDTLS_ENTROPY_HARDWARE_ALT=1", + "OPENTHREAD_PLATFORM_CORE_CONFIG_FILE=\"app/project_include/OpenThreadConfig.h\"", + ] +} + +source_set("openthread_core_config_k32w1") { + sources = [ + "${openthread_nxp_root}/src/k32w1/k32w1/openthread-core-k32w1-config-check.h", + "${openthread_nxp_root}/src/k32w1/k32w1/openthread-core-k32w1-config.h", + ] + + public_configs = [ ":openthread_k32w1_config" ] +} + +source_set("openthread_mbedtls_config_k32w1") { + sources = [ "${openthread_nxp_root}/src/k32w1/k32w1/k32w1-mbedtls-config.h" ] +} + +source_set("libopenthread-k32w1") { + sources = [ + "${openthread_nxp_root}/src/common/flash_nvm.c", + "${openthread_nxp_root}/src/k32w1/k32w1/alarm.c", + "${openthread_nxp_root}/src/k32w1/k32w1/diag.c", + "${openthread_nxp_root}/src/k32w1/k32w1/entropy.c", + "${openthread_nxp_root}/src/k32w1/k32w1/logging.c", + "${openthread_nxp_root}/src/k32w1/k32w1/misc.c", + "${openthread_nxp_root}/src/k32w1/k32w1/power.c", + "${openthread_nxp_root}/src/k32w1/k32w1/radio.c", + "${openthread_nxp_root}/src/k32w1/k32w1/system.c", + "${openthread_nxp_root}/src/k32w1/k32w1/uart.c", + ] + + if (chip_crypto == "platform") { + sources += [ "${openthread_nxp_root}/src/k32w1/k32w1/ecdsa_sss.cpp" ] + } + + if (chip_with_ot_cli == 1) { + sources += [ "${openthread_root}/examples/apps/cli/cli_uart.cpp" ] + } + + public_deps = [ + ":openthread_core_config_k32w1", + "${k32w1_sdk_build_root}:k32w1_sdk", + "${openthread_root}/src/core:libopenthread_core_headers", + "../../..:libopenthread-platform", + "../../..:libopenthread-platform-utils", + ] +}