From 4ffdb301ed877989c94446160b7bc09d881081c0 Mon Sep 17 00:00:00 2001 From: Sid Hsu Date: Tue, 1 Feb 2022 22:42:29 +0800 Subject: [PATCH] [CYW30739] Support OTA requestor app. (#14389) * [CYW30739] Support OTA requestor app. * Add examples/ota-requestor-app/cyw30739 files. * Add OTAImageProcessorImpl for CYW30739. * Refine README files for CYW30739 apps. * Add a null check for HandleProcessBlock --- .github/workflows/examples-cyw30739.yaml | 24 +- examples/lighting-app/cyw30739/README.md | 6 +- examples/lock-app/cyw30739/README.md | 6 +- examples/ota-requestor-app/cyw30739/.gn | 28 + examples/ota-requestor-app/cyw30739/BUILD.gn | 61 ++ examples/ota-requestor-app/cyw30739/README.md | 121 ++++ examples/ota-requestor-app/cyw30739/args.gni | 24 + .../cyw30739/build_overrides | 1 + .../cyw30739/include/CHIPProjectConfig.h | 61 ++ .../ota-requestor-app/cyw30739/src/main.cpp | 145 +++++ .../cyw30739/static_config.txt | 21 + .../cyw30739/third_party/connectedhomeip | 1 + scripts/build/build/targets.py | 1 + scripts/build/builders/cyw30739.py | 5 + .../testdata/all_targets_except_host.txt | 1 + .../build/testdata/build_all_except_host.txt | 6 + .../glob_star_targets_except_host.txt | 1 + src/platform/CYW30739/BUILD.gn | 9 +- .../CYW30739/OTAImageProcessorImpl.cpp | 217 +++++++ src/platform/CYW30739/OTAImageProcessorImpl.h | 63 ++ third_party/cyw30739_sdk/btp_reader.py | 39 +- .../cyw30739_sdk/cyw30739_executable.gni | 6 +- third_party/cyw30739_sdk/cyw30739_sdk.gni | 85 ++- third_party/cyw30739_sdk/flash.btp | 53 ++ third_party/cyw30739_sdk/gen_ota_image.py | 88 +++ .../cyw30739_sdk/include/ota_fw_upgrade.h | 52 ++ third_party/cyw30739_sdk/src/ota_fw_upgrade.c | 591 ++++++++++++++++++ .../cyw30739_sdk/src}/wiced_button_manager.c | 0 .../cyw30739_sdk/src}/wiced_led_manager.c | 0 29 files changed, 1670 insertions(+), 46 deletions(-) create mode 100644 examples/ota-requestor-app/cyw30739/.gn create mode 100644 examples/ota-requestor-app/cyw30739/BUILD.gn create mode 100644 examples/ota-requestor-app/cyw30739/README.md create mode 100644 examples/ota-requestor-app/cyw30739/args.gni create mode 120000 examples/ota-requestor-app/cyw30739/build_overrides create mode 100644 examples/ota-requestor-app/cyw30739/include/CHIPProjectConfig.h create mode 100644 examples/ota-requestor-app/cyw30739/src/main.cpp create mode 100644 examples/ota-requestor-app/cyw30739/static_config.txt create mode 120000 examples/ota-requestor-app/cyw30739/third_party/connectedhomeip create mode 100644 src/platform/CYW30739/OTAImageProcessorImpl.cpp create mode 100644 src/platform/CYW30739/OTAImageProcessorImpl.h create mode 100644 third_party/cyw30739_sdk/flash.btp create mode 100644 third_party/cyw30739_sdk/gen_ota_image.py create mode 100644 third_party/cyw30739_sdk/include/ota_fw_upgrade.h create mode 100644 third_party/cyw30739_sdk/src/ota_fw_upgrade.c rename {src/platform/CYW30739 => third_party/cyw30739_sdk/src}/wiced_button_manager.c (100%) rename {src/platform/CYW30739 => third_party/cyw30739_sdk/src}/wiced_led_manager.c (100%) diff --git a/.github/workflows/examples-cyw30739.yaml b/.github/workflows/examples-cyw30739.yaml index 54e39272456a28..42f3fd62f1fe4f 100644 --- a/.github/workflows/examples-cyw30739.yaml +++ b/.github/workflows/examples-cyw30739.yaml @@ -57,12 +57,12 @@ jobs: path: | .environment/gn_out/.ninja_log .environment/pigweed-venv/*.log - - name: Build example CYW30739 Lighting App - timeout-minutes: 10 + - name: Build example CYW30739 Apps + timeout-minutes: 30 run: | ./scripts/run_in_build_env.sh \ "./scripts/build/build_examples.py \ - --target cyw30739-cyw930739m2evb_01-light \ + --target-glob 'cyw30739-cyw930739m2evb_01-{light,lock,ota-requestor}' \ build \ --copy-artifacts-to out/artifacts \ " @@ -73,12 +73,20 @@ jobs: cyw30739 cyw930739m2evb_01 light \ out/artifacts/cyw30739-cyw930739m2evb_01-light/chip-cyw30739-lighting-example.elf \ /tmp/bloat_reports/ - - name: Build example CYW30739 Lock App - timeout-minutes: 10 + - name: Get lock size stats + timeout-minutes: 5 run: | - scripts/examples/gn_build_example.sh examples/lock-app/cyw30739 out/lock_app - .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py cyw30739 CYW30739 lock-app \ - out/lock_app/chip-cyw30739-lock-example.elf /tmp/bloat_reports/ + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + cyw30739 cyw930739m2evb_01 lock \ + out/artifacts/cyw30739-cyw930739m2evb_01-lock/chip-cyw30739-lock-example.elf \ + /tmp/bloat_reports/ + - name: Get ota-requestor size stats + timeout-minutes: 5 + run: | + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + cyw30739 cyw930739m2evb_01 ota-requestor \ + out/artifacts/cyw30739-cyw930739m2evb_01-ota-requestor/chip-cyw30739-ota-requestor-example.elf \ + /tmp/bloat_reports/ - name: Uploading Size Reports uses: actions/upload-artifact@v2 if: ${{ !env.ACT }} diff --git a/examples/lighting-app/cyw30739/README.md b/examples/lighting-app/cyw30739/README.md index 3d333ee204a75c..d43e663b5f12e0 100644 --- a/examples/lighting-app/cyw30739/README.md +++ b/examples/lighting-app/cyw30739/README.md @@ -18,12 +18,12 @@ An example showing the use of Matter on the Infineon CYW30739 platform. The CYW30739 lighting example provides a baseline demonstration of a Light control device, built using Matter and the Infineon Modustoolbox SDK. It can be -controlled by a Matter controller over Openthread network. +controlled by a Matter controller over Thread network. The CYW30739 device can be commissioned over Bluetooth Low Energy where the device and the Matter controller will exchange security information with the -Rendez-vous procedure. Thread Network credentials are then provided to the -CYW30739 device which will then join the network. +Rendez-vous procedure. Target Thread Network information including the active +dataset and CASE credentials are then provided. ## Building diff --git a/examples/lock-app/cyw30739/README.md b/examples/lock-app/cyw30739/README.md index 1c24ae8c57b067..41a6a23598d3df 100644 --- a/examples/lock-app/cyw30739/README.md +++ b/examples/lock-app/cyw30739/README.md @@ -18,12 +18,12 @@ An example showing the use of Matter on the Infineon CYW30739 platform. The CYW30739 lock example provides a baseline demonstration of a Light control device, built using Matter and the Infineon Modustoolbox SDK. It can be -controlled by a Matter controller over Openthread network. +controlled by a Matter controller over Thread network. The CYW30739 device can be commissioned over Bluetooth Low Energy where the device and the Matter controller will exchange security information with the -Rendez-vous procedure. Thread Network credentials are then provided to the -CYW30739 device which will then join the network. +Rendez-vous procedure. Target Thread Network information including the active +dataset and CASE credentials are then provided. ## Building diff --git a/examples/ota-requestor-app/cyw30739/.gn b/examples/ota-requestor-app/cyw30739/.gn new file mode 100644 index 00000000000000..90115e4209947e --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/.gn @@ -0,0 +1,28 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "cyw30739" + + import("//args.gni") +} diff --git a/examples/ota-requestor-app/cyw30739/BUILD.gn b/examples/ota-requestor-app/cyw30739/BUILD.gn new file mode 100644 index 00000000000000..61ba0c8536a558 --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/BUILD.gn @@ -0,0 +1,61 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/cyw30739_sdk.gni") + +import("${cyw30739_sdk_build_root}/cyw30739_executable.gni") +import("${cyw30739_sdk_build_root}/cyw30739_sdk.gni") + +cyw30739_project_dir = "${chip_root}/examples/ota-requestor-app/cyw30739" + +declare_args() { + setupPinCode = 0 + setupDiscriminator = 0 +} + +cyw30739_sdk("sdk") { + sources = [ "${cyw30739_project_dir}/include/CHIPProjectConfig.h" ] + + include_dirs = [ "${cyw30739_project_dir}/include" ] + + defines = [ + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + ] +} + +cyw30739_executable("ota_requestor_app") { + output_name = "chip-cyw30739-ota-requestor-example.elf" + + sources = [ "src/main.cpp" ] + + deps = [ + ":sdk", + "${chip_root}/examples/ota-requestor-app/ota-requestor-common", + "${chip_root}/examples/shell/shell_common:shell_common", + "${chip_root}/src/lib", + ] + + include_dirs = [ "include" ] +} + +group("cyw30739") { + deps = [ ":ota_requestor_app" ] +} + +group("default") { + deps = [ ":cyw30739" ] +} diff --git a/examples/ota-requestor-app/cyw30739/README.md b/examples/ota-requestor-app/cyw30739/README.md new file mode 100644 index 00000000000000..49737cd4f270fc --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/README.md @@ -0,0 +1,121 @@ +# Matter CYW30739 OTA Requestor Example + +An example showing the use of the Matter OTA Requestor functionality on the +Infineon CYW30739 platform. + +--- + +## Table of Contents + +- [CHIP CYW30739 OTA Requestor Example](#matter-cyw30739-ota-requestor-example) + - [Introduction](#introduction) + - [Building](#building) + - [Flashing the Application](#flashing-the-application) + - [Running the Complete Example](#running-the-complete-example) + +--- + +## Introduction + +The CYW30739 OTA Requestor example provides a baseline demonstration the Matter +OTA Requestor functionality built with the Infineon Modustoolbox SDK. It can be +controlled by a Matter controller over Thread network. + +The CYW30739 device can be commissioned over Bluetooth Low Energy where the +device and the Matter controller will exchange security information with the +Rendez-vous procedure. Target Thread Network information including the active +dataset and CASE credentials are then provided. + +## Building + +- Build the example application: + + ```bash + $ cd ~/connectedhomeip + $ git submodule update --init + $ ./scripts/examples/gn_build_example.sh examples/ota-requestor-app/cyw30739 out/ota-requestor-app + ``` + +- To delete generated executable, libraries and object files use: + + ```bash + $ cd ~/connectedhomeip + $ rm -rf ./out/ + ``` + +- OR use GN/Ninja directly + + ```bash + $ cd ~/connectedhomeip/examples/ota-requestor-app/cyw30739 + $ git submodule update --init + $ source third_party/connectedhomeip/scripts/activate.sh + $ gn gen out/debug + $ ninja -C out/debug + ``` + +- To delete generated executable, libraries and object files use: + + ```bash + $ cd ~/connectedhomeip/examples/ota-requestor-app/cyw30739 + $ rm -rf out/ + ``` + +## Flashing the Application + +### Enter Recovery Mode + +Put the CYW30739 in to the recovery mode before running the flash script. + +1. Press and hold the `RECOVERY` button on the board. +2. Press and hold the `RESET` button on the board. +3. Release the `RESET` button. +4. After one second, release the `RECOVERY` button. + +### Run Flash Script + +- On the command line: + + ```bash + $ cd ~/connectedhomeip/examples/ota-requestor-app/cyw30739 + $ python3 out/debug/chip-cyw30739-ota-requestor-example.flash.py + ``` + +## Running the Complete Example + +- It is assumed here that you already have an OpenThread border router + configured and running. If not see the following guide + [Openthread_border_router](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/openthread_border_router_pi.md) + for more information on how to setup a border router on a raspberryPi. + + - Get the active dataset hex for the chip-tool. + ```bash + ot-ctl dataset active -x + ``` + +- You can provision and control the Chip device using the python controller, + Chip tool standalone, Android or iOS app + + [Chip tool](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) + + Here is an example with the chip tool: + + - Start a Linux OTA Provider. + + ```bash + # Start the OTA provider server with an OTA binary file + chip-ota-provider-app -f + ``` + + - Setup the CYW30739 OTA Requestor the the Linux OTA Provider by the + controller. + + ```bash + # Pair the OTA Requestor + chip-tool pairing ble-thread 1234 hex:0e080000000000000000000300000b35060004001fffe00208dead00beef00cafe0708fddead00beef000005108e11d8ea8ffaa875713699f59e8807e0030a4f70656e5468726561640102c2980410edc641eb63b100b87e90a9980959befc0c0402a0fff8 20202021 3840 + + # Pair the OTA Provider + chip-tool pairing onnetwork-vendor 4321 20202021 9050 + + # Announce the OTA provider to the requestor + chip-tool otasoftwareupdaterequestor announce-ota-provider 4321 9 0 0 1234 0 + ``` diff --git a/examples/ota-requestor-app/cyw30739/args.gni b/examples/ota-requestor-app/cyw30739/args.gni new file mode 100644 index 00000000000000..5906f2e476dc00 --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/args.gni @@ -0,0 +1,24 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("${chip_root}/src/platform/CYW30739/args.gni") + +cyw30739_sdk_target = get_label_info(":sdk", "label_no_toolchain") + +chip_openthread_ftd = true + +declare_args() { + chip_enable_ota_requestor = true +} diff --git a/examples/ota-requestor-app/cyw30739/build_overrides b/examples/ota-requestor-app/cyw30739/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/ota-requestor-app/cyw30739/include/CHIPProjectConfig.h b/examples/ota-requestor-app/cyw30739/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..1ff4d6f64f9c30 --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/include/CHIPProjectConfig.h @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// -------------------- Device Identification Configuration -------------------- + +/* The VendorName attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME "Infineon" + +/* The VendorID attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0x0009 + +/* The ProductName attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME "CYW30739 OTA Requestor App" + +/* The ProductID attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x154c + +/* The HardwareVersionString attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING "30739" + +/* The HardwareVersion attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION 30739 + +/* The SoftwareVersionString attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "TE7.5" + +/* The SoftwareVersion attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 0x0705 + +/* The SerialNumber attribute of the Basic cluster. */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +// -------------------- Test Configuration -------------------- +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 1 diff --git a/examples/ota-requestor-app/cyw30739/src/main.cpp b/examples/ota-requestor-app/cyw30739/src/main.cpp new file mode 100644 index 00000000000000..f3ec01f2680de3 --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/src/main.cpp @@ -0,0 +1,145 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::Credentials; +using namespace chip::DeviceLayer; +using namespace chip::Shell; + +static void InitApp(intptr_t args); + +OTARequestor gRequestorCore; +DeviceLayer::GenericOTARequestorDriver gRequestorUser; +BDXDownloader gDownloader; +OTAImageProcessorImpl gImageProcessor; + +APPLICATION_START() +{ + CHIP_ERROR err; + wiced_result_t result; + + printf("\nOtaRequestor App starting\n"); + + mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree); + + err = Platform::MemoryInit(); + if (err != CHIP_NO_ERROR) + { + printf("ERROR MemoryInit %ld\n", err.AsInteger()); + } + + /* Init. LED Manager. */ + printf("Initializing CHIP\n"); + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + printf("ERROR InitChipStack %ld\n", err.AsInteger()); + } + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + printf("Initializing OpenThread stack\n"); + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + printf("ERROR InitThreadStack %ld\n", err.AsInteger()); + } +#endif + +#if CHIP_DEVICE_CONFIG_THREAD_FTD + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router); +#else // !CHIP_DEVICE_CONFIG_THREAD_FTD + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); +#endif // CHIP_DEVICE_CONFIG_THREAD_FTD + if (err != CHIP_NO_ERROR) + { + printf("ERROR SetThreadDeviceType %ld\n", err.AsInteger()); + } + + printf("Starting event loop task\n"); + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + printf("ERROR StartEventLoopTask %ld\n", err.AsInteger()); + } + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + printf("Starting thread task\n"); + err = ThreadStackMgr().StartThreadTask(); + if (err != CHIP_NO_ERROR) + { + printf("ERROR StartThreadTask %ld\n", err.AsInteger()); + } +#endif + + PlatformMgr().ScheduleWork(InitApp, 0); + + const int ret = Engine::Root().Init(); + if (!ChipError::IsSuccess(ret)) + { + printf("ERROR Shell Init %d\n", ret); + } + cmd_ping_init(); + Engine::Root().RunMainLoop(); + + assert(!wiced_rtos_check_for_stack_overflow()); +} + +void InitApp(intptr_t args) +{ + ConfigurationMgr().LogDeviceConfig(); + + /* Start CHIP datamodel server */ + Server::GetInstance().Init(); + + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + + // Initialize and interconnect the Requestor and Image Processor objects -- START + SetRequestorInstance(&gRequestorCore); + + gRequestorCore.Init(&(chip::Server::GetInstance()), &gRequestorUser, &gDownloader); + gRequestorUser.Init(&gRequestorCore, &gImageProcessor); + + gImageProcessor.SetOTADownloader(&gDownloader); + + // Connect the Downloader and Image Processor objects + gDownloader.SetImageProcessorDelegate(&gImageProcessor); + // Initialize and interconnect the Requestor and Image Processor objects -- END + + if (!wiced_ota_fw_upgrade_init(NULL, NULL, NULL)) + { + ChipLogError(SoftwareUpdate, "wiced_ota_fw_upgrade_init"); + } +} diff --git a/examples/ota-requestor-app/cyw30739/static_config.txt b/examples/ota-requestor-app/cyw30739/static_config.txt new file mode 100644 index 00000000000000..f256ac94aa5abf --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/static_config.txt @@ -0,0 +1,21 @@ +# The post-building script uses this file to generate specified static configurations. +# All '#' prefixed lines are ignored by the script. +# Each line defines a static configuration by 3 fields separated by commas. +# +# The 1st field is a 16-bit ID from 0x2000 to 0x3ffff. +# All IDs in this file have to be different. +# +# The 2nd field is a type to which the script interprets the value according. +# +# The 3rd field is a value of the static configuration. The value format depends on what the value type is: +# - hex: Multiple hexadecimal values separated by commas. +# - uint32/uint16/uint8/int16/int8: A integer. +# - eui64: random or btext. If the value is btext, the configuration will be generated from the BT address. +# +# ID, type, value +# EUI64 +0x2000, eui64, random +# Setup Pin Code +0x2105, uint32, 20202021 +# Setup Discriminator +0x2107, uint32, 3840 diff --git a/examples/ota-requestor-app/cyw30739/third_party/connectedhomeip b/examples/ota-requestor-app/cyw30739/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/ota-requestor-app/cyw30739/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 6cbea9b3764a79..49a794d6c8df3e 100644 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -367,6 +367,7 @@ def K32WTargets(): def Cyw30739Targets(): yield Target('cyw30739-cyw930739m2evb_01-light', Cyw30739Builder, board=Cyw30739Board.CYW930739M2EVB_01, app=Cyw30739App.LIGHT) yield Target('cyw30739-cyw930739m2evb_01-lock', Cyw30739Builder, board=Cyw30739Board.CYW930739M2EVB_01, app=Cyw30739App.LOCK) + yield Target('cyw30739-cyw930739m2evb_01-ota-requestor', Cyw30739Builder, board=Cyw30739Board.CYW930739M2EVB_01, app=Cyw30739App.OTA_REQUESTOR) ALL = [] diff --git a/scripts/build/builders/cyw30739.py b/scripts/build/builders/cyw30739.py index 9716540453de93..07ee65ca2ff7a2 100644 --- a/scripts/build/builders/cyw30739.py +++ b/scripts/build/builders/cyw30739.py @@ -21,12 +21,15 @@ class Cyw30739App(Enum): LIGHT = auto() LOCK = auto() + OTA_REQUESTOR = auto() def ExampleName(self): if self == Cyw30739App.LIGHT: return "lighting-app" elif self == Cyw30739App.LOCK: return "lock-app" + elif self == Cyw30739App.OTA_REQUESTOR: + return "ota-requestor-app" else: raise Exception("Unknown app type: %r" % self) @@ -35,6 +38,8 @@ def AppNamePrefix(self): return "chip-cyw30739-lighting-example" elif self == Cyw30739App.LOCK: return "chip-cyw30739-lock-example" + elif self == Cyw30739App.OTA_REQUESTOR: + return "chip-cyw30739-ota-requestor-example" else: raise Exception("Unknown app type: %r" % self) diff --git a/scripts/build/testdata/all_targets_except_host.txt b/scripts/build/testdata/all_targets_except_host.txt index 00567e44bb7e1a..f66693280c8b5d 100644 --- a/scripts/build/testdata/all_targets_except_host.txt +++ b/scripts/build/testdata/all_targets_except_host.txt @@ -16,6 +16,7 @@ android-x64-chip-tool android-x86-chip-tool cyw30739-cyw930739m2evb_01-light cyw30739-cyw930739m2evb_01-lock +cyw30739-cyw930739m2evb_01-ota-requestor efr32-brd4161a-light efr32-brd4161a-light-rpc efr32-brd4161a-lock diff --git a/scripts/build/testdata/build_all_except_host.txt b/scripts/build/testdata/build_all_except_host.txt index 3b6e7cd0091e8c..13c0648b3cb5da 100644 --- a/scripts/build/testdata/build_all_except_host.txt +++ b/scripts/build/testdata/build_all_except_host.txt @@ -172,6 +172,9 @@ gn gen --check --fail-on-unused-args --export-compile-commands --root={root}/exa # Generating cyw30739-cyw930739m2evb_01-lock gn gen --check --fail-on-unused-args --export-compile-commands --root={root}/examples/lock-app/cyw30739 {out}/cyw30739-cyw930739m2evb_01-lock +# Generating cyw30739-cyw930739m2evb_01-ota-requestor +gn gen --check --fail-on-unused-args --export-compile-commands --root={root}/examples/ota-requestor-app/cyw30739 {out}/cyw30739-cyw930739m2evb_01-ota-requestor + # Generating efr32-brd4161a-light gn gen --check --fail-on-unused-args --export-compile-commands --root={root}/examples/lighting-app/efr32 '--args=efr32_board="BRD4161A"' {out}/efr32-brd4161a-light @@ -880,6 +883,9 @@ ninja -C {out}/cyw30739-cyw930739m2evb_01-light # Building cyw30739-cyw930739m2evb_01-lock ninja -C {out}/cyw30739-cyw930739m2evb_01-lock +# Building cyw30739-cyw930739m2evb_01-ota-requestor +ninja -C {out}/cyw30739-cyw930739m2evb_01-ota-requestor + # Building efr32-brd4161a-light ninja -C {out}/efr32-brd4161a-light diff --git a/scripts/build/testdata/glob_star_targets_except_host.txt b/scripts/build/testdata/glob_star_targets_except_host.txt index 24d45175162476..8690ba8d9a39b9 100644 --- a/scripts/build/testdata/glob_star_targets_except_host.txt +++ b/scripts/build/testdata/glob_star_targets_except_host.txt @@ -16,6 +16,7 @@ android-x64-chip-tool android-x86-chip-tool cyw30739-cyw930739m2evb_01-light cyw30739-cyw930739m2evb_01-lock +cyw30739-cyw930739m2evb_01-ota-requestor efr32-brd4161a-light efr32-brd4161a-light-rpc efr32-brd4161a-lock diff --git a/src/platform/CYW30739/BUILD.gn b/src/platform/CYW30739/BUILD.gn index d5c2f29692cfd9..bbe503441865f7 100644 --- a/src/platform/CYW30739/BUILD.gn +++ b/src/platform/CYW30739/BUILD.gn @@ -52,10 +52,15 @@ static_library("CYW30739") { "cycfg_gatt_db.c", "cycfg_gatt_db.h", "cyw30739-chip-mbedtls-config.h", - "wiced_button_manager.c", - "wiced_led_manager.c", ] + if (chip_enable_ota_requestor) { + sources += [ + "OTAImageProcessorImpl.cpp", + "OTAImageProcessorImpl.h", + ] + } + deps = [ "${chip_root}/src/crypto" ] public_deps = [ "${chip_root}/src/platform:platform_base" ] diff --git a/src/platform/CYW30739/OTAImageProcessorImpl.cpp b/src/platform/CYW30739/OTAImageProcessorImpl.cpp new file mode 100644 index 00000000000000..1058afb042b501 --- /dev/null +++ b/src/platform/CYW30739/OTAImageProcessorImpl.cpp @@ -0,0 +1,217 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "OTAImageProcessorImpl.h" + +namespace chip { + +CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Finalize() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Apply() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleApply, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Abort() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleAbort, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) +{ + if ((block.data() == nullptr) || block.empty()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Store block data for HandleProcessBlock to access + CHIP_ERROR err = SetBlock(block); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format()); + } + + DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + + if (!wiced_firmware_upgrade_prepare()) + { + ChipLogError(SoftwareUpdate, "wiced_firmware_upgrade_prepare"); + return; + } + + imageProcessor->mParams.downloadedBytes = 0; + + imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); +} + +void OTAImageProcessorImpl::HandleFinalize(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + if (!wiced_firmware_upgrade_finalize()) + { + ChipLogError(SoftwareUpdate, "Failed to finalize OTA upgrade"); + return; + } + + imageProcessor->ReleaseBlock(); + + ChipLogProgress(SoftwareUpdate, "OTA image downloaded"); +} + +void OTAImageProcessorImpl::HandleApply(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + if (!wiced_firmware_upgrade_apply()) + { + ChipLogError(SoftwareUpdate, "Failed to apply OTA upgrade"); + return; + } + + ChipLogProgress(SoftwareUpdate, "OTA upgrade completed"); + + wiced_hal_wdog_reset_system(); +} + +void OTAImageProcessorImpl::HandleAbort(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + wiced_firmware_upgrade_abort(); + + ChipLogError(SoftwareUpdate, "OTA upgrade was aborted"); + + imageProcessor->ReleaseBlock(); +} + +void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + + if (IsSpanUsable(imageProcessor->mBlock)) + { + const uint32_t written = wiced_firmware_upgrade_process_block(imageProcessor->mParams.downloadedBytes, + imageProcessor->mBlock.data(), imageProcessor->mBlock.size()); + if (written != imageProcessor->mBlock.size()) + { + ChipLogError(SoftwareUpdate, "wiced_firmware_upgrade_process_block 0x%08lx", written); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + } + + imageProcessor->mParams.downloadedBytes += imageProcessor->mBlock.size(); + imageProcessor->mDownloader->FetchNextData(); +} + +CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) +{ + if (!IsSpanUsable(block)) + { + ReleaseBlock(); + return CHIP_NO_ERROR; + } + if (mBlock.size() < block.size()) + { + if (!mBlock.empty()) + { + ReleaseBlock(); + } + uint8_t * mBlock_ptr = static_cast(chip::Platform::MemoryAlloc(block.size())); + if (mBlock_ptr == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + mBlock = MutableByteSpan(mBlock_ptr, block.size()); + } + CHIP_ERROR err = CopySpanToMutableSpan(block, mBlock); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot copy block data: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ReleaseBlock() +{ + if (mBlock.data() != nullptr) + { + chip::Platform::MemoryFree(mBlock.data()); + } + + mBlock = MutableByteSpan(); + return CHIP_NO_ERROR; +} + +} // namespace chip diff --git a/src/platform/CYW30739/OTAImageProcessorImpl.h b/src/platform/CYW30739/OTAImageProcessorImpl.h new file mode 100644 index 00000000000000..6782ea190d192b --- /dev/null +++ b/src/platform/CYW30739/OTAImageProcessorImpl.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace chip { + +class OTAImageProcessorImpl : public OTAImageProcessorInterface +{ +public: + //////////// OTAImageProcessorInterface Implementation /////////////// + CHIP_ERROR PrepareDownload() override; + CHIP_ERROR Finalize() override; + CHIP_ERROR Apply() override; + CHIP_ERROR Abort() override; + CHIP_ERROR ProcessBlock(ByteSpan & block) override; + + void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; } + +private: + //////////// Actual handlers for the OTAImageProcessorInterface /////////////// + static void HandlePrepareDownload(intptr_t context); + static void HandleFinalize(intptr_t context); + static void HandleApply(intptr_t context); + static void HandleAbort(intptr_t context); + static void HandleProcessBlock(intptr_t context); + + /** + * Called to allocate memory for mBlock if necessary and set it to block + */ + CHIP_ERROR SetBlock(ByteSpan & block); + + /** + * Called to release allocated memory for mBlock + */ + CHIP_ERROR ReleaseBlock(); + + MutableByteSpan mBlock; + OTADownloader * mDownloader; +}; + +} // namespace chip diff --git a/third_party/cyw30739_sdk/btp_reader.py b/third_party/cyw30739_sdk/btp_reader.py index 4a1de71dcd740e..9dface1ff0b485 100644 --- a/third_party/cyw30739_sdk/btp_reader.py +++ b/third_party/cyw30739_sdk/btp_reader.py @@ -1,27 +1,46 @@ #!/usr/bin/env python +import argparse import json +import pathlib import sys def main(): - btp_file = sys.argv[1] + parser = argparse.ArgumentParser() + parser.add_argument("--btp", required=True, type=pathlib.Path) + parser.add_argument("--enable_ota", action="store_true") + + option = parser.parse_args() items = {} - with open(btp_file) as btp: + with open(option.btp) as btp: for line in btp: item = line.strip().split("=") if len(item) == 2: key = item[0].strip() value = item[1].strip() - items[key] = value - - items["XIP_DS_OFFSET"] = "0x0001e000" - items["XIP_LEN"] = "0x{:08x}".format( - int(items["ConfigDS2Location"], 16) - - int(items["ConfigDSLocation"], 16) - - int(items["XIP_DS_OFFSET"], 16) - ) + + if value.startswith('"'): + items[key] = value.strip('"') + else: + items[key] = int(value, 0) + + items["XS_LOCATION_ACTIVE"] = 0x0052E000 + + if option.enable_ota: + items["XS_LOCATION_UPGRADE"] = 0x005A3000 + else: + items["XS_LOCATION_UPGRADE"] = 0x00600000 + + items["XIP_DS_OFFSET"] = items["XS_LOCATION_ACTIVE"] - \ + items["ConfigDSLocation"] + items["XIP_LEN"] = items["XS_LOCATION_UPGRADE"] - \ + items["XS_LOCATION_ACTIVE"] + + for key in items: + if type(items[key]) is int: + items[key] = "0x{:08x}".format(items[key]) print(json.dumps(items)) return 0 diff --git a/third_party/cyw30739_sdk/cyw30739_executable.gni b/third_party/cyw30739_sdk/cyw30739_executable.gni index ca2e92fbd6ca3c..a99793e0198b7b 100644 --- a/third_party/cyw30739_sdk/cyw30739_executable.gni +++ b/third_party/cyw30739_sdk/cyw30739_executable.gni @@ -35,10 +35,14 @@ template("cyw30739_executable") { executable_target = ":${flashable_target}.executable" } + cyw30739_sdk_ota_image("${target_name}.ota_image") { + deps = [ ":${invoker.target_name}.post_build" ] + } + group(target_name) { deps = [ ":${flashable_target}", - ":${target_name}.post_build", + ":${target_name}.ota_image", ] } diff --git a/third_party/cyw30739_sdk/cyw30739_sdk.gni b/third_party/cyw30739_sdk/cyw30739_sdk.gni index c041b955bf0c5e..2a4e06e11224d2 100644 --- a/third_party/cyw30739_sdk/cyw30739_sdk.gni +++ b/third_party/cyw30739_sdk/cyw30739_sdk.gni @@ -13,8 +13,11 @@ # limitations under the License. import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") import("//build_overrides/cyw30739_sdk.gni") +import("${chip_root}/src/platform/device.gni") + declare_args() { # Location of the CYW30739 SDK. cyw30739_sdk_root = "${cyw30739_sdk_build_root}/repos" @@ -32,7 +35,7 @@ cyw30739_sdk_patch_dir = "${cyw30739_sdk_baselib_dir}/internal/30739A0/patches_CYW930739M2EVB_01" cyw30739_sdk_platform_dir = "${cyw30739_sdk_baselib_dir}/platforms" cyw30739_sdk_scripts_dir = "${cyw30739_sdk_baselib_dir}/make/scripts" -cyw30739_sdk_btp_file = "${cyw30739_sdk_platform_dir}/flash.btp" +cyw30739_sdk_btp_file = "${cyw30739_sdk_build_root}/flash.btp" cyw30739_sdk_patch_sym_file = "${cyw30739_sdk_patch_dir}/patch.sym" cyw30739_sdk_tools_dir = "${cyw30739_sdk_root}/btsdk-tools/" @@ -44,6 +47,15 @@ if (host_os == "linux") { cyw30739_sdk_tools_dir += "Windows" } +btp_reader_args = + [ "--btp=" + rebase_path(cyw30739_sdk_btp_file, root_build_dir) ] +if (chip_enable_ota_requestor) { + btp_reader_args += [ "--enable_ota" ] +} +btp = exec_script("${cyw30739_sdk_build_root}/btp_reader.py", + btp_reader_args, + "json") + template("cyw30739_sdk_script") { action(target_name) { forward_variables_from(invoker, @@ -88,17 +100,17 @@ template("cyw30739_sdk") { assert(cyw30739_sdk_root != "", "cyw30739_sdk_root must be specified") + if (is_debug) { + enable_debug = 1 + } else { + enable_debug = 0 + } + config("${target_name}_config") { include_dirs = [] defines = [] libs = [] - if (is_debug) { - enable_debug = 1 - } else { - enable_debug = 0 - } - if (defined(invoker.include_dirs)) { include_dirs += invoker.include_dirs } @@ -119,14 +131,6 @@ template("cyw30739_sdk") { "${cyw30739_sdk_include_dir}", ] - defines += [ - "CHIP_HAVE_CONFIG_H=1", - "CY_PLATFORM_SWDCK=WICED_P05", - "CY_PLATFORM_SWDIO=WICED_P03", - "ENABLE_DEBUG=${enable_debug}", - "SPAR_CRT_SETUP=spar_crt_setup", - ] - cflags = [ "--specs=nano.specs" ] if (is_debug) { cflags += [ "-Wno-unused" ] @@ -174,15 +178,40 @@ template("cyw30739_sdk") { "${cyw30739_sdk_bsp_design_modus_dir}/cycfg_pins.c", "${cyw30739_sdk_bsp_design_modus_dir}/cycfg_pins.h", "${cyw30739_sdk_bsp_design_modus_dir}/cycfg_routing.h", + "${cyw30739_sdk_build_root}/include/auto_flags.h", + "${cyw30739_sdk_build_root}/include/wiced_button_manager.h", + "${cyw30739_sdk_build_root}/include/wiced_led_manager.h", "${cyw30739_sdk_build_root}/src/platform_retarget_lock.c", + "${cyw30739_sdk_build_root}/src/wiced_button_manager.c", + "${cyw30739_sdk_build_root}/src/wiced_led_manager.c", ] + if (chip_enable_ota_requestor) { + sources += [ + "${cyw30739_sdk_build_root}/include/ota_fw_upgrade.h", + "${cyw30739_sdk_build_root}/src/ota_fw_upgrade.c", + ] + } + sources += get_target_outputs(":${target_name}_gen_lib_installer") if (defined(invoker.sources)) { sources += invoker.sources } + defines = [ + "CHIP_HAVE_CONFIG_H=1", + "CY_PLATFORM_SWDCK=WICED_P05", + "CY_PLATFORM_SWDIO=WICED_P03", + "ENABLE_DEBUG=${enable_debug}", + "SPAR_CRT_SETUP=spar_crt_setup", + "XS_LOCATION_ACTIVE=" + btp.XS_LOCATION_ACTIVE, + "XS_LOCATION_UPGRADE=" + btp.XS_LOCATION_UPGRADE, + ] + if (chip_enable_ota_requestor) { + defines += [ "BLE_OTA_FW_UPGRADE=1" ] + } + public_configs = [ ":${target_name}_config" ] deps = [ ":${target_name}_gen_lib_installer" ] @@ -193,10 +222,6 @@ template("cyw30739_sdk_pre_build") { cyw30739_sdk_script(target_name) { script_file_name = "bt_pre_build.bash" - btp = exec_script("${cyw30739_sdk_build_root}/btp_reader.py", - [ rebase_path(cyw30739_sdk_btp_file, root_build_dir) ], - "json") - linker_defines = [ "FLASH0_BEGIN_ADDR=" + btp.DLConfigSSLocation, "FLASH0_LENGTH=0x00100000", @@ -279,3 +304,25 @@ template("cyw30739_sdk_post_build") { ] } } + +template("cyw30739_sdk_ota_image") { + action(target_name) { + forward_variables_from(invoker, [ "deps" ]) + + script = "${cyw30739_sdk_build_root}/gen_ota_image.py" + + binary = "${root_out_dir}/${invoker.output_base_name}_download.ota.bin" + hex = "${root_out_dir}/${invoker.output_base_name}_download.hex" + + outputs = [ binary ] + + inputs = [ hex ] + + args = [ + "--binary=" + rebase_path(binary, root_build_dir), + "--hex=" + rebase_path(hex, root_build_dir), + "--lzss_tool=" + + rebase_path(cyw30739_sdk_tools_dir + "/lzss/lzss", root_build_dir), + ] + } +} diff --git a/third_party/cyw30739_sdk/flash.btp b/third_party/cyw30739_sdk/flash.btp new file mode 100644 index 00000000000000..71a08c458067ce --- /dev/null +++ b/third_party/cyw30739_sdk/flash.btp @@ -0,0 +1,53 @@ +DevicePreset "30739 Flash" +{ + ConfigFSOffset = 0 + DLReadWriteMode = "Cortex M3 HCI" + DLWriteVerifyMode = "Write and verify" + DLMaxWriteSize = 240 + DLSectorEraseMode = "Chip erase" + MinidriverRebaudRate = 3000000 + DLDTRReset = 0 + DLPostResetDelay_ms = 100 + DLAutobaud = 0 + DLAutobaudRepeat = 1 + DLAutobaudRepeatDelay_ms = 200 + DLWaitForLaunchAnnounce = 0 + DLConfigReprogramIF_PLL = 0 + DLUsbBulkPipe = 0 + DLMinidriver = 1 + DLMinidriverPathUSB = "[MINIDRIVERS]\30739\INVALID.hex" + DLMinidriverPathNET = "[MINIDRIVERS]\30739\INVALID.hex" + DLMinidriverPathSDIO = "[MINIDRIVERS]\30739\INVALID.hex" + DLMinidriverPathUPRX = "[MINIDRIVERS]\30739\INVALID.hex" + DLMinidriverPathUART = "[MINIDRIVERS]\30739\uart.hex" + DLFirmware = 1 + DLFirmwareTargeting = "Standard" + DLConfig = 1 + DLConfigTargeting = "Flash absolute" + ConfigPath = "" + DLConfigFixedHeader = 1 + DLConfigFixedHeaderFromBurnImage = 0 + DLConfigOmitRF_PLL = 1 + DLConfigIncludeChargerConfig = 0 + DLConfigDFUKey = 4294967295 + DLConfigCrystalFreqMHzX10000 = 240000 + DLConfigOutputPowerAdjust = 40 + DLConfigImpedanceMatchTuning = 31 + DLConfigSerialControlBaudRate = 115200 + DLConfigEEPROMAccessSpeed = 100 + DLConfigVSOffset = 0 + ConfigDSLocation = 0x508000 + ConfigDS2Location = 0x51b000 + DLConfigSSLocation = 0x500000 + DLConfigIncludeBTWSecurityKey = 0 + DLConfigVSLocation = 0x501000 + DLConfigVSLength = 0x2000 + DLConfigRemoteDeviceCount = 0 + DLConfigBD_ADDRBase = "30739A0*****" + DLConfigFixedBD_ADDRFlag = "Can change" + OTAFWUAckAllRecords = 0 + OTAFWUUpdateFirmware = 1 + OTAFWUUpdateConfig = 1 + CustomSkipInitialHCIReset = 0 + CustomHCIResetTimeoutMS = 5000 +} diff --git a/third_party/cyw30739_sdk/gen_ota_image.py b/third_party/cyw30739_sdk/gen_ota_image.py new file mode 100644 index 00000000000000..e5d143ad6b6b04 --- /dev/null +++ b/third_party/cyw30739_sdk/gen_ota_image.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +import argparse +import pathlib +import subprocess +import sys +import zlib + +from intelhex import IntelHex +from struct import pack, pack_into + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--binary", required=True, type=pathlib.Path) + parser.add_argument("--hex", required=True, type=pathlib.Path) + parser.add_argument("--lzss_tool", required=True, type=pathlib.Path) + + option = parser.parse_args() + + intel_hex = IntelHex(str(option.hex)) + ds_segment, xs_segment = intel_hex.segments()[1:3] + + ds_header = intel_hex.tobinarray( + start=ds_segment[0], end=ds_segment[0] + 0x10 - 1) + ds_data = intel_hex.tobinarray( + start=ds_segment[0] + 0x10, end=ds_segment[1] - 1) + xs_data = intel_hex.tobinarray(start=xs_segment[0], end=xs_segment[1] - 1) + + # Align to 4 bytes + ds_data = pad_data(ds_data, 4) + xs_data = pad_data(xs_data, 4) + + # Pad XS data CRC to DS data + xs_crc = zlib.crc32(xs_data) + ds_data += pack(" +#include + +void wiced_firmware_upgrade_bootloader(void); +bool wiced_firmware_upgrade_prepare(void); +uint32_t wiced_firmware_upgrade_process_block(uint32_t offset, uint8_t * data, uint32_t len); +bool wiced_firmware_upgrade_finalize(void); +bool wiced_firmware_upgrade_apply(void); +void wiced_firmware_upgrade_abort(void); + +#ifdef __cplusplus +} +#endif diff --git a/third_party/cyw30739_sdk/src/ota_fw_upgrade.c b/third_party/cyw30739_sdk/src/ota_fw_upgrade.c new file mode 100644 index 00000000000000..3ed38600459895 --- /dev/null +++ b/third_party/cyw30739_sdk/src/ota_fw_upgrade.c @@ -0,0 +1,591 @@ +/* + * Copyright 2016-2021, Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation. All rights reserved. + * + * This software, including source code, documentation and related + * materials ("Software") is owned by Cypress Semiconductor Corporation + * or one of its affiliates ("Cypress") and is protected by and subject to + * worldwide patent protection (United States and foreign), + * United States copyright laws and international treaty provisions. + * Therefore, you may use this Software only as provided in the license + * agreement accompanying the software package from which you + * obtained this Software ("EULA"). + * If no EULA applies, Cypress hereby grants you a personal, non-exclusive, + * non-transferable license to copy, modify, and compile the Software + * source code solely for use in connection with Cypress's + * integrated circuit products. Any reproduction, modification, translation, + * compilation, or representation of this Software except as specified + * above is prohibited without the express written permission of Cypress. + * + * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress + * reserves the right to make changes to the Software without notice. Cypress + * does not assume any liability arising out of the application or use of the + * Software or any product or circuit described in the Software. Cypress does + * not authorize its products for use in any products where a malfunction or + * failure of the Cypress product may reasonably be expected to result in + * significant property damage, injury or death ("High Risk Product"). By + * including Cypress's product in a High Risk Product, the manufacturer + * of such system or application assumes all risk of such use and in doing + * so agrees to indemnify Cypress against all liability. + */ + +/** @file + * + * WICED Firmware Upgrade internal definitions specific to shim layer + * + * This file provides common functions required to support WICED Smart Ready Upgrade + * whether it is being done over the air, UART, or SPI. Primarily the + * functionality is provided for storing and retrieving information from Serial Flash + * The data being stored is DS portion of burn image generated from CGS. + */ +#include +#include +#include +#include +#include + +#define EF_PAGE_SIZE (0x1000u) + +//================================================================================================== +// Types +//================================================================================================== +//! Structure for FOUNDATION_CONFIG_ITEM_ID_CONFIG_LAYOUT. +#pragma pack(1) +typedef struct +{ + //! Base address or offset of the failsafe (not upgradable) dynamic section base. This field + //! must be present. + UINT32 failsafe_ds_base; + + //! Base address or offset of the upgradable dynamic section base. This field is optional for + //! media types for which DFU is supported. + UINT32 upgradable_ds_base; + + //! Base address or offset to the area reserved for volatile section copy 1. Whether this is an + //! address or offset depends on the media type, and is an internal detail of those media types' + //! access functions. Double-buffering of the volatile section alternates between the two + //! copies when the active copy fills up and has to be consolidated to the other. The volatile + //! section stores information that is mutable at runtime, and is therefore subject to loss if a + //! write operation is interrupted by loss of power. Only an item that is currently being + //! written is subject to loss. Generally, NVRAM media with large page sizes (like flash) use + //! double-buffering, while media with small page sizes (like EEPROM) allocate one or more + //! complete pages per volatile section item. + UINT32 vs_copy1_base; + + //! Base address or offset to the area reserved for volatile section copy 2. Whether this is an + //! address or offset depends on the media type, and is an internal detail of those media types' + //! access functions. See the documentation for vs_copy1_base, but note that not all media + //! types use double-buffering. + UINT32 vs_copy2_base; + + //! Length in bytes per copy of the area reserved for each volatile section copy. If the target + //! media uses double buffering to protect against loss, the total space used by the volatile + //! section is twice this amount. See the documentation for vs_copy1_base and vs_copy1_base. + UINT32 vs_length_per_copy; + + //! Block size for volatile section items. For media with small page sizes (like EEPROM) which + //! allocate one or more pages per volatile section item, blocks must be a multiple of the media + //! page size. + UINT32 vs_block_size; + + //! Media page size. This info is needed for managing volatile section contents. + UINT32 media_page_size; +} FOUNDATION_CONFIG_ITEM_CONFIG_LAYOUT_t; +#pragma pack() + +//! Enumeration used to specify one of the three sections of config data. +//!

+//! If config data is stored in NVRAM: +//!

+//! Static section is written once during manufacturing, and never again. This section includes +//! per-device information like crystal trimming information and an assigned address like BD_ADDR +//! for Bluetooth devices or a MAC address for ethernet or WLAN devices. The static section also +//! includes key layout information like whether a volatile section is present and if so, where it +//! is located. +//!

+//! Dynamic section is written during manufacturing. This section might be subject to upgrades in +//! the field, by the end user. An example of such an upgrade process is USB device firmware +//! upgrade. If this section is subject to upgrade in the field, then a failsafe config must be +//! present, which if present would either force the device into an upgrade-only mode, or fall back +//! to the un-upgraded behavior it would have exhibited when it left the factory. +//!

+//! Volatile section is used to hold information that can change at runtime, for example storing +//! pairing information for pairing with other devices. The volatile section is implemented as +//! failsafe as possible for the target media, such that the most recently written "nugget" of +//! information is subject to loss, but contents that were present before a given write operation +//! will be preserved. +//!

+//! The "volatile" nomenclature is somewhat misleading because this section is only ever present on +//! NVRAM (nonvolatile memory). The "volatile" nomenclature is simply used to highlight the fact +//! that the contents are subject to loss. This is generally a non-issue, but if multiple "nuggets" +//! of information are interdependent but written independently, then it is possible for one +//! "nugget" in the interdependent set to be lost, in which case the firmware that uses this +//! information needs to be ready to recognize that situation and take appropriate action to discard +//! or if possible repair the rest of the set. If no "nuggets" of volatile information form +//! interdependent sets then loss of power during a write operation is functionally equivalent to +//! loss of power immediately before the write operation was initiated. +//!

+//! If config data is stored in RAM (downloaded by the host): +//!

+//! Only the static and dynamic sections are relevant. The distinction between the two halves is +//! more or less irrelevant, merely being a reflection of the NVRAM organization. Nonetheless, the +//! location in which certain pieces of information are stored is influenced by the NVRAM +//! organization. A volatile section should never be specified for RAM config data. +typedef enum +{ + //! Configuration data section containing per-device information and key layout information. + //! The layout information communicates to firmware where to find the rest of the configuration + //! data. See the documentation for the config_section_id_t enumeration as a whole for more + //! complete info. + CONFIG_STATIC, + + //! Configuration data section containing per-product or product family information. See the + //! documentation for the config_section_id_t enumeration as a whole for more complete info. + CONFIG_DYNAMIC, + + //! Configuration data section in NVRAM containing information that can be changed at runtime. + //! This refers to info that needs to be preserved across resets or power cycles. See the + //! documentation for the config_section_id_t enumeration as a whole for more complete info, + //! including where the seemingly contradictory name comes from. + CONFIG_VOLATILE +} config_section_id_t; + +//! \internal +//! Structure used internally by the config module to achieve config media abstraction. It stores +//! layout information for any supported config data media type, as well as media-specific function +//! pointers for various tasks. +typedef struct +{ + //! Access function pointer to read raw data from the media on which config data is stored. + void (*fp_ReadRaw)(int offset, config_section_id_t which_section, OUT BYTE * buffer, int length); + + //! Access function pointer to write raw data to the media on which config data is stored. + void (*fp_WriteRaw)(int offset, config_section_id_t which_section, IN BYTE * buffer, int length); + + //! Address of the static section. + UINT32 ss_base; + + //! Function to handle when the layout config item below has been filled in. It will have been + //! filled in using content from the static section, then this function will be called. + void (*fp_ConfigLayoutHasBeenSet)(void); + + //! Address of the valid dynamic section (which might be the failsafe copy, or might be the + //! upgradable copy). + UINT32 active_ds_base; + + //! Access function pointer to read a volatile section item from config data. The function is + //! presented as being specific to the type of media, but it really reflects the partitioning + //! scheme used by this media as dictated by its physical page size. The truly media-specific + //! access function is in fp_ReadRaw. + UINT16 (*fp_ReadVolatileSectionItem)(UINT16 group_id, UINT16 sub_id_in_group, OUT BYTE * buffer, UINT16 max_length); + + //! Access function pointer to write a volatile section item to config data. The function is + //! presented as being specific to the type of media, but it really reflects the partitioning + //! scheme used by this media as dictated by its physical page size. The truly media-specific + //! access function is in fp_WriteRaw. + void (*fp_WriteVolatileSectionItem)(UINT16 group_id, UINT16 sub_id_in_group, IN BYTE * buffer, UINT16 length); + + //! Layout info, retrieved from the static section. + FOUNDATION_CONFIG_ITEM_CONFIG_LAYOUT_t layout; + + //! Checksum/CRC info for validating segment by segment in the dynamic section. + UINT32 checksum; + UINT32 crc32; + BOOL8 valid_crc32; + + //! Used to allow faster access to the config if it is memory mapped (not in serial flash for example) + BOOL8 direct_access; + + //! Whether a valid DS section was found or not. + BOOL8 valid_ds_found; +} CONFIG_INFO_t; + +typedef struct ds_header +{ + char signature[8]; + uint32_t crc32; + uint32_t length; + uint8_t data[0]; +} ds_header_t; + +typedef struct upgrade_xs +{ + ds_header_t ds_header; + uint32_t crc32; + uint32_t length; + uint32_t compressed_data_crc32; + uint32_t compressed_data_length; + uint8_t compressed_data[0]; +} upgrade_xs_t; + +extern const CONFIG_INFO_t g_config_Info; + +static uint32_t upgrade_location_write(uint32_t offset, uint8_t * data, uint32_t len); +static bool upgrade_location_erase(uint32_t offset, uint8_t * data); +static bool lzss_decompress(const void * src, size_t n, bool (*data_writer)(uint32_t, int)) + __attribute__((section(".text_in_ram"))); +static bool xs_data_writer(uint32_t data_offset, int c) __attribute__((section(".text_in_ram"))); +static uint32_t calc_crc32(const uint8_t * buf, uint32_t len) __attribute__((section(".text_in_ram"))); +static uint32_t ef_offset(uint32_t offset) __attribute__((section(".text_in_ram"))); +static uint32_t upgrade_ds_location(void); + +/****************************************************** + * Function Definitions + ******************************************************/ +__attribute__((section(".init_code"))) void wiced_firmware_upgrade_bootloader(void) +{ + const ds_header_t * ds_header = (const ds_header_t *) g_config_Info.active_ds_base; + const upgrade_xs_t * upgrade_xs = (upgrade_xs_t *) XS_LOCATION_UPGRADE; + + /* Check the DS header of the upgrade XS */ + if (memcmp(&upgrade_xs->ds_header, ds_header, sizeof(*ds_header)) != 0) + { + return; + } + + /* Erase the active XS */ + if (WICED_SUCCESS != wiced_hal_eflash_erase(ef_offset(XS_LOCATION_ACTIVE), upgrade_xs->length)) + { + return; + } + + /* Copy the upgrade XS to the active XS */ + if (!lzss_decompress(upgrade_xs->compressed_data, upgrade_xs->compressed_data_length, xs_data_writer)) + { + goto reset; + } + + /* Verify the active XS */ + if (calc_crc32((void *) XS_LOCATION_ACTIVE, upgrade_xs->length) != upgrade_xs->crc32) + goto reset; + + /* Erase the upgrade XS */ + wiced_hal_eflash_erase(ef_offset(XS_LOCATION_UPGRADE), EF_PAGE_SIZE); + + return; + +reset: + wiced_hal_wdog_reset_system(); + while (1) + ; +} + +bool wiced_firmware_upgrade_prepare(void) +{ + const uint32_t ds1_location = g_config_Info.layout.failsafe_ds_base; + const uint32_t ds1_length = g_config_Info.layout.upgradable_ds_base - g_config_Info.layout.failsafe_ds_base; + const uint32_t ds2_location = g_config_Info.layout.upgradable_ds_base; + const uint32_t ds2_length = XS_LOCATION_ACTIVE - g_config_Info.layout.upgradable_ds_base; + + printf("DS1: 0x%08lx, len: 0x%08lx\n", ds1_location, ds1_length); + printf("DS2: 0x%08lx, len: 0x%08lx\n", ds2_location, ds2_length); + printf("Active DS: 0x%08x\n", g_config_Info.active_ds_base); + printf("Active XS: 0x%08x\n", XS_LOCATION_ACTIVE); + printf("Upgrade XS: 0x%08x\n", XS_LOCATION_UPGRADE); + + return upgrade_ds_location() != 0; +} + +uint32_t wiced_firmware_upgrade_process_block(uint32_t offset, uint8_t * data, uint32_t len) +{ + const ds_header_t * ds_header = (const ds_header_t *) upgrade_ds_location(); + + if (offset == 0) + { + ds_header = (const ds_header_t *) data; + } + else + { + ds_header = (const ds_header_t *) upgrade_ds_location(); + } + + const uint32_t ds_length = sizeof(*ds_header) + ds_header->length; + uint32_t ds_write_length; + uint32_t xs_write_length; + if (offset < ds_length) + { + if (offset + len <= ds_length) + { + ds_write_length = len; + xs_write_length = 0; + } + else + { + ds_write_length = ds_length - offset; + xs_write_length = len - ds_write_length; + } + } + else + { + ds_write_length = 0; + xs_write_length = len; + } + + uint32_t byte_written = 0; + if (ds_write_length > 0) + { + const uint32_t ds_offset = offset + upgrade_ds_location(); + byte_written += upgrade_location_write(ds_offset, data, ds_write_length); + } + if (xs_write_length > 0) + { + const uint32_t xs_offset = offset + ds_write_length - ds_length + XS_LOCATION_UPGRADE; + byte_written += upgrade_location_write(xs_offset, data + ds_write_length, xs_write_length); + } + return byte_written; +} + +bool upgrade_location_erase(uint32_t offset, uint8_t * data) +{ + uint32_t erase_length; + if (offset == upgrade_ds_location()) + { + const ds_header_t * ds_header = (const ds_header_t *) data; + erase_length = sizeof(*ds_header) + ds_header->length; + } + else if (offset == XS_LOCATION_UPGRADE) + { + const upgrade_xs_t * upgrade_xs = (const upgrade_xs_t *) data; + erase_length = sizeof(*upgrade_xs) + upgrade_xs->compressed_data_length; + } + else + { + return true; + } + + if (erase_length != 0) + { + printf("Erasing 0x%08lx, len: %lu\n", offset, erase_length); + if (WICED_SUCCESS != wiced_hal_eflash_erase(ef_offset(offset), erase_length)) + { + printf("ERROR erase\n"); + return false; + } + } + + return true; +} + +uint32_t upgrade_location_write(uint32_t offset, uint8_t * data, uint32_t len) +{ + if (!upgrade_location_erase(offset, data)) + { + return 0; + } + + // reserve first 4 bytes of download to commit when complete, in case of unexpected power loss + // boot rom checks this signature to validate DS + uint32_t offset_adjustment; + if (offset == upgrade_ds_location()) + { + offset_adjustment = 4; + } + else + { + offset_adjustment = 0; + } + offset += offset_adjustment; + data += offset_adjustment; + len -= offset_adjustment; + + printf("write: offset: 0x%08lx len: %lu\n", offset, len); + /* write length should in words */ + if (wiced_hal_eflash_write(ef_offset(offset), data, (len + 3) & 0xfffffffc) == WICED_SUCCESS) + { + return len + offset_adjustment; + } + else + { + printf("ERROR write\n"); + return 0; + } +} + +bool wiced_firmware_upgrade_finalize(void) +{ + const ds_header_t * ds_header = (ds_header_t *) upgrade_ds_location(); + const upgrade_xs_t * upgrade_xs = (upgrade_xs_t *) XS_LOCATION_UPGRADE; + + const uint32_t ds_crc32 = calc_crc32(ds_header->data, ds_header->length); + const uint32_t cx_crc32 = calc_crc32(upgrade_xs->compressed_data, upgrade_xs->compressed_data_length); + + printf("DS: length 0x%08lx, crc32 0x%08lx\n", ds_header->length, ds_crc32); + printf("XS: length 0x%08lx, crc32 0x%08lx\n", upgrade_xs->length, upgrade_xs->crc32); + printf("CX: length 0x%08lx, crc32 0x%08lx\n", upgrade_xs->compressed_data_length, cx_crc32); + + return ds_header->crc32 == ds_crc32 && upgrade_xs->compressed_data_crc32 == cx_crc32; +} + +bool wiced_firmware_upgrade_apply(void) +{ + enum + { + SIGNATURE = 0x4d435242, + }; + wiced_result_t result; + uint32_t signature = SIGNATURE; + + printf("Switching DS to 0x%08lx\n", upgrade_ds_location()); + + // commit reserved first 4 bytes of download to complete + // this is done last and after crc in case of power loss during download + // boot rom checks this signature to validate DS, checking DS1 first, then DS2 + wiced_hal_eflash_write(ef_offset(upgrade_ds_location()), (uint8_t *) &signature, 4); + + // check that the write completed + wiced_hal_eflash_read(ef_offset(upgrade_ds_location()), (uint8_t *) &signature, 4); + if (signature != SIGNATURE) + { + return false; + } + + // clear first active DS sector in eflash, so that on next boot, CRC check will fail and ROM code boots from upgraded DS + result = wiced_hal_eflash_erase(ef_offset(g_config_Info.active_ds_base), EF_PAGE_SIZE); + printf("wiced_hal_eflash_erase status %d\n", result); + + return result == WICED_SUCCESS; +} + +void wiced_firmware_upgrade_abort(void) {} + +bool lzss_decompress(const void * src, size_t n, bool (*data_writer)(uint32_t, int)) +{ + enum + { + /* size of ring buffer */ + N = 4096, + /* upper limit for match_length */ + F = 18, + /* + * encode string into position and length + * if match_length is greater than this + */ + THRESHOLD = 2, + }; + + /* ring buffer of size N, with extra F-1 bytes to facilitate string comparison */ + static uint8_t ring_buf[N + F - 1]; + + int r; + int c; + unsigned int flags; + uint32_t offset = 0; + const uint8_t * s = src; + const uint8_t * s_stop = s + n; + + memset(ring_buf, 0, N - F); + + r = N - F; + flags = 0; + while (s != s_stop) + { + if (((flags >>= 1) & 0x100) == 0) + { + c = *s++; + flags = c | 0xff00; /* ues higher byte cleverly */ + } /* to count eight */ + if (flags & 1) + { + c = *s++; + ring_buf[r++] = c; + r &= N - 1; + if (!data_writer(offset++, c)) + return FALSE; + } + else + { + int i; + int patloc = *s++; + int patlen = *s++; + + patloc |= ((patlen & 0xf0) << 4); + patlen = (patlen & 0x0f) + THRESHOLD; + + for (i = 0; i <= patlen; i++) + { + c = ring_buf[(patloc + i) & (N - 1)]; + ring_buf[r++] = c; + r &= N - 1; + if (!data_writer(offset++, c)) + return FALSE; + } + } + } + return data_writer(offset, EOF); +} + +bool xs_data_writer(uint32_t data_offset, int c) +{ + static uint8_t xs_data_buf[EF_PAGE_SIZE]; + + const uint32_t offset = data_offset % sizeof(xs_data_buf); + + if (c != EOF) + { + xs_data_buf[offset] = c; + } + + uint32_t write_length = 0; + if (offset + 1 == sizeof(xs_data_buf)) + { + write_length = offset + 1; + } + else if (c == EOF) + { + write_length = offset; + } + + if (write_length > 0) + { + const uint32_t write_offset = XS_LOCATION_ACTIVE + data_offset - offset; + if (WICED_SUCCESS != wiced_hal_eflash_write(ef_offset(write_offset), xs_data_buf, write_length)) + { + return FALSE; + } + } + return TRUE; +} + +uint32_t calc_crc32(const uint8_t * buf, uint32_t len) +{ + uint32_t crc32_Update(uint32_t crc, const uint8_t * buf, uint16_t len); + uint32_t crc32 = 0xffffffff; + uint32_t i; + + for (i = 0; i < len; i += UINT16_MAX) + { + crc32 = crc32_Update(crc32, buf + i, MIN(len - i, UINT16_MAX)); + } + + return crc32 ^ 0xffffffff; +} + +uint32_t ef_offset(uint32_t offset) +{ + return offset - 0x00500000u; +} + +uint32_t upgrade_ds_location(void) +{ + if (g_config_Info.active_ds_base == g_config_Info.layout.failsafe_ds_base) + { + return g_config_Info.layout.upgradable_ds_base; + } + else if (g_config_Info.active_ds_base == g_config_Info.layout.upgradable_ds_base) + { + return g_config_Info.layout.failsafe_ds_base; + } + else + { + return 0; + } +} + +/* Dummy stub */ +wiced_bool_t wiced_ota_fw_upgrade_init(void * public_key, wiced_ota_firmware_upgrade_status_callback_t * p_status_callback, + wiced_ota_firmware_upgrade_send_data_callback_t * p_send_data_callback) +{ + return TRUE; +} diff --git a/src/platform/CYW30739/wiced_button_manager.c b/third_party/cyw30739_sdk/src/wiced_button_manager.c similarity index 100% rename from src/platform/CYW30739/wiced_button_manager.c rename to third_party/cyw30739_sdk/src/wiced_button_manager.c diff --git a/src/platform/CYW30739/wiced_led_manager.c b/third_party/cyw30739_sdk/src/wiced_led_manager.c similarity index 100% rename from src/platform/CYW30739/wiced_led_manager.c rename to third_party/cyw30739_sdk/src/wiced_led_manager.c