From 0015e258725cec551324fd6fd0f62b48cc234848 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Thu, 28 Jan 2021 17:16:15 +0100 Subject: [PATCH 01/64] [nrf noup] Add Zephyr module manifest in the root directory Add Zephyr module manifest in the CHIP root directory in order to automatically pull CHIP into a project when CHIP is one of the submodules specified in west manifest. CHIP module takes all compilatinon flags associated with the zephyr_interface target and passes them to the external GN-based project. For that reason we must ensure that the Matter module is processed after other revelant modules that modify the zephyr_interface target. nrfxlib is such a module as it contains nrf_security which carries the mbedtls configuration. Signed-off-by: Damian Krolik --- zephyr/module.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 zephyr/module.yml diff --git a/zephyr/module.yml b/zephyr/module.yml new file mode 100644 index 0000000000..061408afa5 --- /dev/null +++ b/zephyr/module.yml @@ -0,0 +1,14 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +name: connectedhomeip + +build: + cmake: config/nrfconnect/chip-module + kconfig: config/nrfconnect/chip-module/Kconfig + depends: + - nrfxlib + - openthread From 0bd444b42b62fe93d59d76e48f216eed42aa73a1 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Mon, 26 Jul 2021 12:05:16 +0200 Subject: [PATCH 02/64] [nrf noup] add workflow for building CHIP tools Add a manually triggered workflow for building Android CHIPTool packages for arm and arm64 architectures, and CHIP Tool for Linux x64 and arm64. The packages are uploaded both as github artifacts and release packages (as the latter require a release tag). The doxygen workflow pushes doxygen HTML files to another branch which is undesired on the sdk-connectedhomeip fork as it causes significant growth of the repository size. Signed-off-by: Damian Krolik Signed-off-by: Kamil Kasperczyk --- .github/workflows/doxygen.yaml | 115 ----------------------- .github/workflows/release_tools.yaml | 131 +++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 115 deletions(-) delete mode 100644 .github/workflows/doxygen.yaml create mode 100644 .github/workflows/release_tools.yaml diff --git a/.github/workflows/doxygen.yaml b/.github/workflows/doxygen.yaml deleted file mode 100644 index 0497a6b062..0000000000 --- a/.github/workflows/doxygen.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) 2020 Project CHIP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Doxygen - -on: - push: - paths: - - "**.do[xc]" - - "**.c[cs]?" - - "**.cxx" - - "**.cpp" - - "**.c++" - - "**.ii" - - "**.ixx" - - "**.ipp" - - "**.i++" - - "**.inl" - - "**.[hH]" - - "**.hh" - - "**.HH" - - "**.hxx" - - "**.hpp" - - "**.h++" - - "**.mm" - - "**.txt" - - "**.[ido]dl" - - "**.java" - - "**.d" - - "**.php[45]?" - - "**.inc" - - "**.phtml" - - "**.[mM]" - pull_request: - paths: - - "**.do[xc]" - - "**.c[cs]?" - - "**.cxx" - - "**.cpp" - - "**.c++" - - "**.ii" - - "**.ixx" - - "**.ipp" - - "**.i++" - - "**.inl" - - "**.[hH]" - - "**.hh" - - "**.HH" - - "**.hxx" - - "**.hpp" - - "**.h++" - - "**.mm" - - "**.txt" - - "**.[ido]dl" - - "**.java" - - "**.d" - - "**.php[45]?" - - "**.inc" - - "**.phtml" - - "**.[mM]" - workflow_dispatch: - -concurrency: - group: ${{ github.ref }}-${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.event.number) || (github.event_name == 'workflow_dispatch' && github.run_number) || github.sha }} - cancel-in-progress: true - -jobs: - doxygen: - name: Build Doxygen - timeout-minutes: 5 - - runs-on: ubuntu-20.04 - container: - image: connectedhomeip/chip-build-doxygen:0.5.73 - - if: github.actor != 'restyled-io[bot]' - - steps: - - name: "Print Actor" - run: echo ${{github.actor}} - - uses: Wandalen/wretry.action@v1.0.15 - name: Checkout - with: - action: actions/checkout@v3 - with: | - submodules: true - token: ${{ github.token }} - attempt_limit: 3 - attempt_delay: 2000 - - name: Generate - run: scripts/helpers/doxygen.sh - - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/})" - id: extract_branch - - name: Deploy if master - if: steps.extract_branch.outputs.branch == 'master' && github.repository == 'project-chip/connectedhomeip' - uses: peaceiris/actions-gh-pages@v3 - with: - deploy_key: ${{ secrets.DOXYGEN_DEPLOY_KEY }} - external_repository: project-chip/connectedhomeip-doc - publish_dir: ./docs/html - # Keep only the latest version of the documentation - force_orphan: true diff --git a/.github/workflows/release_tools.yaml b/.github/workflows/release_tools.yaml new file mode 100644 index 0000000000..5ff07e333c --- /dev/null +++ b/.github/workflows/release_tools.yaml @@ -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. + +name: Release CHIP Tools + +on: + workflow_dispatch: + inputs: + commit: + description: "Release tag name or commit SHA:" + required: true + publishRelease: + description: "Publish release packages (if true, 'commit' must contain a release tag name):" + required: true + default: "false" + +jobs: + tools: + name: Build CHIP Tools + timeout-minutes: 60 + + runs-on: ubuntu-latest + + env: + DEBIAN_FRONTEND: noninteractive + JAVA_HOME: /usr/lib/jvm/java-8-openjdk-amd64/ + + container: + image: connectedhomeip/chip-build-android:0.5.58 + volumes: + - "/tmp/log_output:/tmp/test_logs" + - "/tmp/output_binaries:/tmp/output_binaries" + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: "${{ github.event.inputs.commit }}" + submodules: true + - name: Bootstrap + timeout-minutes: 10 + run: scripts/build/gn_bootstrap.sh + - name: Install Python CHIP Tool dependencies + timeout-minutes: 10 + run: | + echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports $(lsb_release -sc) main restricted" > /etc/apt/sources.list.d/arm64.list + echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports $(lsb_release -sc)-updates main restricted" >> /etc/apt/sources.list.d/arm64.list + apt update + apt install -y --no-install-recommends -o APT::Immediate-Configure=false g++-aarch64-linux-gnu libgirepository1.0-dev + dpkg --add-architecture arm64 + apt install -y --no-install-recommends -o APT::Immediate-Configure=false libavahi-client-dev:arm64 libglib2.0-dev:arm64 libssl-dev:arm64 + - name: Build x64 CHIP Tool with debug logs enabled + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh "gn gen out/chiptool_x64_debug --args='chip_mdns=\"platform\"'" + scripts/run_in_build_env.sh "ninja -C out/chiptool_x64_debug chip-tool" + mv out/chiptool_x64_debug/chip-tool out/chiptool_x64_debug/chip-tool-debug + - name: Build x64 CHIP Tool with debug logs disabled + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh "gn gen out/chiptool_x64_release --args='chip_mdns=\"platform\" chip_detail_logging=false'" + scripts/run_in_build_env.sh "ninja -C out/chiptool_x64_release chip-tool" + mv out/chiptool_x64_release/chip-tool out/chiptool_x64_release/chip-tool-release + - name: Build arm64 CHIP Tool with debug logs enabled + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh "gn gen out/chiptool_arm64_debug --args='chip_mdns=\"platform\" + custom_toolchain=\"//build/toolchain/custom\" + target_cc=\"aarch64-linux-gnu-gcc\" + target_cxx=\"aarch64-linux-gnu-g++\" + target_ar=\"aarch64-linux-gnu-ar\" + target_cpu=\"arm64\"'" + scripts/run_in_build_env.sh "ninja -C out/chiptool_arm64_debug chip-tool" + mv out/chiptool_arm64_debug/chip-tool out/chiptool_arm64_debug/chip-tool-debug + - name: Build arm64 CHIP Tool with debug logs disabled + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh "gn gen out/chiptool_arm64_release --args='chip_mdns=\"platform\" + chip_detail_logging=false + custom_toolchain=\"//build/toolchain/custom\" + target_cc=\"aarch64-linux-gnu-gcc\" + target_cxx=\"aarch64-linux-gnu-g++\" + target_ar=\"aarch64-linux-gnu-ar\" + target_cpu=\"arm64\"'" + scripts/run_in_build_env.sh "ninja -C out/chiptool_arm64_release chip-tool" + mv out/chiptool_arm64_release/chip-tool out/chiptool_arm64_release/chip-tool-release + - name: Create zip files for CHIP Tool debug and release packages + timeout-minutes: 10 + run: | + python3 -m zipfile -c /tmp/output_binaries/chip-tool-linux_x64.zip out/chiptool_x64_debug/chip-tool-debug out/chiptool_x64_release/chip-tool-release + python3 -m zipfile -c /tmp/output_binaries/chip-tool-linux_aarch64.zip out/chiptool_arm64_debug/chip-tool-debug out/chiptool_arm64_release/chip-tool-release + - name: Build arm Android CHIPTool + timeout-minutes: 30 + env: + TARGET_CPU: arm + run: | + scripts/run_in_build_env.sh "./scripts/build/build_examples.py --target android-arm-chip-tool build" + cp out/android-arm-chip-tool/outputs/apk/debug/app-debug.apk /tmp/output_binaries/chip-tool-android_armv7l.apk + - name: Build arm64 Android CHIPTool + timeout-minutes: 30 + env: + TARGET_CPU: arm64 + run: | + git clean -fdx src/android/CHIPTool + scripts/run_in_build_env.sh "./scripts/build/build_examples.py --target android-arm64-chip-tool build" + cp out/android-arm64-chip-tool/outputs/apk/debug/app-debug.apk /tmp/output_binaries/chip-tool-android_aarch64.apk + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: chip + path: /tmp/output_binaries/* + - name: Upload release packages + uses: softprops/action-gh-release@v1 + if: github.event.inputs.publishRelease == 'true' + with: + files: /tmp/output_binaries/* + fail_on_unmatched_files: true + tag_name: "${{ github.event.inputs.commit }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 20a01c61f06f5452af6a6ffceff05f23652a3389 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Wed, 17 Nov 2021 11:08:04 +0100 Subject: [PATCH 03/64] [nrf noup] Set nRF Connect SDK recommended version Set for CI build NCS recommended version to origin/main --- config/nrfconnect/.nrfconnect-recommended-revision | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/nrfconnect/.nrfconnect-recommended-revision b/config/nrfconnect/.nrfconnect-recommended-revision index 64f70a1911..c5387f4e1b 100644 --- a/config/nrfconnect/.nrfconnect-recommended-revision +++ b/config/nrfconnect/.nrfconnect-recommended-revision @@ -1 +1 @@ -5ea8f7fa91d7315fcc6cd9eb3aa74f9640d0abac +origin/main From f928e05d77c05bbc0c5896dfd469badc2732da30 Mon Sep 17 00:00:00 2001 From: Marcin Kajor Date: Fri, 29 Apr 2022 12:15:27 +0200 Subject: [PATCH 04/64] [nrf noup] update the Zephyr include path. Recently the Zephyr include path was changed from ${ZEPHYR_BASE}/include/posix/ to ${ZEPHYR_BASE}/include/zephyr/posix. We need to align this in Matter SDK to avoid build errors. --- config/nrfconnect/chip-module/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt index 3594022025..8f58f7dcd9 100644 --- a/config/nrfconnect/chip-module/CMakeLists.txt +++ b/config/nrfconnect/chip-module/CMakeLists.txt @@ -100,7 +100,7 @@ endif() if (CONFIG_POSIX_API) list(APPEND CHIP_CFLAGS -D_SYS__PTHREADTYPES_H_ - -isystem${ZEPHYR_BASE}/include/posix + -isystem${ZEPHYR_BASE}/include/zephyr/posix ) endif() From 7dfcc48f6db54aa5f1fca10162d8562148b7f2f6 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Wed, 11 May 2022 13:37:45 +0200 Subject: [PATCH 05/64] [nrf fromlist] Refactored OnboardingCodesUtil to decrease memory footprint. OnboardingCodesUtil uses SetupPayload object that contains a lot unnecessary data and takes a lot of flash. Replaced using SetupPayload with PayloadContents and QRCodeSetupPayloadGenerator with QRCodeBasicSetupPayloadGenerator. It allowed to save about 3.28 k of flash for nrfconnect platform. (cherry picked from commit 4175f409594d593683e3f13829988336b037b3cb) --- .../esp32/main/DeviceWithDisplay.cpp | 10 ++- examples/chef/esp32/main/main.cpp | 9 ++- examples/common/pigweed/rpc_services/Device.h | 7 +- .../light-switch-app/efr32/src/AppTask.cpp | 6 +- examples/lighting-app/efr32/src/AppTask.cpp | 6 +- examples/lock-app/efr32/src/AppTask.cpp | 6 +- .../ota-requestor-app/efr32/src/AppTask.cpp | 6 +- examples/platform/linux/AppMain.cpp | 4 +- examples/platform/linux/Options.h | 2 +- .../window-app/efr32/include/WindowAppImpl.h | 5 +- .../window-app/efr32/src/WindowAppImpl.cpp | 5 +- src/app/server/OnboardingCodesUtil.cpp | 69 ++++++++++--------- src/app/server/OnboardingCodesUtil.h | 44 ++++++++++-- src/controller/CommissioningWindowOpener.cpp | 2 +- src/lib/shell/commands/OnboardingCodes.cpp | 26 ++++--- src/setup_payload/Base38Encode.cpp | 2 + src/setup_payload/Base38Encode.h | 10 ++- .../ManualSetupPayloadGenerator.cpp | 4 ++ .../ManualSetupPayloadGenerator.h | 2 + .../QRCodeSetupPayloadGenerator.h | 2 + src/setup_payload/tests/TestQRCode.cpp | 50 +++++++++----- 21 files changed, 186 insertions(+), 91 deletions(-) diff --git a/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp b/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp index 55a77f4d3a..987a095134 100644 --- a/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp @@ -17,6 +17,7 @@ */ #include "DeviceWithDisplay.h" +#include #if CONFIG_HAVE_DISPLAY using namespace ::chip; @@ -651,8 +652,11 @@ esp_err_t InitM5Stack(std::string qrCodeText) void InitDeviceDisplay() { - std::string qrCodeText; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); + // Get QR Code and emulate its content using NFC tag GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); // Initialize the display device. @@ -681,12 +685,12 @@ void InitDeviceDisplay() #if CONFIG_DEVICE_TYPE_M5STACK - InitM5Stack(qrCodeText); + InitM5Stack(qrCodeText.data()); #elif CONFIG_DEVICE_TYPE_ESP32_WROVER_KIT // Display the QR Code - QRCodeScreen qrCodeScreen(qrCodeText); + QRCodeScreen qrCodeScreen(qrCodeText.data()); qrCodeScreen.Display(); #endif diff --git a/examples/chef/esp32/main/main.cpp b/examples/chef/esp32/main/main.cpp index 03751d641d..5fd864313c 100644 --- a/examples/chef/esp32/main/main.cpp +++ b/examples/chef/esp32/main/main.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "Display.h" #include "QRCodeScreen.h" @@ -137,7 +138,9 @@ const char * TAG = "chef-app"; #if CONFIG_HAVE_DISPLAY void printQRCode() { - std::string qrCodeText; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE)); @@ -153,8 +156,8 @@ void printQRCode() ScreenManager::Init(); ESP_LOGI(TAG, "Opening QR code screen"); - ESP_LOGI(TAG, "QR CODE Text: '%s'", qrCodeText.c_str()); - ScreenManager::PushScreen(chip::Platform::New(qrCodeText)); + ESP_LOGI(TAG, "QR CODE Text: '%s'", qrCodeText.data()); + ScreenManager::PushScreen(chip::Platform::New(qrCodeText.data())); } #endif // CONFIG_HAVE_DISPLAY diff --git a/examples/common/pigweed/rpc_services/Device.h b/examples/common/pigweed/rpc_services/Device.h index e097936552..57ef6a3275 100644 --- a/examples/common/pigweed/rpc_services/Device.h +++ b/examples/common/pigweed/rpc_services/Device.h @@ -28,6 +28,7 @@ #include "platform/ConfigurationManager.h" #include "platform/DiagnosticDataProvider.h" #include "platform/PlatformManager.h" +#include namespace chip { namespace rpc { @@ -146,10 +147,12 @@ class Device : public pw_rpc::nanopb::Device::Service snprintf(response.serial_number, sizeof(response.serial_number), CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER); } - std::string qrCodeText; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCodeText(qrCodeBuffer); if (GetQRCode(qrCodeText, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - snprintf(response.pairing_info.qr_code, sizeof(response.pairing_info.qr_code), "%s", qrCodeText.c_str()); + snprintf(response.pairing_info.qr_code, sizeof(response.pairing_info.qr_code), "%s", qrCodeText.data()); GetQRCodeUrl(response.pairing_info.qr_code_url, sizeof(response.pairing_info.qr_code_url), qrCodeText); response.has_pairing_info = true; } diff --git a/examples/light-switch-app/efr32/src/AppTask.cpp b/examples/light-switch-app/efr32/src/AppTask.cpp index ea6ce7073e..0de6074a6e 100644 --- a/examples/light-switch-app/efr32/src/AppTask.cpp +++ b/examples/light-switch-app/efr32/src/AppTask.cpp @@ -239,11 +239,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/lighting-app/efr32/src/AppTask.cpp b/examples/lighting-app/efr32/src/AppTask.cpp index c61198b695..d9c5de9bc7 100644 --- a/examples/lighting-app/efr32/src/AppTask.cpp +++ b/examples/lighting-app/efr32/src/AppTask.cpp @@ -283,11 +283,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/lock-app/efr32/src/AppTask.cpp b/examples/lock-app/efr32/src/AppTask.cpp index 066d570411..18da28e917 100644 --- a/examples/lock-app/efr32/src/AppTask.cpp +++ b/examples/lock-app/efr32/src/AppTask.cpp @@ -274,11 +274,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/ota-requestor-app/efr32/src/AppTask.cpp b/examples/ota-requestor-app/efr32/src/AppTask.cpp index 558db22f18..e3255f3eac 100644 --- a/examples/ota-requestor-app/efr32/src/AppTask.cpp +++ b/examples/ota-requestor-app/efr32/src/AppTask.cpp @@ -170,11 +170,13 @@ CHIP_ERROR AppTask::Init() // Print setup info on LCD if available #ifdef DISPLAY_ENABLED - std::string QRCode; + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) QRCode.c_str()); + LCDWriteQRCode((uint8_t *) QRCode.data()); } else { diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index aa5a1622e9..83f867f9cd 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -241,7 +241,7 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions) LinuxDeviceOptions::GetInstance()); SuccessOrExit(err); - err = GetSetupPayload(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags); + err = GetPayloadContents(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags); SuccessOrExit(err); ConfigurationMgr().LogDeviceConfig(); @@ -254,7 +254,7 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions) { // For testing of manual pairing code with custom commissioning flow ChipLogProgress(NotSpecified, "==== Onboarding payload for Custom Commissioning Flows ===="); - err = GetSetupPayload(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags); + err = GetPayloadContents(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags); SuccessOrExit(err); LinuxDeviceOptions::GetInstance().payload.commissioningFlow = chip::CommissioningFlow::kCustom; diff --git a/examples/platform/linux/Options.h b/examples/platform/linux/Options.h index 9b46d82874..4f55f6f7f5 100644 --- a/examples/platform/linux/Options.h +++ b/examples/platform/linux/Options.h @@ -38,7 +38,7 @@ struct LinuxDeviceOptions { - chip::SetupPayload payload; + chip::PayloadContents payload; chip::Optional discriminator; chip::Optional> spake2pVerifier; chip::Optional> spake2pSalt; diff --git a/examples/window-app/efr32/include/WindowAppImpl.h b/examples/window-app/efr32/include/WindowAppImpl.h index 7c03131955..a052838add 100644 --- a/examples/window-app/efr32/include/WindowAppImpl.h +++ b/examples/window-app/efr32/include/WindowAppImpl.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,9 @@ class WindowAppImpl : public WindowApp QueueHandle_t mQueue = nullptr; LEDWidget mStatusLED; LEDWidget mActionLED; - std::string mQRCode; + + // Get QR Code and emulate its content using NFC tag + char mQRCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; Timer mIconTimer; LcdIcon mIcon = LcdIcon::None; }; diff --git a/examples/window-app/efr32/src/WindowAppImpl.cpp b/examples/window-app/efr32/src/WindowAppImpl.cpp index 5cfc4b6206..2330bade5d 100644 --- a/examples/window-app/efr32/src/WindowAppImpl.cpp +++ b/examples/window-app/efr32/src/WindowAppImpl.cpp @@ -433,9 +433,10 @@ void WindowAppImpl::UpdateLCD() #ifdef QR_CODE_ENABLED else { - if (GetQRCode(mQRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) + chip::MutableCharSpan qrCode(mQRCodeBuffer); + if (GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) { - LCDWriteQRCode((uint8_t *) mQRCode.c_str()); + LCDWriteQRCode((uint8_t *) qrCode.data()); } } #endif // QR_CODE_ENABLED diff --git a/src/app/server/OnboardingCodesUtil.cpp b/src/app/server/OnboardingCodesUtil.cpp index 9cfd99999f..28451e207d 100644 --- a/src/app/server/OnboardingCodesUtil.cpp +++ b/src/app/server/OnboardingCodesUtil.cpp @@ -37,21 +37,21 @@ using namespace ::chip::DeviceLayer; void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags) { - chip::SetupPayload payload; + chip::PayloadContents payload; - CHIP_ERROR err = GetSetupPayload(payload, aRendezvousFlags); + CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags); if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)); + ChipLogError(AppServer, "GetPayloadContents() failed: %s", chip::ErrorStr(err)); } PrintOnboardingCodes(payload); } -void PrintOnboardingCodes(const chip::SetupPayload & payload) +void PrintOnboardingCodes(const chip::PayloadContents & payload) { - std::string qrCode; - std::string manualPairingCode; + char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCode(payloadBuffer); if (GetQRCode(qrCode, payload) == CHIP_NO_ERROR) { @@ -59,7 +59,7 @@ void PrintOnboardingCodes(const chip::SetupPayload & payload) const size_t qrCodeBufferMaxSize = strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + 3 * qrCode.size() + 1; qrCodeBuffer.Alloc(qrCodeBufferMaxSize); - ChipLogProgress(AppServer, "SetupQRCode: [%s]", qrCode.c_str()); + ChipLogProgress(AppServer, "SetupQRCode: [%s]", qrCode.data()); if (GetQRCodeUrl(qrCodeBuffer.Get(), qrCodeBufferMaxSize, qrCode) == CHIP_NO_ERROR) { ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:"); @@ -71,9 +71,10 @@ void PrintOnboardingCodes(const chip::SetupPayload & payload) ChipLogError(AppServer, "Getting QR code failed!"); } + chip::MutableCharSpan manualPairingCode(payloadBuffer); if (GetManualPairingCode(manualPairingCode, payload) == CHIP_NO_ERROR) { - ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.c_str()); + ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.data()); } else { @@ -85,47 +86,49 @@ void PrintOnboardingCodes(const chip::SetupPayload & payload) void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags) { // Get QR Code and emulate its content using NFC tag - std::string qrCode; + char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCode(payloadBuffer); + ReturnOnFailure(GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE))); - ReturnOnFailure(NFCMgr().StartTagEmulation(qrCode.c_str(), qrCode.size())); + ReturnOnFailure(NFCMgr().StartTagEmulation(qrCode.data(), qrCode.size())); } #endif -CHIP_ERROR GetSetupPayload(chip::SetupPayload & aSetupPayload, chip::RendezvousInformationFlags aRendezvousFlags) +CHIP_ERROR GetPayloadContents(chip::PayloadContents & aPayload, chip::RendezvousInformationFlags aRendezvousFlags) { - CHIP_ERROR err = CHIP_NO_ERROR; - aSetupPayload.version = 0; - aSetupPayload.rendezvousInformation = aRendezvousFlags; + CHIP_ERROR err = CHIP_NO_ERROR; + aPayload.version = 0; + aPayload.rendezvousInformation = aRendezvousFlags; - err = GetCommissionableDataProvider()->GetSetupPasscode(aSetupPayload.setUpPINCode); + err = GetCommissionableDataProvider()->GetSetupPasscode(aPayload.setUpPINCode); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "GetCommissionableDataProvider()->GetSetupPasscode() failed: %s", chip::ErrorStr(err)); #if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE ChipLogProgress(AppServer, "*** Using default EXAMPLE passcode %u ***", static_cast(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE)); - aSetupPayload.setUpPINCode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE; + aPayload.setUpPINCode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE; #else return err; #endif } - err = GetCommissionableDataProvider()->GetSetupDiscriminator(aSetupPayload.discriminator); + err = GetCommissionableDataProvider()->GetSetupDiscriminator(aPayload.discriminator); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "GetCommissionableDataProvider()->GetSetupDiscriminator() failed: %s", chip::ErrorStr(err)); return err; } - err = ConfigurationMgr().GetVendorId(aSetupPayload.vendorID); + err = ConfigurationMgr().GetVendorId(aPayload.vendorID); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err)); return err; } - err = ConfigurationMgr().GetProductId(aSetupPayload.productID); + err = ConfigurationMgr().GetProductId(aPayload.productID); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "ConfigurationMgr().GetProductId() failed: %s", chip::ErrorStr(err)); @@ -135,25 +138,23 @@ CHIP_ERROR GetSetupPayload(chip::SetupPayload & aSetupPayload, chip::RendezvousI return err; } -CHIP_ERROR GetQRCode(std::string & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags) +CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags) { - chip::SetupPayload payload; + chip::PayloadContents payload; - CHIP_ERROR err = GetSetupPayload(payload, aRendezvousFlags); + CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags); if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)); + ChipLogError(AppServer, "GetPayloadContents() failed: %s", chip::ErrorStr(err)); return err; } return GetQRCode(aQRCode, payload); } -CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload) +CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContents & payload) { - // TODO: Usage of STL will significantly increase the image size, this should be changed to more efficient method for - // generating payload - CHIP_ERROR err = chip::QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode); + CHIP_ERROR err = chip::QRCodeBasicSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "Generating QR Code failed: %s", chip::ErrorStr(err)); @@ -163,7 +164,7 @@ CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload) return CHIP_NO_ERROR; } -CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string & aQRCode) +CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const chip::CharSpan & aQRCode) { VerifyOrReturnError(aQRCodeUrl, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(aUrlMaxSize >= (strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + aQRCode.size() + 1), @@ -173,24 +174,24 @@ CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string VerifyOrReturnError((writtenDataSize > 0) && (static_cast(writtenDataSize) < aUrlMaxSize), CHIP_ERROR_INVALID_STRING_LENGTH); - return EncodeQRCodeToUrl(aQRCode.c_str(), aQRCode.size(), aQRCodeUrl + writtenDataSize, + return EncodeQRCodeToUrl(aQRCode.data(), aQRCode.size(), aQRCodeUrl + writtenDataSize, aUrlMaxSize - static_cast(writtenDataSize)); } -CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags) +CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags) { - chip::SetupPayload payload; + chip::PayloadContents payload; - CHIP_ERROR err = GetSetupPayload(payload, aRendezvousFlags); + CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags); if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)); + ChipLogError(AppServer, "GetPayloadContents() failed: %s", chip::ErrorStr(err)); return err; } return GetManualPairingCode(aManualPairingCode, payload); } -CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, const chip::SetupPayload & payload) +CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, const chip::PayloadContents & payload) { CHIP_ERROR err = chip::ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(aManualPairingCode); if (err != CHIP_NO_ERROR) diff --git a/src/app/server/OnboardingCodesUtil.h b/src/app/server/OnboardingCodesUtil.h index e586b852c1..78d170c084 100644 --- a/src/app/server/OnboardingCodesUtil.h +++ b/src/app/server/OnboardingCodesUtil.h @@ -17,17 +17,47 @@ #pragma once +#include #include void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags); -void PrintOnboardingCodes(const chip::SetupPayload & payload); +void PrintOnboardingCodes(const chip::PayloadContents & payload); void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags); -CHIP_ERROR GetQRCode(std::string & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags); -CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload); -CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string & aQRCode); -CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags); -CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, const chip::SetupPayload & payload); -CHIP_ERROR GetSetupPayload(chip::SetupPayload & aSetupPayload, chip::RendezvousInformationFlags aRendezvousFlags); + +/** + * Creates a null-terminated QR code from the payload created based on rendezvous flag information. + * + * The resulting size of the QR code span will be the size of data written and not including the null terminator. + */ +CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags); + +/** + * Creates a null-terminated QR code based on the provided payload. + * + * The resulting size of the QR code span will be the size of data written and not including the null terminator. + */ +CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContents & payload); + +/** + * Creates a null-terminated QR code url. + */ +CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const chip::CharSpan & aQRCode); + +/** + * Creates a null-terminated manual pairing code from the payload created based on rendezvous flag information. + * + * The resulting size of the manual pairing code span will be the size of data written and not including the null terminator. + */ +CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags); + +/** + * Creates a null-terminated manual pairing code based on the provided payload. + * + * The resulting size of the manual pairing code span will be the size of data written and not including the null terminator. + */ +CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, const chip::PayloadContents & payload); + +CHIP_ERROR GetPayloadContents(chip::PayloadContents & aPayload, chip::RendezvousInformationFlags aRendezvousFlags); /** * Initialize DataModelHandler and start CHIP datamodel server, the server diff --git a/src/controller/CommissioningWindowOpener.cpp b/src/controller/CommissioningWindowOpener.cpp index 9ff1c486ee..a6127d3a29 100644 --- a/src/controller/CommissioningWindowOpener.cpp +++ b/src/controller/CommissioningWindowOpener.cpp @@ -144,7 +144,7 @@ CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindowInternal(Operationa ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenCommissioningWindowSuccess, OnOpenCommissioningWindowFailure, MakeOptional(kTimedInvokeTimeoutMs))); - char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength]; + char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; MutableCharSpan manualCode(payloadBuffer); ReturnErrorOnFailure(ManualSetupPayloadGenerator(mSetupPayload).payloadDecimalStringRepresentation(manualCode)); diff --git a/src/lib/shell/commands/OnboardingCodes.cpp b/src/lib/shell/commands/OnboardingCodes.cpp index 3acb3a4e65..1ecb791904 100644 --- a/src/lib/shell/commands/OnboardingCodes.cpp +++ b/src/lib/shell/commands/OnboardingCodes.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #define CHIP_SHELL_MAX_BUFFER_SIZE 128 @@ -36,21 +37,27 @@ namespace Shell { static CHIP_ERROR GetOnboardingQRCode(bool printHeader, chip::RendezvousInformationFlags aRendezvousFlags) { streamer_t * sout = streamer_get(); - std::string QRCode; + + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (printHeader) { streamer_printf(sout, "QRCode: "); } ReturnErrorOnFailure(GetQRCode(QRCode, aRendezvousFlags)); - streamer_printf(sout, "%s\r\n", QRCode.c_str()); + streamer_printf(sout, "%s\r\n", QRCode.data()); return CHIP_NO_ERROR; } static CHIP_ERROR GetOnboardingQRCodeUrl(bool printHeader, chip::RendezvousInformationFlags aRendezvousFlags) { streamer_t * sout = streamer_get(); - std::string QRCode; + + // Create buffer for QR code that can fit max size and null terminator. + char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan QRCode(qrCodeBuffer); if (printHeader) { @@ -58,24 +65,27 @@ static CHIP_ERROR GetOnboardingQRCodeUrl(bool printHeader, chip::RendezvousInfor } ReturnErrorOnFailure(GetQRCode(QRCode, aRendezvousFlags)); - char qrCodeBuffer[CHIP_SHELL_MAX_BUFFER_SIZE]; + char qrCodeUrlBuffer[CHIP_SHELL_MAX_BUFFER_SIZE]; - ReturnErrorOnFailure(GetQRCodeUrl(qrCodeBuffer, sizeof(qrCodeBuffer), QRCode)); - streamer_printf(sout, "%s\r\n", qrCodeBuffer); + ReturnErrorOnFailure(GetQRCodeUrl(qrCodeUrlBuffer, sizeof(qrCodeUrlBuffer), QRCode)); + streamer_printf(sout, "%s\r\n", qrCodeUrlBuffer); return CHIP_NO_ERROR; } static CHIP_ERROR GetOnboardingManualPairingCode(bool printHeader, chip::RendezvousInformationFlags aRendezvousFlags) { streamer_t * sout = streamer_get(); - std::string manualPairingCode; + + // Create buffer for manual pariting code that can fit max size + check digit + null terminator. + char manualPairingCodeBuffer[chip::kManualSetupLongCodeCharLength + 1]; + chip::MutableCharSpan manualPairingCode(manualPairingCodeBuffer); if (printHeader) { streamer_printf(sout, "ManualPairingCode: "); } ReturnErrorOnFailure(GetManualPairingCode(manualPairingCode, aRendezvousFlags)); - streamer_printf(sout, "%s\r\n", manualPairingCode.c_str()); + streamer_printf(sout, "%s\r\n", manualPairingCode.data()); return CHIP_NO_ERROR; } diff --git a/src/setup_payload/Base38Encode.cpp b/src/setup_payload/Base38Encode.cpp index f00f4b5460..5e663d23be 100644 --- a/src/setup_payload/Base38Encode.cpp +++ b/src/setup_payload/Base38Encode.cpp @@ -81,6 +81,8 @@ CHIP_ERROR base38Encode(ByteSpan in_buf, MutableCharSpan & out_buf) if (out_idx < out_buf.size()) { out_buf.data()[out_idx] = '\0'; + // Reduce output span size to be the size of written data and to not include null-terminator. + out_buf.reduce_size(out_idx); } else { diff --git a/src/setup_payload/Base38Encode.h b/src/setup_payload/Base38Encode.h index 05d4f901e9..a6df4592cb 100644 --- a/src/setup_payload/Base38Encode.h +++ b/src/setup_payload/Base38Encode.h @@ -25,10 +25,16 @@ namespace chip { -// out_buf is null-terminated on success +/* + * The out_buf is null-terminated on success. + * + * The resulting size of the out_buf span will be the size of data written and not including the null terminator. + */ CHIP_ERROR base38Encode(ByteSpan in_buf, MutableCharSpan & out_buf); -// returns size needed to store encoded string given number of input bytes +/* + * Returns size needed to store encoded string given number of input bytes including null terminator. + */ size_t base38EncodedLength(size_t num_bytes); } // namespace chip diff --git a/src/setup_payload/ManualSetupPayloadGenerator.cpp b/src/setup_payload/ManualSetupPayloadGenerator.cpp index a1e26dbcb9..25ffa738e9 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.cpp +++ b/src/setup_payload/ManualSetupPayloadGenerator.cpp @@ -151,6 +151,10 @@ CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(Mutab int checkDigit = Verhoeff10::CharToVal(Verhoeff10::ComputeCheckChar(outBuffer.data())); ReturnErrorOnFailure(decimalStringWithPadding(outBuffer.SubSpan(offset, 2), static_cast(checkDigit))); + offset += 1; + + // Reduce outBuffer span size to be the size of written data and to not include null-terminator. + outBuffer.reduce_size(offset); return CHIP_NO_ERROR; } diff --git a/src/setup_payload/ManualSetupPayloadGenerator.h b/src/setup_payload/ManualSetupPayloadGenerator.h index bb04735f1b..7a73e0c3a2 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.h +++ b/src/setup_payload/ManualSetupPayloadGenerator.h @@ -58,6 +58,8 @@ class ManualSetupPayloadGenerator * This function is called to encode the binary data of a payload to a * decimal null-terminated string. * + * The resulting size of the outBuffer will be the size of data written and not including the null terminator. + * * @param[out] outBuffer * Output buffer to write the decimal string. * diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.h b/src/setup_payload/QRCodeSetupPayloadGenerator.h index c82aaa6ac7..7d79e67ced 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.h +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.h @@ -112,6 +112,8 @@ class QRCodeBasicSetupPayloadGenerator * This function is called to encode the binary data of a payload to a * base38 null-terminated string. * + * The resulting size of the out_buf span will be the size of data written and not including the null terminator. + * * @param[out] outBuffer * The buffer to copy the base38 to. * diff --git a/src/setup_payload/tests/TestQRCode.cpp b/src/setup_payload/tests/TestQRCode.cpp index c39dbd773a..1920f8f902 100644 --- a/src/setup_payload/tests/TestQRCode.cpp +++ b/src/setup_payload/tests/TestQRCode.cpp @@ -119,21 +119,25 @@ void TestPayloadBase38Rep(nlTestSuite * inSuite, void * inContext) void TestBase38(nlTestSuite * inSuite, void * inContext) { uint8_t input[3] = { 10, 10, 10 }; - char encodedBuf[32]; + char encodedBuf[64]; MutableByteSpan inputSpan(input); MutableCharSpan encodedSpan(encodedBuf); // basic stuff base38Encode(inputSpan.SubSpan(0, 0), encodedSpan); NL_TEST_ASSERT(inSuite, strlen(encodedBuf) == 0); + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan.SubSpan(0, 1), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "A0") == 0); + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan.SubSpan(0, 2), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "OT10") == 0); + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "-N.B0") == 0); // test null termination of output buffer + encodedSpan = MutableCharSpan(encodedBuf); MutableCharSpan subSpan = encodedSpan.SubSpan(0, 2); NL_TEST_ASSERT(inSuite, base38Encode(inputSpan.SubSpan(0, 1), subSpan) == CHIP_ERROR_BUFFER_TOO_SMALL); // Force no nulls in output buffer @@ -146,60 +150,72 @@ void TestBase38(nlTestSuite * inSuite, void * inContext) // passing empty parameters MutableCharSpan emptySpan; + encodedSpan = MutableCharSpan(encodedBuf); NL_TEST_ASSERT(inSuite, base38Encode(inputSpan, emptySpan) == CHIP_ERROR_BUFFER_TOO_SMALL); base38Encode(MutableByteSpan(), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "") == 0); NL_TEST_ASSERT(inSuite, base38Encode(MutableByteSpan(), emptySpan) == CHIP_ERROR_BUFFER_TOO_SMALL); // test single odd byte corner conditions - input[2] = 0; + encodedSpan = MutableCharSpan(encodedBuf); + input[2] = 0; base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "OT100") == 0); - input[2] = 40; + input[2] = 40; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "Y6V91") == 0); - input[2] = 41; + input[2] = 41; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "KL0B1") == 0); - input[2] = 255; + input[2] = 255; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "Q-M08") == 0); // verify chunks of 1,2 and 3 bytes result in fixed-length strings padded with '0' // for 1 byte we need always 2 characters - input[0] = 35; + input[0] = 35; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan.SubSpan(0, 1), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "Z0") == 0); // for 2 bytes we need always 4 characters - input[0] = 255; - input[1] = 0; + input[0] = 255; + input[1] = 0; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan.SubSpan(0, 2), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "R600") == 0); // for 3 bytes we need always 5 characters - input[0] = 46; - input[1] = 0; - input[2] = 0; + input[0] = 46; + input[1] = 0; + input[2] = 0; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "81000") == 0); // verify maximum available values for each chunk size to check selecting proper characters number // for 1 byte we need 2 characters - input[0] = 255; + input[0] = 255; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan.SubSpan(0, 1), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "R6") == 0); // for 2 bytes we need 4 characters - input[0] = 255; - input[1] = 255; + input[0] = 255; + input[1] = 255; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan.SubSpan(0, 2), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "NE71") == 0); // for 3 bytes we need 5 characters - input[0] = 255; - input[1] = 255; - input[2] = 255; + input[0] = 255; + input[1] = 255; + input[2] = 255; + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(inputSpan, encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "PLS18") == 0); // fun with strings + encodedSpan = MutableCharSpan(encodedBuf); base38Encode(ByteSpan((uint8_t *) "Hello World!", sizeof("Hello World!") - 1), encodedSpan); NL_TEST_ASSERT(inSuite, strcmp(encodedBuf, "KKHF3W2S013OPM3EJX11") == 0); From 3662b7268ad86264e7543e64ffd6297aaa8ab49d Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Mon, 16 May 2022 13:17:13 +0200 Subject: [PATCH 06/64] [nrf fromlist] [zephyr] Fix realtime clock I applied a code review comment only partially and forgot to remove the multiplication. (cherry picked from commit f45e998b9d9c719107f6fb3bf4a02eb5f3aa18c4) --- src/platform/Zephyr/SystemTimeSupport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/Zephyr/SystemTimeSupport.cpp b/src/platform/Zephyr/SystemTimeSupport.cpp index 37f50b8651..3e847e1763 100644 --- a/src/platform/Zephyr/SystemTimeSupport.cpp +++ b/src/platform/Zephyr/SystemTimeSupport.cpp @@ -44,9 +44,9 @@ namespace { // Last known UTC time in Unix format. #ifdef CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_UNIX_TIME -Microseconds64 gRealTime = Seconds64(CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_UNIX_TIME * UINT64_C(1000000)); +Microseconds64 gRealTime = Seconds64(CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_UNIX_TIME); #else -Microseconds64 gRealTime = Seconds64(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD * UINT64_C(1000000)); +Microseconds64 gRealTime = Seconds64(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD); #endif // Monotonic time of setting the last known UTC time. From ad3feac4f5689c4b6fc35bc5072e658b5e8f828e Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Tue, 17 May 2022 10:43:54 +0200 Subject: [PATCH 07/64] [nrf noup] Fixed relative reference in documentation. --- docs/guides/chip_tool_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/chip_tool_guide.md b/docs/guides/chip_tool_guide.md index a516faef4a..60e100506f 100644 --- a/docs/guides/chip_tool_guide.md +++ b/docs/guides/chip_tool_guide.md @@ -676,7 +676,7 @@ rm -fr /tmp/chip_* ``` Developer details on how the test suite is structured can be found -[here](../../src/app/tests/suites/README.md). +[here](https://github.com/project-chip/connectedhomeip/blob/master/src/app/tests/suites/README.md). ### Parsing the setup payload From 4f5cc9988497355d297f82e70a56c111d0074ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Audun=20Kvamtr=C3=B8?= Date: Fri, 13 May 2022 14:24:52 +0200 Subject: [PATCH 08/64] [nrf noup] matter: Update default for matter to enable nrf_oberon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Fix hash size issue (grew from 240 to 244 bytes) -Changing default to disable PSA Crypto driver for nrf_cc3xx as it is not in use yet -Removed CC3XX_BACKEND configuration from defaults ref: NCSDK-13857 Signed-off-by: Frank Audun Kvamtrø --- config/nrfconnect/chip-module/Kconfig.defaults | 6 +++--- src/platform/nrfconnect/CHIPPlatformConfig.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/nrfconnect/chip-module/Kconfig.defaults b/config/nrfconnect/chip-module/Kconfig.defaults index 73216d9dbf..7166084b67 100644 --- a/config/nrfconnect/chip-module/Kconfig.defaults +++ b/config/nrfconnect/chip-module/Kconfig.defaults @@ -202,9 +202,9 @@ choice OPENTHREAD_SECURITY default OPENTHREAD_NRF_SECURITY_CHOICE endchoice -config CC3XX_BACKEND - bool - default n +config PSA_CRYPTO_DRIVER_CC3XX + bool + default n config OBERON_BACKEND bool diff --git a/src/platform/nrfconnect/CHIPPlatformConfig.h b/src/platform/nrfconnect/CHIPPlatformConfig.h index b34fc5ab5f..4d8bc0371a 100644 --- a/src/platform/nrfconnect/CHIPPlatformConfig.h +++ b/src/platform/nrfconnect/CHIPPlatformConfig.h @@ -37,7 +37,7 @@ // Size of the statically allocated context for SHA256 operations in CryptoPAL // determined empirically. #ifdef CONFIG_CC3XX_BACKEND -#define CHIP_CONFIG_SHA256_CONTEXT_SIZE 240 +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE 244 #else #define CHIP_CONFIG_SHA256_CONTEXT_SIZE 208 #endif From a79fe42372604271a3f25476b57b7230a5d18cbd Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Tue, 17 May 2022 13:51:42 +0200 Subject: [PATCH 09/64] [nrf noup] Moved putting QSPI to sleep after OTA requestor init Fixed bug observed on nRF53 SED that ends with assert due to not initialized QSPI during OTA Requestor init. --- .../nrfconnect/OTAImageProcessorImpl.cpp | 44 +++++++------------ .../nrfconnect/OTAImageProcessorImpl.h | 40 +++++++---------- 2 files changed, 33 insertions(+), 51 deletions(-) diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index 90924b9649..26eaab23d5 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -36,6 +36,8 @@ CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() { VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE); + TriggerFlashAction(FlashHandler::Action::WAKE_UP); + return DeviceLayer::SystemLayer().ScheduleLambda([this] { mDownloader->OnPreparedForDownload(PrepareDownloadImpl()); }); } @@ -55,7 +57,10 @@ CHIP_ERROR OTAImageProcessorImpl::Finalize() CHIP_ERROR OTAImageProcessorImpl::Abort() { - return System::MapErrorZephyr(dfu_target_reset()); + CHIP_ERROR error = System::MapErrorZephyr(dfu_target_reset()); + + TriggerFlashAction(FlashHandler::Action::SLEEP); + return error; } CHIP_ERROR OTAImageProcessorImpl::Apply() @@ -67,6 +72,8 @@ CHIP_ERROR OTAImageProcessorImpl::Apply() err = dfu_target_schedule_update(-1); } + TriggerFlashAction(FlashHandler::Action::SLEEP); + #ifdef CONFIG_CHIP_OTA_REQUESTOR_REBOOT_ON_APPLY if (!err) { @@ -206,8 +213,16 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & aBlock) return CHIP_NO_ERROR; } +void OTAImageProcessorImpl::TriggerFlashAction(FlashHandler::Action action) +{ + if (mFlashHandler) + { + mFlashHandler->DoAction(action); + } +} + // external flash power consumption optimization -void ExtFlashHandler::DoAction(Action aAction) +void FlashHandler::DoAction(Action aAction) { #if CONFIG_PM_DEVICE && CONFIG_NORDIC_QSPI_NOR && !CONFIG_SOC_NRF52840 // nRF52 is optimized per default // utilize the QSPI driver sleep power mode @@ -220,30 +235,5 @@ void ExtFlashHandler::DoAction(Action aAction) #endif } -OTAImageProcessorImplPMDevice::OTAImageProcessorImplPMDevice(ExtFlashHandler & aHandler) : mHandler(aHandler) -{ - mHandler.DoAction(ExtFlashHandler::Action::SLEEP); -} - -CHIP_ERROR OTAImageProcessorImplPMDevice::PrepareDownload() -{ - mHandler.DoAction(ExtFlashHandler::Action::WAKE_UP); - return OTAImageProcessorImpl::PrepareDownload(); -} - -CHIP_ERROR OTAImageProcessorImplPMDevice::Abort() -{ - auto status = OTAImageProcessorImpl::Abort(); - mHandler.DoAction(ExtFlashHandler::Action::SLEEP); - return status; -} - -CHIP_ERROR OTAImageProcessorImplPMDevice::Apply() -{ - auto status = OTAImageProcessorImpl::Apply(); - mHandler.DoAction(ExtFlashHandler::Action::SLEEP); - return status; -} - } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.h b/src/platform/nrfconnect/OTAImageProcessorImpl.h index 8965c4d541..59529c49a1 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.h +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.h @@ -27,11 +27,25 @@ class OTADownloader; namespace DeviceLayer { +class FlashHandler +{ +public: + enum class Action : uint8_t + { + WAKE_UP, + SLEEP + }; + virtual ~FlashHandler() {} + virtual void DoAction(Action aAction); +}; + class OTAImageProcessorImpl : public OTAImageProcessorInterface { public: static constexpr size_t kBufferSize = CONFIG_CHIP_OTA_REQUESTOR_BUFFER_SIZE; + OTAImageProcessorImpl(FlashHandler * flashHandler = nullptr) : mFlashHandler(flashHandler){}; + enum class ImageType : uint8_t { kAppImage = 0, @@ -54,6 +68,7 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface CHIP_ERROR ProcessBlock(ByteSpan & aBlock) override; bool IsFirstImageRun() override; CHIP_ERROR ConfirmCurrentImage() override; + void TriggerFlashAction(FlashHandler::Action action); private: CHIP_ERROR PrepareDownloadImpl(); @@ -66,30 +81,7 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface uint8_t mBuffer[kBufferSize]; OTAImageContentHeader mContentHeader; OTAImage mCurrentImage; -}; - -class ExtFlashHandler -{ -public: - enum class Action : uint8_t - { - WAKE_UP, - SLEEP - }; - virtual ~ExtFlashHandler() {} - virtual void DoAction(Action aAction); -}; - -class OTAImageProcessorImplPMDevice : public OTAImageProcessorImpl -{ -public: - explicit OTAImageProcessorImplPMDevice(ExtFlashHandler & aHandler); - CHIP_ERROR PrepareDownload() override; - CHIP_ERROR Abort() override; - CHIP_ERROR Apply() override; - -private: - ExtFlashHandler & mHandler; + FlashHandler * mFlashHandler; }; } // namespace DeviceLayer From 034992be27a90e794417ae46a304f716d4a5a012 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Thu, 19 May 2022 08:40:57 +0200 Subject: [PATCH 10/64] [nrf fromlist][setup_payload] Fixed bug with not reducing span size properly Output buffer span is not reduced properly, as subspan is passed to the base38Encode method and changed size doesn't propagate to the outBuffer. Added reducing outBuffer size to the subSpan + prefixLen size. --- src/setup_payload/QRCodeSetupPayloadGenerator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp index c8e7dc7fc1..976e443afa 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp @@ -196,6 +196,8 @@ static CHIP_ERROR payloadBase38RepresentationWithTLV(PayloadContents & payload, MutableCharSpan subSpan = outBuffer.SubSpan(prefixLen, outBuffer.size() - prefixLen); memcpy(outBuffer.data(), kQRCodePrefix, prefixLen); err = base38Encode(bits, subSpan); + // Reduce output span size to be the size of written data + outBuffer.reduce_size(subSpan.size() + prefixLen); } return err; From 5547a6e1084f3ff4be7b8855538cdba70e3242df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Kr=C3=B3lik?= <66667989+Damian-Nordic@users.noreply.github.com> Date: Tue, 17 May 2022 17:40:56 +0200 Subject: [PATCH 11/64] [nrf fromtree] [opcreds] Fix LEAVE event on RemoveFabric (#18434) * [opcreds] Fix LEAVE event on RemoveFabric LEAVE event is not emitted on RemoveFabric or factory reset. There are two reasons for that: - Removing a fabric causes closing all active ReadHandlers for a given fabric, so we must flush the event log before that happens. - There are two listeners for removing a fabric; the one that removes ACLs for a given fabric index is executed prior to the other one that generates LEAVE event. That causes "Accces control: denied" error. Fix both issues. * Add comment (cherry picked from commit d016401e551c35c9eb1d14bed6b5cb129c656a86) --- .../operational-credentials-server.cpp | 23 +++++++++++++++++-- src/app/server/Server.h | 15 ------------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp index 7c02d23d37..2f08e8ddd5 100644 --- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp +++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp @@ -364,8 +364,7 @@ class OpCredsFabricTableDelegate : public FabricTableDelegate static_cast(fabricIndex)); fabricListChanged(); - // The Leave event SHOULD be emitted by a Node prior to permanently - // leaving the Fabric. + // The Leave event SHOULD be emitted by a Node prior to permanently leaving the Fabric. for (auto endpoint : EnabledEndpointsWithServerCluster(Basic::Id)) { // If Basic cluster is implemented on this endpoint @@ -377,6 +376,26 @@ class OpCredsFabricTableDelegate : public FabricTableDelegate ChipLogError(Zcl, "OpCredsFabricTableDelegate: Failed to record Leave event"); } } + + // Try to send the queued events as soon as possible. If the just emitted leave event won't + // be sent this time, it will likely not be delivered at all for the following reasons: + // - removing the fabric expires all associated ReadHandlers, so all subscriptions to + // the leave event will be cancelled. + // - removing the fabric removes all associated access control entries, so generating + // subsequent reports containing the leave event will fail the access control check. + InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleUrgentEventDeliverySync(); + EventManagement::GetInstance().FabricRemoved(fabricIndex); + + // Remove access control entries in reverse order (it could be any order, but reverse order + // will cause less churn in persistent storage). + size_t aclCount = 0; + if (Access::GetAccessControl().GetEntryCount(fabricIndex, aclCount) == CHIP_NO_ERROR) + { + while (aclCount) + { + (void) Access::GetAccessControl().DeleteEntry(nullptr, fabricIndex, --aclCount); + } + } } // Gets called when a fabric is loaded into the FabricTable from storage diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 86d5114e18..aca60a7833 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -314,21 +314,6 @@ class Server { groupDataProvider->RemoveFabric(fabricIndex); } - - { - // Remove access control entries in reverse order. (It could be - // any order, but reverse order will cause less churn in - // persistent storage.) - size_t count = 0; - if (Access::GetAccessControl().GetEntryCount(fabricIndex, count) == CHIP_NO_ERROR) - { - while (count) - { - Access::GetAccessControl().DeleteEntry(nullptr, fabricIndex, --count); - } - } - } - app::EventManagement::GetInstance().FabricRemoved(fabricIndex); }; void OnFabricRetrievedFromStorage(FabricInfo * fabricInfo) override { (void) fabricInfo; } From d492ce75b2a12433fa73937dbc838e0dfcda5604 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Thu, 19 May 2022 13:17:17 +0200 Subject: [PATCH 12/64] [nrf fromlist] [nrfconnect] Minor OTA Requestor fixes 1. Increase the default sleep time between emitting the shutdown event and rebooting the device to apply a new image. That is to increase chances of delivering the event to subscribers. 2. Do not auto-confirm a new image using the DFUoverSMP module when OTA Requestor is enabled. In such a case, it is the OTA Requestor's job to confirm the image and notify OTA Provider that it has just happened. 3. Limit UPGRADE_ONLY mode to nRF53 (it was mistakenly enabled for all Nordic boards). 4. Change OTAImageProcessorImpl::IsFirstImageRun impl to make it work even if UPGRADE_ONLY mode is enabled. Signed-off-by: Damian Krolik (cherry picked from commit 645acff4063b3c79c7af8eb1cae040b3c786c6ed) --- config/nrfconnect/chip-module/Kconfig.mcuboot.defaults | 9 +++++---- examples/light-switch-app/nrfconnect/main/AppTask.cpp | 3 +++ examples/lighting-app/nrfconnect/main/AppTask.cpp | 3 +++ examples/lock-app/nrfconnect/main/AppTask.cpp | 3 +++ examples/platform/nrfconnect/util/OTAUtil.cpp | 2 +- examples/pump-app/nrfconnect/main/AppTask.cpp | 3 +++ .../pump-controller-app/nrfconnect/main/AppTask.cpp | 3 +++ src/platform/nrfconnect/CHIPDevicePlatformConfig.h | 2 +- src/platform/nrfconnect/OTAImageProcessorImpl.cpp | 10 +++++++++- 9 files changed, 31 insertions(+), 7 deletions(-) diff --git a/config/nrfconnect/chip-module/Kconfig.mcuboot.defaults b/config/nrfconnect/chip-module/Kconfig.mcuboot.defaults index b26e721c8f..2e2ea5b0f2 100644 --- a/config/nrfconnect/chip-module/Kconfig.mcuboot.defaults +++ b/config/nrfconnect/chip-module/Kconfig.mcuboot.defaults @@ -36,10 +36,6 @@ config BOOT_ENCRYPT_X25519 bool default n -choice BOOT_IMAGE_UPGRADE_MODE - default BOOT_UPGRADE_ONLY -endchoice - config BOOT_BOOTSTRAP bool default n @@ -119,6 +115,11 @@ config UPDATEABLE_IMAGE_NUMBER int default 2 +# Multi-image updates do not support image swapping yet. +choice BOOT_IMAGE_UPGRADE_MODE + default BOOT_UPGRADE_ONLY +endchoice + # The network core cannot access external flash directly. The flash simulator must be used to # provide a memory region that is used to forward the new firmware to the network core. config FLASH_SIMULATOR diff --git a/examples/light-switch-app/nrfconnect/main/AppTask.cpp b/examples/light-switch-app/nrfconnect/main/AppTask.cpp index 06bb078a44..5f2888bb15 100644 --- a/examples/light-switch-app/nrfconnect/main/AppTask.cpp +++ b/examples/light-switch-app/nrfconnect/main/AppTask.cpp @@ -153,7 +153,10 @@ CHIP_ERROR AppTask::Init() // Initialize DFU #ifdef CONFIG_MCUMGR_SMP_BT GetDFUOverSMP().Init(RequestSMPAdvertisingStart); +#ifndef CONFIG_CHIP_OTA_REQUESTOR + // When OTA Requestor is enabled, it is responsible for confirming new images. GetDFUOverSMP().ConfirmNewImage(); +#endif #endif // Print initial configs diff --git a/examples/lighting-app/nrfconnect/main/AppTask.cpp b/examples/lighting-app/nrfconnect/main/AppTask.cpp index 4de9d4eeb5..12ee2a9e8a 100644 --- a/examples/lighting-app/nrfconnect/main/AppTask.cpp +++ b/examples/lighting-app/nrfconnect/main/AppTask.cpp @@ -161,7 +161,10 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP GetDFUOverSMP().Init(RequestSMPAdvertisingStart); +#ifndef CONFIG_CHIP_OTA_REQUESTOR + // When OTA Requestor is enabled, it is responsible for confirming new images. GetDFUOverSMP().ConfirmNewImage(); +#endif #endif // Initialize CHIP server diff --git a/examples/lock-app/nrfconnect/main/AppTask.cpp b/examples/lock-app/nrfconnect/main/AppTask.cpp index 054ea732bb..94d5c29891 100644 --- a/examples/lock-app/nrfconnect/main/AppTask.cpp +++ b/examples/lock-app/nrfconnect/main/AppTask.cpp @@ -145,7 +145,10 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP GetDFUOverSMP().Init(RequestSMPAdvertisingStart); +#ifndef CONFIG_CHIP_OTA_REQUESTOR + // When OTA Requestor is enabled, it is responsible for confirming new images. GetDFUOverSMP().ConfirmNewImage(); +#endif #endif // Initialize CHIP server diff --git a/examples/platform/nrfconnect/util/OTAUtil.cpp b/examples/platform/nrfconnect/util/OTAUtil.cpp index 53caa1e1e0..23795c3589 100644 --- a/examples/platform/nrfconnect/util/OTAUtil.cpp +++ b/examples/platform/nrfconnect/util/OTAUtil.cpp @@ -53,6 +53,6 @@ void InitBasicOTARequestor() sBDXDownloader.SetImageProcessorDelegate(&imageProcessor); sOTARequestorStorage.Init(Server::GetInstance().GetPersistentStorage()); sOTARequestor.Init(Server::GetInstance(), sOTARequestorStorage, sOTARequestorDriver, sBDXDownloader); - sOTARequestorDriver.Init(&sOTARequestor, &imageProcessor); chip::SetRequestorInstance(&sOTARequestor); + sOTARequestorDriver.Init(&sOTARequestor, &imageProcessor); } diff --git a/examples/pump-app/nrfconnect/main/AppTask.cpp b/examples/pump-app/nrfconnect/main/AppTask.cpp index 4aa2eac013..abb9f8f2b6 100644 --- a/examples/pump-app/nrfconnect/main/AppTask.cpp +++ b/examples/pump-app/nrfconnect/main/AppTask.cpp @@ -141,7 +141,10 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP GetDFUOverSMP().Init(RequestSMPAdvertisingStart); +#ifndef CONFIG_CHIP_OTA_REQUESTOR + // When OTA Requestor is enabled, it is responsible for confirming new images. GetDFUOverSMP().ConfirmNewImage(); +#endif #endif // Initialize CHIP server diff --git a/examples/pump-controller-app/nrfconnect/main/AppTask.cpp b/examples/pump-controller-app/nrfconnect/main/AppTask.cpp index f47ddb9a9f..923c9001f4 100644 --- a/examples/pump-controller-app/nrfconnect/main/AppTask.cpp +++ b/examples/pump-controller-app/nrfconnect/main/AppTask.cpp @@ -138,7 +138,10 @@ CHIP_ERROR AppTask::Init() #ifdef CONFIG_MCUMGR_SMP_BT // Initialize DFU over SMP GetDFUOverSMP().Init(RequestSMPAdvertisingStart); +#ifndef CONFIG_CHIP_OTA_REQUESTOR + // When OTA Requestor is enabled, it is responsible for confirming new images. GetDFUOverSMP().ConfirmNewImage(); +#endif #endif // Initialize CHIP server diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h index b487b0fa87..69b58456ca 100644 --- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h +++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h @@ -70,7 +70,7 @@ #ifndef CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS /// Time to sleep after running server shutdown actions to let lower layers complete the actions. /// This may include transmitting packets created by the actions. -#define CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS 10 +#define CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS 500 #endif // CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS #ifndef CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index 26eaab23d5..e117b29ca8 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -18,6 +18,7 @@ #include "OTAImageProcessorImpl.h" #include +#include #include #include #include @@ -167,7 +168,14 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & aBlock) bool OTAImageProcessorImpl::IsFirstImageRun() { - return mcuboot_swap_type() == BOOT_SWAP_TYPE_REVERT; + OTARequestorInterface * requestor = GetRequestorInstance(); + ReturnErrorCodeIf(requestor == nullptr, false); + + uint32_t currentVersion; + ReturnErrorCodeIf(ConfigurationMgr().GetSoftwareVersion(currentVersion) != CHIP_NO_ERROR, false); + + return requestor->GetCurrentUpdateState() == OTARequestorInterface::OTAUpdateStateEnum::kApplying && + requestor->GetTargetVersion() == currentVersion; } CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage() From 90a41a6a16b455c931d41bfbf04787a8d3649c62 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Mon, 23 May 2022 15:39:38 +0200 Subject: [PATCH 13/64] [nrf noup] Bump release_tools workflow Docker image Signed-off-by: Damian Krolik --- .github/workflows/release_tools.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release_tools.yaml b/.github/workflows/release_tools.yaml index 5ff07e333c..23635af686 100644 --- a/.github/workflows/release_tools.yaml +++ b/.github/workflows/release_tools.yaml @@ -37,7 +37,7 @@ jobs: JAVA_HOME: /usr/lib/jvm/java-8-openjdk-amd64/ container: - image: connectedhomeip/chip-build-android:0.5.58 + image: connectedhomeip/chip-build-android:0.5.73 volumes: - "/tmp/log_output:/tmp/test_logs" - "/tmp/output_binaries:/tmp/output_binaries" @@ -47,11 +47,12 @@ jobs: uses: actions/checkout@v2 with: ref: "${{ github.event.inputs.commit }}" - submodules: true + - name: Checkout submodules + run: scripts/checkout_submodules.py --shallow --platform android linux - name: Bootstrap timeout-minutes: 10 run: scripts/build/gn_bootstrap.sh - - name: Install Python CHIP Tool dependencies + - name: Install CHIP Tool dependencies timeout-minutes: 10 run: | echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports $(lsb_release -sc) main restricted" > /etc/apt/sources.list.d/arm64.list @@ -59,7 +60,7 @@ jobs: apt update apt install -y --no-install-recommends -o APT::Immediate-Configure=false g++-aarch64-linux-gnu libgirepository1.0-dev dpkg --add-architecture arm64 - apt install -y --no-install-recommends -o APT::Immediate-Configure=false libavahi-client-dev:arm64 libglib2.0-dev:arm64 libssl-dev:arm64 + apt install -y --no-install-recommends -o APT::Immediate-Configure=false libavahi-client-dev:arm64 libglib2.0-dev:arm64 libssl-dev:arm64 libreadline-dev:arm64 - name: Build x64 CHIP Tool with debug logs enabled timeout-minutes: 10 run: | From 55b65c001e21135037ee7efee828df333ef041f4 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Tue, 24 May 2022 13:36:10 +0200 Subject: [PATCH 14/64] [nrf noup] Use DFU Multi Image library Use DFU Multi Image package and library to allow for multi-image updates. Skip OTA requestor initialization if already initialized. Signed-off-by: Damian Krolik --- config/nrfconnect/chip-module/CMakeLists.txt | 26 +-- config/nrfconnect/chip-module/Kconfig | 2 + .../chip-module/make_ota_content_header.py | 122 -------------- .../chip-module/ota-content-header.cmake | 64 -------- config/zephyr/Kconfig | 7 - examples/platform/nrfconnect/util/OTAUtil.cpp | 2 + src/platform/nrfconnect/BUILD.gn | 2 - .../nrfconnect/OTAImageContentHeader.cpp | 149 ------------------ .../nrfconnect/OTAImageContentHeader.h | 107 ------------- .../nrfconnect/OTAImageProcessorImpl.cpp | 101 +++--------- .../nrfconnect/OTAImageProcessorImpl.h | 22 +-- 11 files changed, 32 insertions(+), 572 deletions(-) delete mode 100755 config/nrfconnect/chip-module/make_ota_content_header.py delete mode 100644 config/nrfconnect/chip-module/ota-content-header.cmake delete mode 100644 src/platform/nrfconnect/OTAImageContentHeader.cpp delete mode 100644 src/platform/nrfconnect/OTAImageContentHeader.h diff --git a/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt index 8f58f7dcd9..1e3d1cf446 100644 --- a/config/nrfconnect/chip-module/CMakeLists.txt +++ b/config/nrfconnect/chip-module/CMakeLists.txt @@ -30,7 +30,6 @@ if (CONFIG_CHIP) include(ExternalProject) include(../../zephyr/ota-image.cmake) include(../../zephyr/zephyr-util.cmake) -include(ota-content-header.cmake) # ============================================================================== # Declare configuration variables and define constants @@ -333,32 +332,11 @@ add_dependencies(chip chip-gn) # ============================================================================== if (CONFIG_CHIP_OTA_IMAGE_BUILD) - if (CONFIG_CHIP_OTA_IMAGE_INCLUDE_MCUBOOT) - list(APPEND CHIP_IMAGE_TYPES "mcuboot") - list(APPEND CHIP_IMAGE_PATHS "${APPLICATION_BINARY_DIR}/mcuboot/zephyr/zephyr.bin") - endif() - - list(APPEND CHIP_IMAGE_TYPES "app_mcuboot") - list(APPEND CHIP_IMAGE_PATHS "${PROJECT_BINARY_DIR}/app_update.bin") - - if (CONFIG_NRF53_UPGRADE_NETWORK_CORE) - list(APPEND CHIP_IMAGE_TYPES "net_mcuboot") - list(APPEND CHIP_IMAGE_PATHS "${PROJECT_BINARY_DIR}/net_core_app_update.bin") - endif() - - chip_ota_content_header(chip-ota-content-header - FILE_TYPES ${CHIP_IMAGE_TYPES} - FILE_PATHS ${CHIP_IMAGE_PATHS} - OUTPUT_FILE ${PROJECT_BINARY_DIR}/${CONFIG_CHIP_OTA_IMAGE_FILE_NAME}.content - ) - chip_ota_image(chip-ota-image - INPUT_FILES ${PROJECT_BINARY_DIR}/${CONFIG_CHIP_OTA_IMAGE_FILE_NAME}.content ${CHIP_IMAGE_PATHS} + INPUT_FILES ${PROJECT_BINARY_DIR}/dfu_multi_image.bin OUTPUT_FILE ${PROJECT_BINARY_DIR}/${CONFIG_CHIP_OTA_IMAGE_FILE_NAME} ) - - add_dependencies(chip-ota-content-header mcuboot_sign_target) - add_dependencies(chip-ota-image chip-ota-content-header) + add_dependencies(chip-ota-image dfu_multi_image_pkg) endif() endif() # CONFIG_CHIP diff --git a/config/nrfconnect/chip-module/Kconfig b/config/nrfconnect/chip-module/Kconfig index 9321d5f795..2f57b7dace 100644 --- a/config/nrfconnect/chip-module/Kconfig +++ b/config/nrfconnect/chip-module/Kconfig @@ -31,6 +31,7 @@ config CHIP_NFC_COMMISSIONING # See config/zephyr/Kconfig for full definition config CHIP_OTA_REQUESTOR bool + imply DFU_MULTI_IMAGE imply DFU_TARGET imply BOOTLOADER_MCUBOOT imply IMG_MANAGER @@ -60,6 +61,7 @@ config CHIP_OTA_IMAGE_BUILD bool default y if CHIP_OTA_REQUESTOR depends on SIGN_IMAGES + select DFU_MULTI_IMAGE_PACKAGE_BUILD config CHIP_DEBUG_SYMBOLS bool "Generate debug symbols" diff --git a/config/nrfconnect/chip-module/make_ota_content_header.py b/config/nrfconnect/chip-module/make_ota_content_header.py deleted file mode 100755 index 1aa437a6b9..0000000000 --- a/config/nrfconnect/chip-module/make_ota_content_header.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 - -# -# 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. -# - -""" -Utility for creating a Matter OTA content header that describes a list of files -included in a Matter OTA image. The header format is specific to the nRF Connect -platform. - -Usage example: - -./make_ota_content_header.py \ - --file mcuboot mcuboot/zephyr/zephyr.bin \ - --file app_mcuboot zephyr/app_update.bin \ - out.header -""" - -import argparse -import os -import struct -import sys -from enum import IntEnum - -sys.path.insert(0, os.path.join(os.path.dirname( - __file__), '../../../src/controller/python')) -from chip.tlv import TLVWriter, uint # noqa: E402 - - -# Context-specific tags describing members of the top-level header TLV structure -class HeaderTag(IntEnum): - FILE_INFO_LIST = 0, - - -# Context-specific tags describing members of the file info TLV structure -class FileInfoTag(IntEnum): - FILE_ID = 0, - FILE_SIZE = 1, - - -# File identifiers for all the supported file types -FILE_IDS = dict( - mcuboot=0, - app_mcuboot=1, - net_mcuboot=2, -) - - -def generate_header_tlv(file_infos: list): - """ - Generate TLV structure describing OTA image contents: - - Header ::= - [0] FileInfoList: [ - [0]: - [0] FileId: - [1] FileSize: - [1]: - [0] FileId: - [1] FileSize: - ... - ] - """ - - writer = TLVWriter() - writer.put(None, { - HeaderTag.FILE_INFO_LIST: [{ - FileInfoTag.FILE_ID: uint(file_id), - FileInfoTag.FILE_SIZE: uint(file_size), - } for file_id, file_size in file_infos] - }) - - return writer.encoding - - -def generate_header(file_infos: list, output_file: str): - """ - Generate OTA image content header and save it to file - """ - - header_tlv = generate_header_tlv(file_infos) - header = struct.pack(' -#include -#include -#include - -namespace chip { -namespace DeviceLayer { - -namespace { - -enum class HeaderTag : uint8_t -{ - kFileInfoList = 0, -}; - -enum class FileInfoTag : uint8_t -{ - kFileId = 0, - kFileSize = 1, -}; - -/// Maximum supported Matter OTA image content header size -constexpr uint32_t kMaxHeaderSize = 1024; -} // namespace - -void OTAImageContentHeaderParser::Init() -{ - mState = State::kInitialized; - mBufferOffset = 0; - mHeaderTlvSize = 0; - mBuffer.Alloc(sizeof(mHeaderTlvSize)); -} - -void OTAImageContentHeaderParser::Clear() -{ - mState = State::kNotInitialized; - mBufferOffset = 0; - mHeaderTlvSize = 0; - mBuffer.Free(); -} - -CHIP_ERROR OTAImageContentHeaderParser::AccumulateAndDecode(ByteSpan & buffer, OTAImageContentHeader & header) -{ - CHIP_ERROR error = CHIP_NO_ERROR; - - if (mState == State::kInitialized) - { - ReturnErrorCodeIf(!mBuffer, CHIP_ERROR_NO_MEMORY); - Append(buffer, sizeof(mHeaderTlvSize) - mBufferOffset); - error = DecodeFixed(); - } - - if (mState == State::kTlv) - { - Append(buffer, mHeaderTlvSize - mBufferOffset); - error = DecodeTlv(header); - } - - if (error != CHIP_NO_ERROR && error != CHIP_ERROR_BUFFER_TOO_SMALL) - { - Clear(); - } - - return error; -} - -void OTAImageContentHeaderParser::Append(ByteSpan & buffer, uint32_t numBytes) -{ - numBytes = chip::min(numBytes, static_cast(buffer.size())); - memcpy(&mBuffer[mBufferOffset], buffer.data(), numBytes); - mBufferOffset += numBytes; - buffer = buffer.SubSpan(numBytes); -} - -CHIP_ERROR OTAImageContentHeaderParser::DecodeFixed() -{ - ReturnErrorCodeIf(mBufferOffset < sizeof(mHeaderTlvSize), CHIP_ERROR_BUFFER_TOO_SMALL); - - mHeaderTlvSize = Encoding::LittleEndian::Get32(mBuffer.Get()); - // Safety check against malicious headers. - ReturnErrorCodeIf(mHeaderTlvSize > kMaxHeaderSize, CHIP_ERROR_NO_MEMORY); - ReturnErrorCodeIf(!mBuffer.Alloc(mHeaderTlvSize), CHIP_ERROR_NO_MEMORY); - - mState = State::kTlv; - mBufferOffset = 0; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR OTAImageContentHeaderParser::DecodeTlv(OTAImageContentHeader & header) -{ - ReturnErrorCodeIf(mBufferOffset < mHeaderTlvSize, CHIP_ERROR_BUFFER_TOO_SMALL); - - TLV::TLVReader tlvReader; - tlvReader.Init(mBuffer.Get(), mBufferOffset); - ReturnErrorOnFailure(tlvReader.Next(TLV::TLVType::kTLVType_Structure, TLV::AnonymousTag())); - - TLV::TLVType outerType; - ReturnErrorOnFailure(tlvReader.EnterContainer(outerType)); - - TLV::TLVType headerType; - ReturnErrorOnFailure(tlvReader.Next(TLV::TLVType::kTLVType_Array, TLV::ContextTag(to_underlying(HeaderTag::kFileInfoList)))); - ReturnErrorOnFailure(tlvReader.EnterContainer(headerType)); - - size_t fileNo = 0; - - while (tlvReader.Next(TLV::TLVType::kTLVType_Structure, TLV::AnonymousTag()) == CHIP_NO_ERROR) - { - ReturnErrorCodeIf(fileNo >= OTAImageContentHeader::kMaxFiles, CHIP_ERROR_NO_MEMORY); - - TLV::TLVType arrayType; - ReturnErrorOnFailure(tlvReader.EnterContainer(arrayType)); - - ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(to_underlying(FileInfoTag::kFileId)))); - ReturnErrorOnFailure(tlvReader.Get(header.mFiles[fileNo].mFileId)); - ReturnErrorOnFailure(tlvReader.Next(TLV::ContextTag(to_underlying(FileInfoTag::kFileSize)))); - ReturnErrorOnFailure(tlvReader.Get(header.mFiles[fileNo].mFileSize)); - ++fileNo; - - ReturnErrorOnFailure(tlvReader.ExitContainer(arrayType)); - } - - ReturnErrorOnFailure(tlvReader.ExitContainer(headerType)); - ReturnErrorOnFailure(tlvReader.ExitContainer(outerType)); - - return CHIP_NO_ERROR; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nrfconnect/OTAImageContentHeader.h b/src/platform/nrfconnect/OTAImageContentHeader.h deleted file mode 100644 index f56108a6f5..0000000000 --- a/src/platform/nrfconnect/OTAImageContentHeader.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Copyright (c) 2022 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include - -namespace chip { -namespace DeviceLayer { - -struct OTAImageContentHeader -{ - static constexpr size_t kMaxFiles = 3; - - enum class FileId : uint32_t - { - kMcuboot = 0, - kAppMcuboot = 1, - kNetMcuboot = 2, - }; - - struct FileInfo - { - FileId mFileId; - uint32_t mFileSize; - }; - - FileInfo mFiles[kMaxFiles]; -}; - -class OTAImageContentHeaderParser -{ -public: - /** - * @brief Prepare the parser for accepting Matter OTA image chunks. - * - * The method can be called many times to reset the parser state. - */ - void Init(); - - /** - * @brief Clear all resources associated with the parser. - */ - void Clear(); - - /** - * @brief Returns if the parser is ready to accept subsequent Matter OTA image chunks. - */ - bool IsInitialized() const { return mState != State::kNotInitialized; } - - /** - * @brief Decode nRF Connect Matter OTA image content header - * - * The method takes subsequent chunks of the Matter OTA image file and decodes the header when - * enough data has been provided. If more image chunks are needed, CHIP_ERROR_BUFFER_TOO_SMALL - * error is returned. Other error codes indicate that the header is invalid. - * - * @param buffer Byte span containing a subsequent Matter OTA image chunk. When the method - * returns CHIP_NO_ERROR, the byte span is used to return a remaining part - * of the chunk, not used by the header. - * @param header Structure to store results of the operation. - * - * @retval CHIP_NO_ERROR Header has been decoded successfully. - * @retval CHIP_ERROR_BUFFER_TOO_SMALL Provided buffers are insufficient to decode the - * header. A user is expected call the method again - * when the next image chunk is available. - * @retval Error code Encoded header is invalid. - */ - CHIP_ERROR AccumulateAndDecode(ByteSpan & buffer, OTAImageContentHeader & header); - -private: - enum State - { - kNotInitialized, - kInitialized, - kTlv - }; - - void Append(ByteSpan & buffer, uint32_t numBytes); - CHIP_ERROR DecodeFixed(); - CHIP_ERROR DecodeTlv(OTAImageContentHeader & header); - - State mState; - uint32_t mBufferOffset; - uint32_t mHeaderTlvSize; - Platform::ScopedMemoryBuffer mBuffer; -}; - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index e117b29ca8..d9caebbd34 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -45,33 +46,41 @@ CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() CHIP_ERROR OTAImageProcessorImpl::PrepareDownloadImpl() { mHeaderParser.Init(); - mContentHeaderParser.Init(); ReturnErrorOnFailure(System::MapErrorZephyr(dfu_target_mcuboot_set_buf(mBuffer, sizeof(mBuffer)))); + ReturnErrorOnFailure(System::MapErrorZephyr(dfu_multi_image_init(mBuffer, sizeof(mBuffer)))); + + for (int image_id = 0; image_id < CONFIG_UPDATEABLE_IMAGE_NUMBER; ++image_id) + { + dfu_image_writer writer; + writer.image_id = image_id; + writer.open = [](int id, size_t size) { return dfu_target_init(DFU_TARGET_IMAGE_TYPE_MCUBOOT, id, size, nullptr); }; + writer.write = [](const uint8_t * chunk, size_t chunk_size) { return dfu_target_write(chunk, chunk_size); }; + writer.close = [](bool success) { return dfu_target_done(success); }; + + ReturnErrorOnFailure(System::MapErrorZephyr(dfu_multi_image_register_writer(&writer))); + }; return CHIP_NO_ERROR; } CHIP_ERROR OTAImageProcessorImpl::Finalize() { - return CHIP_NO_ERROR; + return System::MapErrorZephyr(dfu_multi_image_done(true)); } CHIP_ERROR OTAImageProcessorImpl::Abort() { - CHIP_ERROR error = System::MapErrorZephyr(dfu_target_reset()); + CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(false)); TriggerFlashAction(FlashHandler::Action::SLEEP); + return error; } CHIP_ERROR OTAImageProcessorImpl::Apply() { - int err = dfu_target_done(true); - if (!err) - { - // schedule update of all possible targets by caling this function with argument -1 - err = dfu_target_schedule_update(-1); - } + // Schedule update of all images + int err = dfu_target_schedule_update(-1); TriggerFlashAction(FlashHandler::Action::SLEEP); @@ -96,67 +105,25 @@ CHIP_ERROR OTAImageProcessorImpl::Apply() #endif } -CHIP_ERROR OTAImageProcessorImpl::SwitchToNextImage(const ByteSpan & aRemainingData) -{ - mCurrentImage.mFileInfo = &mContentHeader.mFiles[static_cast(ImageType::kNetImage)]; - mCurrentImage.mImageType = ImageType::kNetImage; - - if (mCurrentImage.mFileInfo->mFileSize > 0) - { - // finish app-core dfu target to inform mcuboot that all bytes were written - ReturnErrorOnFailure(System::MapErrorZephyr(dfu_target_done(true))); - // Reset app-core target to allow switching a target to the next one - ReturnErrorOnFailure(System::MapErrorZephyr(dfu_target_reset())); - // initialize next dfu target to store net-core image. - ReturnErrorOnFailure(System::MapErrorZephyr( - dfu_target_init(DFU_TARGET_IMAGE_TYPE_MCUBOOT, static_cast(mCurrentImage.mImageType), /* size */ 0, nullptr))); - // write remaining data to new image - ReturnErrorOnFailure(System::MapErrorZephyr(dfu_target_write(aRemainingData.data(), aRemainingData.size()))); - mCurrentImage.mCurrentOffset = aRemainingData.size(); - } - return CHIP_NO_ERROR; -} - CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & aBlock) { VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = ProcessHeader(aBlock); + if (error == CHIP_NO_ERROR) { - mCurrentImage.mCurrentOffset += aBlock.size(); - if (mCurrentImage.mCurrentOffset >= mCurrentImage.mFileInfo->mFileSize) - { - // create new subspan with data which should be moved to the next image - ByteSpan remainingData = aBlock.SubSpan( - aBlock.size() - (mCurrentImage.mCurrentOffset - static_cast(mCurrentImage.mFileInfo->mFileSize))); - // write last data of previous image - error = System::MapErrorZephyr(dfu_target_write(aBlock.data(), aBlock.size() - remainingData.size())); - if (OTAImageContentHeader::FileId::kAppMcuboot == mCurrentImage.mFileInfo->mFileId && CHIP_NO_ERROR == error) - { - // switch to net image - error = SwitchToNextImage(remainingData); - } - else - { - // Finish process with error to ensure that only two images are available. - error = CHIP_ERROR_INVALID_DATA_LIST; - } - } - else - { - // DFU target library buffers data internally, so do not clone the block data. - error = System::MapErrorZephyr(dfu_target_write(aBlock.data(), aBlock.size())); - } + // DFU target library buffers data internally, so do not clone the block data. + error = System::MapErrorZephyr(dfu_multi_image_write(mParams.downloadedBytes, aBlock.data(), aBlock.size())); + mParams.downloadedBytes += aBlock.size(); } // Report the result back to the downloader asynchronously. return DeviceLayer::SystemLayer().ScheduleLambda([this, error, aBlock] { if (error == CHIP_NO_ERROR) { - mParams.downloadedBytes += aBlock.size(); - ChipLogDetail(SoftwareUpdate, "Processed %llu/%u Bytes of image no. %u", mCurrentImage.mCurrentOffset, - mCurrentImage.mFileInfo->mFileSize, static_cast(mCurrentImage.mImageType)); + ChipLogDetail(SoftwareUpdate, "Downloaded %u/%u bytes", static_cast(mParams.downloadedBytes), + static_cast(mParams.totalFileBytes)); mDownloader->FetchNextData(); } else @@ -198,26 +165,6 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & aBlock) mHeaderParser.Clear(); } - if (mContentHeaderParser.IsInitialized() && !aBlock.empty()) - { - CHIP_ERROR error = mContentHeaderParser.AccumulateAndDecode(aBlock, mContentHeader); - - // Needs more data to decode the header - ReturnErrorCodeIf(error == CHIP_ERROR_BUFFER_TOO_SMALL, CHIP_NO_ERROR); - ReturnErrorOnFailure(error); - - if (OTAImageContentHeader::FileId::kAppMcuboot == mContentHeader.mFiles[0].mFileId) - { - mCurrentImage.mFileInfo = &mContentHeader.mFiles[static_cast(ImageType::kAppImage)]; - mCurrentImage.mImageType = ImageType::kAppImage; - // Initialize dfu target to receive first image - ReturnErrorOnFailure(System::MapErrorZephyr(dfu_target_init( - DFU_TARGET_IMAGE_TYPE_MCUBOOT, static_cast(mCurrentImage.mImageType), /* size */ 0, nullptr))); - } - - mContentHeaderParser.Clear(); - } - return CHIP_NO_ERROR; } diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.h b/src/platform/nrfconnect/OTAImageProcessorImpl.h index 59529c49a1..99b9c13e9d 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.h +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.h @@ -19,7 +19,6 @@ #include #include #include -#include namespace chip { @@ -44,22 +43,10 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface public: static constexpr size_t kBufferSize = CONFIG_CHIP_OTA_REQUESTOR_BUFFER_SIZE; - OTAImageProcessorImpl(FlashHandler * flashHandler = nullptr) : mFlashHandler(flashHandler){}; - - enum class ImageType : uint8_t - { - kAppImage = 0, - kNetImage = 1 - }; + explicit OTAImageProcessorImpl(FlashHandler * flashHandler = nullptr) : mFlashHandler(flashHandler) {} void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; }; - - struct OTAImage - { - OTAImageContentHeader::FileInfo * mFileInfo; - ImageType mImageType; - uint64_t mCurrentOffset; - }; + void TriggerFlashAction(FlashHandler::Action action); CHIP_ERROR PrepareDownload() override; CHIP_ERROR Finalize() override; @@ -68,19 +55,14 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface CHIP_ERROR ProcessBlock(ByteSpan & aBlock) override; bool IsFirstImageRun() override; CHIP_ERROR ConfirmCurrentImage() override; - void TriggerFlashAction(FlashHandler::Action action); private: CHIP_ERROR PrepareDownloadImpl(); CHIP_ERROR ProcessHeader(ByteSpan & aBlock); - CHIP_ERROR SwitchToNextImage(const ByteSpan & aRemainingData); OTADownloader * mDownloader = nullptr; OTAImageHeaderParser mHeaderParser; - OTAImageContentHeaderParser mContentHeaderParser; uint8_t mBuffer[kBufferSize]; - OTAImageContentHeader mContentHeader; - OTAImage mCurrentImage; FlashHandler * mFlashHandler; }; From fc6a52c72f357b434c7dc05c6e961d8f004e1f80 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk <66371704+kkasperczyk-no@users.noreply.github.com> Date: Wed, 25 May 2022 08:58:03 +0200 Subject: [PATCH 15/64] [nrf fromtee] [nrfconnect] Fixed window covering bug in updating cluster attributes (#18752) * [nrfconnect] Fixed window covering bug in updating cluster attributes Nrfconnect window covering example doesn't update window covering cluster attributes properly. * Moved PostAttributeChange method from window-covering-server.cpp to header. * Called PostAttributeChange method in nrfconnect implementation of MatterWindowCoveringClusterServerAttributeChangedCallback * Changed mode default value from 0x14 to 0. * [nrfconnect] window-app: do not block in chip attribute changed callback. Signed-off-by: Marcin Kajor Co-authored-by: Marcin Kajor (cherry picked from commit a3fdd059ebcf22131f6905dd551eabd631466db4) --- .../nrfconnect/main/WindowCovering.cpp | 19 +++++++++++++++++++ .../nrfconnect/main/ZclCallbacks.cpp | 1 + .../nrfconnect/main/include/WindowCovering.h | 8 ++++++++ .../window-covering-server.cpp | 6 ------ .../window-covering-server.h | 8 ++++++++ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/examples/window-app/nrfconnect/main/WindowCovering.cpp b/examples/window-app/nrfconnect/main/WindowCovering.cpp index 4da326ed16..f166704539 100644 --- a/examples/window-app/nrfconnect/main/WindowCovering.cpp +++ b/examples/window-app/nrfconnect/main/WindowCovering.cpp @@ -322,3 +322,22 @@ uint8_t WindowCovering::PositionToBrightness(uint16_t aPosition, MoveType aMoveT return Percent100thsToValue(pwmLimits, aPosition); } + +void WindowCovering::SchedulePostAttributeChange(chip::EndpointId aEndpoint, chip::AttributeId aAttributeId) +{ + AttributeUpdateData * data = chip::Platform::New(); + VerifyOrReturn(data != nullptr); + + data->mEndpoint = aEndpoint; + data->mAttributeId = aAttributeId; + + chip::DeviceLayer::PlatformMgr().ScheduleWork(DoPostAttributeChange, reinterpret_cast(data)); +} + +void WindowCovering::DoPostAttributeChange(intptr_t aArg) +{ + AttributeUpdateData * data = reinterpret_cast(aArg); + VerifyOrReturn(data != nullptr); + + PostAttributeChange(data->mEndpoint, data->mAttributeId); +} diff --git a/examples/window-app/nrfconnect/main/ZclCallbacks.cpp b/examples/window-app/nrfconnect/main/ZclCallbacks.cpp index f05dbdec8a..f8407af3ff 100644 --- a/examples/window-app/nrfconnect/main/ZclCallbacks.cpp +++ b/examples/window-app/nrfconnect/main/ZclCallbacks.cpp @@ -75,4 +75,5 @@ void MatterWindowCoveringClusterServerAttributeChangedCallback(const app::Concre break; }; } + WindowCovering::Instance().SchedulePostAttributeChange(attributePath.mEndpointId, attributePath.mAttributeId); } diff --git a/examples/window-app/nrfconnect/main/include/WindowCovering.h b/examples/window-app/nrfconnect/main/include/WindowCovering.h index 9d4d17b548..2b5b6ef792 100644 --- a/examples/window-app/nrfconnect/main/include/WindowCovering.h +++ b/examples/window-app/nrfconnect/main/include/WindowCovering.h @@ -36,6 +36,12 @@ class WindowCovering NONE }; + struct AttributeUpdateData + { + chip::EndpointId mEndpoint; + chip::AttributeId mAttributeId; + }; + WindowCovering(); static WindowCovering & Instance() { @@ -49,6 +55,7 @@ class WindowCovering MoveType GetMoveType() { return mCurrentUIMoveType; } void PositionLEDUpdate(MoveType aMoveType); + static void SchedulePostAttributeChange(chip::EndpointId aEndpoint, chip::AttributeId aAttributeId); static constexpr chip::EndpointId Endpoint() { return 1; }; private: @@ -63,6 +70,7 @@ class WindowCovering static void DriveCurrentLiftPosition(intptr_t); static void DriveCurrentTiltPosition(intptr_t); static void MoveTimerTimeoutCallback(k_timer * aTimer); + static void DoPostAttributeChange(intptr_t aArg); MoveType mCurrentUIMoveType; LEDWidget mLiftLED; diff --git a/src/app/clusters/window-covering-server/window-covering-server.cpp b/src/app/clusters/window-covering-server/window-covering-server.cpp index a4d5d4b7a9..79660c45cd 100644 --- a/src/app/clusters/window-covering-server/window-covering-server.cpp +++ b/src/app/clusters/window-covering-server/window-covering-server.cpp @@ -587,12 +587,6 @@ EmberEventControl * ConfigureFakeMotionEventControl(EndpointId endpoint) return controller; } -/** - * @brief PostAttributeChange is called when an Attribute is modified - * - * @param[in] endpoint - * @param[in] attributeId - */ void PostAttributeChange(chip::EndpointId endpoint, chip::AttributeId attributeId) { // all-cluster-app: simulation for the CI testing diff --git a/src/app/clusters/window-covering-server/window-covering-server.h b/src/app/clusters/window-covering-server/window-covering-server.h index cf785b61aa..1ef0506ce2 100644 --- a/src/app/clusters/window-covering-server/window-covering-server.h +++ b/src/app/clusters/window-covering-server/window-covering-server.h @@ -137,6 +137,14 @@ void TiltPositionSet(chip::EndpointId endpoint, NPercent100ths position); EmberAfStatus GetMotionLockStatus(chip::EndpointId endpoint); +/** + * @brief PostAttributeChange is called when an Attribute is modified + * + * @param[in] endpoint + * @param[in] attributeId + */ +void PostAttributeChange(chip::EndpointId endpoint, chip::AttributeId attributeId); + } // namespace WindowCovering } // namespace Clusters } // namespace app From cf449fdce0955a47ee7d3d6d04b848556e944184 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Wed, 25 May 2022 10:32:34 +0200 Subject: [PATCH 16/64] [nrf noup] Fix Android CHIPTool multi-admin commands Commands for opening the commissioning window used too low duration. Change the duration to 180s. Signed-off-by: Damian Krolik --- .../chiptool/clusterclient/MultiAdminClientFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt index 2405535147..1d9990c432 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt @@ -78,22 +78,22 @@ class MultiAdminClientFragment : Fragment() { } private suspend fun sendBasicCommissioningCommandClick() { - val testDuration = 100 + val windowDuration = 180 deviceController.openPairingWindow( ChipClient.getConnectedDevicePointer( requireContext(), addressUpdateFragment.deviceId - ), testDuration + ), windowDuration ) } private suspend fun sendEnhancedCommissioningCommandClick() { - val testDuration = 100 - val testIteration = 1000 + val windowDuration = 180 + val spakeIterationCount = 1000 val devicePointer = ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId) deviceController.openPairingWindowWithPIN( - devicePointer, testDuration, testIteration.toLong(), + devicePointer, windowDuration, spakeIterationCount.toLong(), discriminatorEd.text.toString().toInt(), setupPinCodeEd.text.toString().toULong().toLong() ) } From cdee751ea6928cdaff05db32f57bc4146401f93a Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Wed, 25 May 2022 10:44:51 +0200 Subject: [PATCH 17/64] [nrf noup] Enable NVS lookup cache by default NVS cache should speed up reading settings on the device boot. Signed-off-by: Damian Krolik --- config/nrfconnect/chip-module/Kconfig.defaults | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/nrfconnect/chip-module/Kconfig.defaults b/config/nrfconnect/chip-module/Kconfig.defaults index 7166084b67..c803bcff21 100644 --- a/config/nrfconnect/chip-module/Kconfig.defaults +++ b/config/nrfconnect/chip-module/Kconfig.defaults @@ -40,6 +40,10 @@ config LOG_DEFAULT_LEVEL endif +config NVS_LOOKUP_CACHE + bool + default y + config PRINTK_SYNC bool default y From 2f793b28ba67940300ec3b7cff0b39588f41ed5a Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Wed, 25 May 2022 12:54:56 +0200 Subject: [PATCH 18/64] [nrf noup] Always set UPDATEABLE_IMAGE_NUMBER=2 for nRF53 UPDATEABLE_IMAGE_NUMBER was set to 2 for nRF53 SOCs only if DFU over SMP was enabled. We need that for a regular Matter OTA, too. Signed-off-by: Damian Krolik --- config/nrfconnect/chip-module/Kconfig.defaults | 4 ++++ config/nrfconnect/chip-module/Kconfig.features | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/nrfconnect/chip-module/Kconfig.defaults b/config/nrfconnect/chip-module/Kconfig.defaults index c803bcff21..1ebd8a36f7 100644 --- a/config/nrfconnect/chip-module/Kconfig.defaults +++ b/config/nrfconnect/chip-module/Kconfig.defaults @@ -351,6 +351,10 @@ endif # SOC_SERIES_NRF52X if SOC_SERIES_NRF53X +config UPDATEABLE_IMAGE_NUMBER + int + default 2 + # Generate random numbers using Xoroshiro algorithm instead of direct calls # to the cryptocell library to workaround firmware hangs. choice RNG_GENERATOR_CHOICE diff --git a/config/nrfconnect/chip-module/Kconfig.features b/config/nrfconnect/chip-module/Kconfig.features index 07c0cc5c47..b63983a11e 100644 --- a/config/nrfconnect/chip-module/Kconfig.features +++ b/config/nrfconnect/chip-module/Kconfig.features @@ -93,10 +93,6 @@ config SYSTEM_WORKQUEUE_STACK_SIZE if SOC_SERIES_NRF53X -config UPDATEABLE_IMAGE_NUMBER - int - default 2 - # FLASH nop device is enabled to prevent bus faults when mcumgr tries to access # simulated partition with network core image data. config FLASH_NOP_DEVICE From a5d185905c459647aaac1e89f76de07d263241ef Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Thu, 26 May 2022 14:12:53 +0200 Subject: [PATCH 19/64] [nrf noup] [android] Use ScrollView in main screen Some buttons were not visible on low-resolution devices. Signed-off-by: Damian Krolik --- .../res/layout/select_action_fragment.xml | 182 +++++++++--------- 1 file changed, 94 insertions(+), 88 deletions(-) diff --git a/src/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml b/src/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml index 89b4ea62e2..3098a32415 100644 --- a/src/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml +++ b/src/android/CHIPTool/app/src/main/res/layout/select_action_fragment.xml @@ -1,103 +1,109 @@ - -