From 6b0796b9a4cb6080126a6dbb4b994ef0a9bafd09 Mon Sep 17 00:00:00 2001 From: Michael Spang Date: Tue, 3 Nov 2020 06:28:10 -0500 Subject: [PATCH] Remove support for nRF5 SDK for Thread & Zigbee The nRF5 SDK for Thread & Zigbee is deprecated and will not receive any feature updates or support for new parts. CHIP will support nRF5 SoCs via the nRF Connect SDK instead. Delete the support code for the nRF5 SDK for Thread & Zigbee, sample apps, and documentation. fixes #3604 --- .github/boring-cyborg.yml | 3 - .github/labeler.yml | 3 - .github/workflows/examples-nrf.yaml | 94 -- .vscode/c_cpp_properties.json | 12 - .vscode/tasks.json | 26 - BUILD.gn | 39 - build_overrides/nrf5_sdk.gni | 18 - config/nrf5/toolchain/BUILD.gn | 38 - docs/BUILDING.md | 8 +- docs/VSCODE_DEVELOPMENT.md | 2 +- examples/build_overrides/nrf5_sdk.gni | 18 - examples/common/nrf5/README.md | 16 - examples/common/nrf5/gdb/gdb-startup-cmds.txt | 38 - examples/common/nrf5/gdb/start-gdb.sh | 38 - .../common/nrf5/gdb/start-jlink-gdb-server.sh | 57 - examples/lighting-app/nrf5/.gn | 26 - examples/lighting-app/nrf5/BUILD.gn | 117 -- examples/lighting-app/nrf5/README.md | 248 ---- examples/lighting-app/nrf5/args.gni | 20 - examples/lighting-app/nrf5/build | 1 - examples/lighting-app/nrf5/build_overrides | 1 - examples/lighting-app/nrf5/main/AppTask.cpp | 571 --------- .../lighting-app/nrf5/main/LightingCLI.cpp | 214 ---- .../nrf5/main/LightingManager.cpp | 104 -- .../lighting-app/nrf5/main/ZclCallbacks.cpp | 69 - .../lighting-app/nrf5/main/include/AppEvent.h | 59 - .../lighting-app/nrf5/main/include/AppTask.h | 80 -- .../nrf5/main/include/LightingCLI.h | 3 - .../nrf5/main/include/LightingManager.h | 69 - .../nrf5/main/include/app_config.h | 141 --- examples/lighting-app/nrf5/main/main.cpp | 244 ---- .../nrf5/third_party/connectedhomeip | 1 - examples/lock-app/nrf5/.gn | 26 - examples/lock-app/nrf5/BUILD.gn | 109 -- examples/lock-app/nrf5/README.md | 253 ---- examples/lock-app/nrf5/args.gni | 20 - examples/lock-app/nrf5/build | 1 - examples/lock-app/nrf5/build_overrides | 1 - examples/lock-app/nrf5/main/AppTask.cpp | 597 --------- .../lock-app/nrf5/main/BoltLockManager.cpp | 217 ---- examples/lock-app/nrf5/main/ZclCallbacks.cpp | 71 -- .../lock-app/nrf5/main/include/AppEvent.h | 57 - examples/lock-app/nrf5/main/include/AppTask.h | 80 -- .../nrf5/main/include/BoltLockManager.h | 79 -- .../lock-app/nrf5/main/include/app_config.h | 142 --- examples/lock-app/nrf5/main/main.cpp | 244 ---- .../lock-app/nrf5/third_party/connectedhomeip | 1 - examples/pigweed-app/nrf5/.gn | 26 - examples/pigweed-app/nrf5/BUILD.gn | 77 -- examples/pigweed-app/nrf5/args.gni | 35 - examples/pigweed-app/nrf5/build | 1 - examples/pigweed-app/nrf5/build_overrides | 1 - .../nrf5/main/include/app_config.h | 143 --- examples/pigweed-app/nrf5/main/main.cpp | 101 -- .../nrf5/mobly_tests/pigweed_mobly_config.yml | 25 - .../nrf5/mobly_tests/pigweed_mobly_test.py | 43 - .../nrf5/third_party/connectedhomeip | 1 - examples/platform/nrf528xx/BUILD.gn | 25 - examples/platform/nrf528xx/app/Service.cpp | 117 -- examples/platform/nrf528xx/app/chipinit.cpp | 152 --- .../platform/nrf528xx/app/include/Service.h | 21 - .../platform/nrf528xx/app/include/chipinit.h | 5 - .../app/ldscripts/chip-nrf52840-example.ld | 131 -- .../app/project_include/CHIPProjectConfig.h | 139 -- .../app/project_include/FreeRTOSConfig.h | 216 ---- .../app/project_include/OpenThreadConfig.h | 62 - .../freertos_tasks_c_additions.h | 71 -- .../project_include/nrf_log_ctrl_internal.h | 48 - .../platform/nrf528xx/app/support/AltPrintf.c | 148 --- .../platform/nrf528xx/app/support/BUILD.gn | 46 - .../app/support/CXXExceptionStubs.cpp | 80 -- .../app/support/FreeRTOSDebuggingHooks.c | 29 - .../app/support/FreeRTOSDebuggingHooks.h | 34 - .../app/support/FreeRTOSNewlibLockSupport.c | 147 --- .../support/FreeRTOSNewlibLockSupport_test.c | 86 -- .../support/FreeRTOSNewlibLockSupport_test.h | 27 - .../platform/nrf528xx/app/support/nRF5Sbrk.c | 82 -- examples/platform/nrf528xx/args.gni | 41 - .../nrf528xx/doc/images/nrf52840-dk.jpg | Bin 224065 -> 0 bytes examples/platform/nrf528xx/pw_sys_io/BUILD.gn | 44 - .../pw_sys_io_baremetal_nrf528xx/init.h | 27 - .../pw_sys_io/sys_io_baremetal_nrf528xx.cc | 104 -- examples/platform/nrf528xx/sdk/BUILD.gn | 54 - examples/platform/nrf528xx/util/LEDWidget.cpp | 89 -- .../nrf528xx/util/include/LEDWidget.h | 39 - .../nrf528xx/util/streamer/streamer_nrf5.cpp | 107 -- .../nrfconnect/pw_sys_io/sys_io_nrfconnect.cc | 1 + examples/shell/nrf52/.gn | 26 - examples/shell/nrf52/BUILD.gn | 122 -- examples/shell/nrf52/args.gni | 20 - examples/shell/nrf52/build | 1 - examples/shell/nrf52/build_overrides | 1 - .../shell/nrf52/include/CHIPProjectConfig.h | 142 --- examples/shell/nrf52/include/app_config.h | 134 -- examples/shell/nrf52/main.cpp | 107 -- .../shell/nrf52/third_party/connectedhomeip | 1 - gn_build.sh | 15 - .../images/chip-build-nrf-platform/Dockerfile | 13 - .../images/chip-build-vscode/Dockerfile | 2 - scripts/examples/gn_nrf_example.sh | 32 - scripts/flashing/nrf5_firmware_utils.py | 214 ---- scripts/helpers/update_compile_commands.sh | 3 - src/lwip/BUILD.gn | 12 +- src/lwip/nrf5/arch/cc.h | 99 -- src/lwip/nrf5/arch/perf.h | 33 - src/lwip/nrf5/lwipopts.h | 174 --- src/lwip/nrf5/lwippools.h | 17 - src/lwip/qpg6100/lwipopts.h | 3 +- src/platform/BUILD.gn | 50 - src/platform/device.gni | 10 +- src/platform/nRF5/BLEManagerImpl.cpp | 1115 ----------------- src/platform/nRF5/BLEManagerImpl.h | 208 --- src/platform/nRF5/BlePlatformConfig.h | 44 - src/platform/nRF5/CHIPDevicePlatformConfig.h | 89 -- src/platform/nRF5/CHIPDevicePlatformEvent.h | 85 -- src/platform/nRF5/CHIPPlatformConfig.h | 122 -- .../nRF5/ConfigurationManagerImpl.cpp | 159 --- src/platform/nRF5/ConfigurationManagerImpl.h | 102 -- src/platform/nRF5/ConnectivityManagerImpl.cpp | 74 -- src/platform/nRF5/ConnectivityManagerImpl.h | 120 -- .../DeviceNetworkProvisioningDelegateImpl.cpp | 44 - .../DeviceNetworkProvisioningDelegateImpl.h | 43 - src/platform/nRF5/Entropy.cpp | 162 --- src/platform/nRF5/GroupKeyStoreImpl.cpp | 347 ----- src/platform/nRF5/GroupKeyStoreImpl.h | 87 -- src/platform/nRF5/InetPlatformConfig.h | 47 - src/platform/nRF5/Logging.cpp | 224 ---- src/platform/nRF5/PlatformManagerImpl.cpp | 62 - src/platform/nRF5/PlatformManagerImpl.h | 90 -- src/platform/nRF5/README.md | 59 - .../nRF5/SoftwareUpdateManagerImpl.cpp | 40 - src/platform/nRF5/SystemPlatformConfig.h | 60 - src/platform/nRF5/ThreadStackManagerImpl.cpp | 126 -- src/platform/nRF5/ThreadStackManagerImpl.h | 121 -- src/platform/nRF5/args.gni | 39 - src/platform/nRF5/nRF5Config.cpp | 789 ------------ src/platform/nRF5/nRF5Config.h | 205 --- src/platform/nRF5/nRF5Utils.cpp | 84 -- src/platform/nRF5/nRF5Utils.h | 35 - third_party/nrf5_sdk/BUILD.gn | 28 - third_party/nrf5_sdk/nrf5_executable.gni | 54 - third_party/nrf5_sdk/nrf5_sdk.gni | 439 ------- .../openthread/platforms/nrf528xx/BUILD.gn | 201 --- 143 files changed, 15 insertions(+), 13621 deletions(-) delete mode 100644 .github/workflows/examples-nrf.yaml delete mode 100644 build_overrides/nrf5_sdk.gni delete mode 100644 config/nrf5/toolchain/BUILD.gn delete mode 100644 examples/build_overrides/nrf5_sdk.gni delete mode 100644 examples/common/nrf5/README.md delete mode 100644 examples/common/nrf5/gdb/gdb-startup-cmds.txt delete mode 100755 examples/common/nrf5/gdb/start-gdb.sh delete mode 100755 examples/common/nrf5/gdb/start-jlink-gdb-server.sh delete mode 100644 examples/lighting-app/nrf5/.gn delete mode 100644 examples/lighting-app/nrf5/BUILD.gn delete mode 100644 examples/lighting-app/nrf5/README.md delete mode 100644 examples/lighting-app/nrf5/args.gni delete mode 120000 examples/lighting-app/nrf5/build delete mode 120000 examples/lighting-app/nrf5/build_overrides delete mode 100644 examples/lighting-app/nrf5/main/AppTask.cpp delete mode 100644 examples/lighting-app/nrf5/main/LightingCLI.cpp delete mode 100644 examples/lighting-app/nrf5/main/LightingManager.cpp delete mode 100644 examples/lighting-app/nrf5/main/ZclCallbacks.cpp delete mode 100644 examples/lighting-app/nrf5/main/include/AppEvent.h delete mode 100644 examples/lighting-app/nrf5/main/include/AppTask.h delete mode 100644 examples/lighting-app/nrf5/main/include/LightingCLI.h delete mode 100644 examples/lighting-app/nrf5/main/include/LightingManager.h delete mode 100644 examples/lighting-app/nrf5/main/include/app_config.h delete mode 100644 examples/lighting-app/nrf5/main/main.cpp delete mode 120000 examples/lighting-app/nrf5/third_party/connectedhomeip delete mode 100644 examples/lock-app/nrf5/.gn delete mode 100644 examples/lock-app/nrf5/BUILD.gn delete mode 100644 examples/lock-app/nrf5/README.md delete mode 100644 examples/lock-app/nrf5/args.gni delete mode 120000 examples/lock-app/nrf5/build delete mode 120000 examples/lock-app/nrf5/build_overrides delete mode 100644 examples/lock-app/nrf5/main/AppTask.cpp delete mode 100644 examples/lock-app/nrf5/main/BoltLockManager.cpp delete mode 100644 examples/lock-app/nrf5/main/ZclCallbacks.cpp delete mode 100644 examples/lock-app/nrf5/main/include/AppEvent.h delete mode 100644 examples/lock-app/nrf5/main/include/AppTask.h delete mode 100644 examples/lock-app/nrf5/main/include/BoltLockManager.h delete mode 100644 examples/lock-app/nrf5/main/include/app_config.h delete mode 100644 examples/lock-app/nrf5/main/main.cpp delete mode 120000 examples/lock-app/nrf5/third_party/connectedhomeip delete mode 100644 examples/pigweed-app/nrf5/.gn delete mode 100644 examples/pigweed-app/nrf5/BUILD.gn delete mode 100644 examples/pigweed-app/nrf5/args.gni delete mode 120000 examples/pigweed-app/nrf5/build delete mode 120000 examples/pigweed-app/nrf5/build_overrides delete mode 100644 examples/pigweed-app/nrf5/main/include/app_config.h delete mode 100644 examples/pigweed-app/nrf5/main/main.cpp delete mode 100644 examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_config.yml delete mode 100755 examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_test.py delete mode 120000 examples/pigweed-app/nrf5/third_party/connectedhomeip delete mode 100644 examples/platform/nrf528xx/BUILD.gn delete mode 100644 examples/platform/nrf528xx/app/Service.cpp delete mode 100644 examples/platform/nrf528xx/app/chipinit.cpp delete mode 100644 examples/platform/nrf528xx/app/include/Service.h delete mode 100644 examples/platform/nrf528xx/app/include/chipinit.h delete mode 100644 examples/platform/nrf528xx/app/ldscripts/chip-nrf52840-example.ld delete mode 100644 examples/platform/nrf528xx/app/project_include/CHIPProjectConfig.h delete mode 100644 examples/platform/nrf528xx/app/project_include/FreeRTOSConfig.h delete mode 100644 examples/platform/nrf528xx/app/project_include/OpenThreadConfig.h delete mode 100644 examples/platform/nrf528xx/app/project_include/freertos_tasks_c_additions.h delete mode 100644 examples/platform/nrf528xx/app/project_include/nrf_log_ctrl_internal.h delete mode 100644 examples/platform/nrf528xx/app/support/AltPrintf.c delete mode 100644 examples/platform/nrf528xx/app/support/BUILD.gn delete mode 100644 examples/platform/nrf528xx/app/support/CXXExceptionStubs.cpp delete mode 100644 examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.c delete mode 100644 examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.h delete mode 100644 examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport.c delete mode 100644 examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.c delete mode 100644 examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.h delete mode 100644 examples/platform/nrf528xx/app/support/nRF5Sbrk.c delete mode 100644 examples/platform/nrf528xx/args.gni delete mode 100755 examples/platform/nrf528xx/doc/images/nrf52840-dk.jpg delete mode 100644 examples/platform/nrf528xx/pw_sys_io/BUILD.gn delete mode 100644 examples/platform/nrf528xx/pw_sys_io/include/pw_sys_io_baremetal_nrf528xx/init.h delete mode 100644 examples/platform/nrf528xx/pw_sys_io/sys_io_baremetal_nrf528xx.cc delete mode 100644 examples/platform/nrf528xx/sdk/BUILD.gn delete mode 100644 examples/platform/nrf528xx/util/LEDWidget.cpp delete mode 100644 examples/platform/nrf528xx/util/include/LEDWidget.h delete mode 100644 examples/platform/nrf528xx/util/streamer/streamer_nrf5.cpp delete mode 100644 examples/shell/nrf52/.gn delete mode 100644 examples/shell/nrf52/BUILD.gn delete mode 100644 examples/shell/nrf52/args.gni delete mode 120000 examples/shell/nrf52/build delete mode 120000 examples/shell/nrf52/build_overrides delete mode 100644 examples/shell/nrf52/include/CHIPProjectConfig.h delete mode 100644 examples/shell/nrf52/include/app_config.h delete mode 100644 examples/shell/nrf52/main.cpp delete mode 120000 examples/shell/nrf52/third_party/connectedhomeip delete mode 100755 scripts/examples/gn_nrf_example.sh delete mode 100755 scripts/flashing/nrf5_firmware_utils.py delete mode 100644 src/lwip/nrf5/arch/cc.h delete mode 100644 src/lwip/nrf5/arch/perf.h delete mode 100644 src/lwip/nrf5/lwipopts.h delete mode 100644 src/lwip/nrf5/lwippools.h delete mode 100644 src/platform/nRF5/BLEManagerImpl.cpp delete mode 100644 src/platform/nRF5/BLEManagerImpl.h delete mode 100644 src/platform/nRF5/BlePlatformConfig.h delete mode 100644 src/platform/nRF5/CHIPDevicePlatformConfig.h delete mode 100644 src/platform/nRF5/CHIPDevicePlatformEvent.h delete mode 100644 src/platform/nRF5/CHIPPlatformConfig.h delete mode 100644 src/platform/nRF5/ConfigurationManagerImpl.cpp delete mode 100644 src/platform/nRF5/ConfigurationManagerImpl.h delete mode 100644 src/platform/nRF5/ConnectivityManagerImpl.cpp delete mode 100644 src/platform/nRF5/ConnectivityManagerImpl.h delete mode 100644 src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.cpp delete mode 100644 src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.h delete mode 100644 src/platform/nRF5/Entropy.cpp delete mode 100644 src/platform/nRF5/GroupKeyStoreImpl.cpp delete mode 100644 src/platform/nRF5/GroupKeyStoreImpl.h delete mode 100644 src/platform/nRF5/InetPlatformConfig.h delete mode 100644 src/platform/nRF5/Logging.cpp delete mode 100644 src/platform/nRF5/PlatformManagerImpl.cpp delete mode 100644 src/platform/nRF5/PlatformManagerImpl.h delete mode 100644 src/platform/nRF5/README.md delete mode 100644 src/platform/nRF5/SoftwareUpdateManagerImpl.cpp delete mode 100644 src/platform/nRF5/SystemPlatformConfig.h delete mode 100644 src/platform/nRF5/ThreadStackManagerImpl.cpp delete mode 100644 src/platform/nRF5/ThreadStackManagerImpl.h delete mode 100644 src/platform/nRF5/args.gni delete mode 100644 src/platform/nRF5/nRF5Config.cpp delete mode 100644 src/platform/nRF5/nRF5Config.h delete mode 100644 src/platform/nRF5/nRF5Utils.cpp delete mode 100644 src/platform/nRF5/nRF5Utils.h delete mode 100644 third_party/nrf5_sdk/BUILD.gn delete mode 100644 third_party/nrf5_sdk/nrf5_executable.gni delete mode 100644 third_party/nrf5_sdk/nrf5_sdk.gni delete mode 100644 third_party/openthread/platforms/nrf528xx/BUILD.gn diff --git a/.github/boring-cyborg.yml b/.github/boring-cyborg.yml index 4b595f465cce46..2974da8bdbb92c 100644 --- a/.github/boring-cyborg.yml +++ b/.github/boring-cyborg.yml @@ -122,9 +122,6 @@ labelPRBasedOnFilePath: linux: - src/platform/Linux/* - nrf5: - - src/platform/nRF5/* - nrf connect: - src/platform/nrfconnect/* diff --git a/.github/labeler.yml b/.github/labeler.yml index db2c0b1f3f5eee..183c1fa260f890 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -146,9 +146,6 @@ k32w: linux: - src/platform/Linux/* -nrf5: - - src/platform/nRF5/* - nrf connect: - src/platform/nrfconnect/* diff --git a/.github/workflows/examples-nrf.yaml b/.github/workflows/examples-nrf.yaml deleted file mode 100644 index e5509425439e93..00000000000000 --- a/.github/workflows/examples-nrf.yaml +++ /dev/null @@ -1,94 +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: Build example - nRF - -on: - push: - pull_request: - -jobs: - nrf: - name: nRF - env: - BUILD_TYPE: gn_nrf - BUILD_VERSION: 0.2.14 - BUILD_IMAGE: chip-build-nrf-platform - BUILD_ORG: connectedhomeip - - runs-on: ubuntu-latest - - container: - image: connectedhomeip/chip-build-nrf-platform:0.4.12 - volumes: - - "/tmp/bloat_reports:/tmp/bloat_reports" - - "/tmp/output_binaries:/tmp/output_binaries" - - steps: - - name: Checkout - uses: actions/checkout@v2 - # Fetch depth 0 to get all history and be able to check mergepoint for bloat report - with: - fetch-depth: 0 - submodules: true - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: "cpp, python" - queries: +security-and-quality - - name: Bootstrap - run: scripts/build/gn_bootstrap.sh - - name: Build example nRF5 Lock App - run: - scripts/examples/gn_nrf_example.sh examples/lock-app/nrf5 - out/lock_app_debug - - name: Build example nRF5 Lighting App - run: - scripts/examples/gn_nrf_example.sh examples/lighting-app/nrf5 - out/lighting_app_debug - - name: Build example nRF5 Shell App - run: - scripts/examples/gn_nrf_example.sh examples/shell/nrf52 - out/shell_app_debug - - name: Binary artifact suffix - id: outsuffix - uses: haya14busa/action-cond@v1.0.0 - with: - cond: ${{ github.event.pull_request.number == '' }} - if_true: "${{ github.sha }}" - if_false: "pull-${{ github.event.pull_request.number }}" - - name: Uploading Binaries - uses: actions/upload-artifact@v2 - with: - name: - ${{ env.BUILD_TYPE }}-example-build-${{ - steps.outsuffix.outputs.value }} - path: | - out/lock_app_debug/chip-nrf52840-lock-example - out/lighting_app_debug/chip-nrf52840-lighting-example - out/shell_app_debug/shell-nrf52840 - # TODO: NRF Connect https://github.com/project-chip/connectedhomeip/issues/2225 - - name: Show tree - run: find . - - name: Remove third_party binaries for CodeQL Analysis - run: find out -type d -name "third_party" -exec rm -rf {} + - - name: Remove nrfxlib binaries for CodeQL Analysis - run: find out -type d -name "nrfxlib" -exec rm -rf {} + - - name: Remove NordicSemiconductor binaries for CodeQL Analysis - run: - find out -type d -name "NordicSemiconductor" -exec rm -rf {} + - - - name: Perform CodeQL Analysis - if: ${{ github.event_name == 'push' }} - uses: github/codeql-action/analyze@v1 diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 7476136cebe300..e99e7d2e9dc4cd 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -60,18 +60,6 @@ "limitSymbolsToIncludedHeaders": true } }, - { - "name": "nRF5 examples debug (GN)", - "cStandard": "c11", - "cppStandard": "c++11", - "intelliSenseMode": "gcc-x64", - "compileCommands": "${workspaceFolder}/out/debug/compile_commands.nrf5.json", - "compilerPath": "/opt/ARM-software/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gcc", - "browse": { - "path": ["${workspaceFolder}/out/debug/"], - "limitSymbolsToIncludedHeaders": true - } - }, { "name": "EFR32 examples debug (GN)", "cStandard": "c11", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d6fada3832da35..d9bce7888594dd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -114,32 +114,6 @@ ] } }, - { - "label": "Build nRF5 Lock Example", - "type": "shell", - "command": "scripts/examples/gn_build_example.sh examples/lock-app/nrf5 out/nrf5_lock_app", - "group": "build", - "problemMatcher": { - "base": "$gcc", - "fileLocation": [ - "relative", - "${workspaceFolder}/out/nrf5_lock_app/" - ] - } - }, - { - "label": "Build nRF5 Lighting Example", - "type": "shell", - "command": "scripts/examples/gn_build_example.sh examples/lighting-app/nrf5 out/nrf5_lighting_app", - "group": "build", - "problemMatcher": { - "base": "$gcc", - "fileLocation": [ - "relative", - "${workspaceFolder}/out/nrf5_lighting_app/" - ] - } - }, { "label": "Build EFR32 Lock Example", "type": "shell", diff --git a/BUILD.gn b/BUILD.gn index e489b511c561e1..5c3479dfd38d8c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -106,9 +106,6 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { # Enable building for Android. enable_android_builds = false - # Set this to true to enable nRF5 builds by default. - enable_nrf5_builds = false - # Set this to true to enable efr32 builds by default. enable_efr32_builds = false @@ -139,15 +136,6 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { enable_linux_lighting_app_build = enable_default_builds && host_os == "linux" - # Build the nRF5 lock app example. - enable_nrf5_lock_app_build = enable_nrf5_builds - - # Build the nRF5 lighting app example. - enable_nrf5_lighting_app_build = enable_nrf5_builds - - # Build the nRF5 pigweed app example. - enable_nrf5_pigweed_app_build = enable_nrf5_builds - # Build the efr32 lock app example. enable_efr32_lock_app_build = enable_efr32_builds @@ -220,24 +208,6 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { } } - if (enable_nrf5_lock_app_build) { - group("nrf5_lock_app") { - deps = [ "${chip_root}/examples/lock-app/nrf5(${chip_root}/config/nrf5/toolchain:nrf5_lock_app)" ] - } - } - - if (enable_nrf5_lighting_app_build) { - group("nrf5_lighting_app") { - deps = [ "${chip_root}/examples/lighting-app/nrf5(${chip_root}/config/nrf5/toolchain:nrf5_lighting_app)" ] - } - } - - if (enable_nrf5_pigweed_app_build) { - group("nrf5_pigweed_app") { - deps = [ "${chip_root}/examples/pigweed-app/nrf5(${chip_root}/config/nrf5/toolchain:nrf5_pigweed_app)" ] - } - } - if (enable_efr32_lock_app_build) { group("efr32_lock_app") { deps = [ "${chip_root}/examples/lock-app/efr32(${chip_root}/config/efr32/toolchain:efr32_lock_app)" ] @@ -290,15 +260,6 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { if (enable_linux_lighting_app_build) { deps += [ ":linux_lighting_app" ] } - if (enable_nrf5_lock_app_build) { - deps += [ ":nrf5_lock_app" ] - } - if (enable_nrf5_lighting_app_build) { - deps += [ ":nrf5_lighting_app" ] - } - if (enable_nrf5_pigweed_app_build) { - deps += [ ":nrf5_pigweed_app" ] - } if (enable_efr32_lock_app_build) { deps += [ ":efr32_lock_app" ] } diff --git a/build_overrides/nrf5_sdk.gni b/build_overrides/nrf5_sdk.gni deleted file mode 100644 index f9422dc9eb319c..00000000000000 --- a/build_overrides/nrf5_sdk.gni +++ /dev/null @@ -1,18 +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. - -declare_args() { - # Root directory for nRF5 SDK build files. - nrf5_sdk_build_root = "//third_party/nrf5_sdk" -} diff --git a/config/nrf5/toolchain/BUILD.gn b/config/nrf5/toolchain/BUILD.gn deleted file mode 100644 index 06fc50d7969b39..00000000000000 --- a/config/nrf5/toolchain/BUILD.gn +++ /dev/null @@ -1,38 +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. - -import("//build_overrides/chip.gni") - -import("//build/toolchain/arm_gcc/arm_toolchain.gni") - -arm_toolchain("nrf5_lock_app") { - toolchain_args = { - current_os = "freertos" - import("${chip_root}/examples/lock-app/nrf5/args.gni") - } -} - -arm_toolchain("nrf5_lighting_app") { - toolchain_args = { - current_os = "freertos" - import("${chip_root}/examples/lighting-app/nrf5/args.gni") - } -} - -arm_toolchain("nrf5_pigweed_app") { - toolchain_args = { - current_os = "freertos" - import("${chip_root}/examples/pigweed-app/nrf5/args.gni") - } -} diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 2c242e6e111b03..d4f1390614b49c 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -236,12 +236,12 @@ gn desc out/unified '//src/controller(//build/toolchain/host:linux_x64_clang)' ``` Note: Some builds are disabled by default as they need extra SDKs. For example, -to add the nRF5 examples to the unified build, download the -[Nordic nRF5 SDK for Thread and Zigbee](https://www.nordicsemi.com/Software-and-Tools/Software/nRF5-SDK-for-Thread-and-Zigbee) -and add the following build arguments: +to add the EFR32 examples to the unified build, download the +[SDK](https://github.com/SiliconLabs/sdk_support) and add the following build +arguments: ``` -gn gen out/unified --args='target_os="all" enable_nrf5_builds=true nrf5_sdk_root="/path/to/sdk"' +gn gen out/unified --args='target_os="all" enable_efr32_builds=true efr32_sdk_root="/path/to/sdk" efr32_board="BRD4161A"' ``` ### Getting Help diff --git a/docs/VSCODE_DEVELOPMENT.md b/docs/VSCODE_DEVELOPMENT.md index 305373058d9272..1f7463dbed607a 100644 --- a/docs/VSCODE_DEVELOPMENT.md +++ b/docs/VSCODE_DEVELOPMENT.md @@ -70,7 +70,7 @@ same base configuration and build. - Main Build - Build the default configuration (i.e., Linux OpenSSL) - Run Unit and Functional Tests - Test the default configuration - Build & Test (all) - Build & Test various configurations (Linux variants, - Android, nRF5, EFR32) + Android, EFR32) - Update compilation database - Update the database used by IntelliSense (needed for cross references, completion) - Bootstrap - On a clean tree, pull in the third party dependencies required diff --git a/examples/build_overrides/nrf5_sdk.gni b/examples/build_overrides/nrf5_sdk.gni deleted file mode 100644 index 6729e7f082cfb6..00000000000000 --- a/examples/build_overrides/nrf5_sdk.gni +++ /dev/null @@ -1,18 +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. - -declare_args() { - # Root directory for nRF5 SDK. - nrf5_sdk_build_root = "//third_party/connectedhomeip/third_party/nrf5_sdk" -} diff --git a/examples/common/nrf5/README.md b/examples/common/nrf5/README.md deleted file mode 100644 index ad21cdbacda27e..00000000000000 --- a/examples/common/nrf5/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# CHIP nRF52840 Common Code - -This directory contains common code for several example apps. - -- `common` - - This directory contains common code for bringing up a nRF52840 example app. - -- `util` - - This directory contains some usful classes for example apps. - -- `gdb` - - This directory contains some shell scripts for setting up debugging - environment. diff --git a/examples/common/nrf5/gdb/gdb-startup-cmds.txt b/examples/common/nrf5/gdb/gdb-startup-cmds.txt deleted file mode 100644 index bbd74bf25782c4..00000000000000 --- a/examples/common/nrf5/gdb/gdb-startup-cmds.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Set convenience vars for the start and end of the .text section -set $FLASH_START=&__isr_vector -set $FLASH_END=&__etext - -# Search for the signature string indicating that the app was built with support -# for J-Link monitor mode debugging. -set logging file /dev/null -set logging redirect on -set logging on -find /b1 $FLASH_START, $FLASH_END, 'J', 'L', 'I', 'N', 'K', 'M', 'O', 'N', 'H', 'A', 'N', 'D', 'L', 'E', 'R' -set logging off -set logging redirect off - -# Tell the user which type of debugging will being used. -if $numfound != 0 - echo J-LINK monitor handler detected: Enabling monitor mode debugging\n -else - echo J-LINK monitor handler NOT detected: Using standard 'HALT' mode debugging\n -end - -# Connect to the GDB server -echo Connecting to local GDB server\n -target remote localhost:2331 - -# Enable monitor mode debugging if available. -set logging file /dev/null -set logging redirect on -set logging on -if $numfound != 0 - mon exec SetMonModeDebug=1 - eval "mon exec SetMonModeVTableAddr=%p", $FLASH_START -else - mon exec SetMonModeDebug=0 -end -set logging off -set logging redirect off - - diff --git a/examples/common/nrf5/gdb/start-gdb.sh b/examples/common/nrf5/gdb/start-gdb.sh deleted file mode 100755 index 799f9db2fbd97a..00000000000000 --- a/examples/common/nrf5/gdb/start-gdb.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -# -# 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. -# - -SCRIPT_ROOT=$(dirname "$0") -GNU_INSTALL_ROOT=${GNU_INSTALL_ROOT:-${HOME}/tools/arm/gcc-arm-none-eabi-7-2018-q2-update/bin} -GDB=$GNU_INSTALL_ROOT/arm-none-eabi-gdb -DEFAULT_APP=./build/chip-nrf52840-lock-example.out -STARTUP_CMDS=$SCRIPT_ROOT/gdb-startup-cmds.txt - -if [[ $# -eq 0 ]]; then - APP=$DEFAULT_APP -else - APP=$1 -fi - -EXTRA_STARTUP_CMDS=() -if [[ -n $OPENTHREAD_ROOT ]]; then - EXTRA_STARTUP_CMDS+=( - "set substitute-path /build/KNGP-TOLL1-JOB1/openthread/examples/.. $OPENTHREAD_ROOT" - ) -fi - -exec "$GDB" -q -x "$STARTUP_CMDS" "${EXTRA_STARTUP_CMDS[@]/#/-ex=}" "$APP" diff --git a/examples/common/nrf5/gdb/start-jlink-gdb-server.sh b/examples/common/nrf5/gdb/start-jlink-gdb-server.sh deleted file mode 100755 index 06871dc8be7047..00000000000000 --- a/examples/common/nrf5/gdb/start-jlink-gdb-server.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash - -# -# 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. -# - -JLINK_GDB_SERVER=JLinkGDBServer -DEVICE_TYPE=NRF52840_XXAA -RTT_PORT=19021 - -command -v "$JLINK_GDB_SERVER" || { - echo "ERROR: $JLINK_GDB_SERVER not found" - echo "Please install SEGGER J-Link software package" - exit 1 -} - -command -v nc || { - echo "ERROR: nc command not found" - exit 1 -} - -# Launch JLink GDB Server in background; redirect output thru sed to add prefix. -"$JLINK_GDB_SERVER" -device "$DEVICE_TYPE" -if SWD -speed 4000 -rtos GDBServer/RTOSPlugin_FreeRTOS "$@" > >(exec sed -e 's/^/JLinkGDBServer: /') 2>&1 & -GDB_SERVER_PID=$! - -# Repeatedly open a connection to the GDB server's RTT port until -# the user kills the GDB server with an interrupt character. -while true; do - # Wait for GDB server to begin listening on RTT port - while ! lsof -nP -i4TCP:"$RTT_PORT" -sTCP:LISTEN >/dev/null; do - # Quit if the GDB server exits. - if ! kill -0 "$GDB_SERVER_PID" >/dev/null 2>&1; then - echo "" - exit - fi - - # Wait a bit. - sleep 0.1 - - done - - # Connect to RTT port. - nc localhost "$RTT_PORT" - -done diff --git a/examples/lighting-app/nrf5/.gn b/examples/lighting-app/nrf5/.gn deleted file mode 100644 index 89dc9a6fcb5f6c..00000000000000 --- a/examples/lighting-app/nrf5/.gn +++ /dev/null @@ -1,26 +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. - -# The location of the build configuration file. -buildconfig = "//build/config/BUILDCONFIG.gn" - -# CHIP uses angle bracket includes. -check_system_includes = true - -default_args = { - target_cpu = "arm" - target_os = "freertos" - - import("//args.gni") -} diff --git a/examples/lighting-app/nrf5/BUILD.gn b/examples/lighting-app/nrf5/BUILD.gn deleted file mode 100644 index 5187b4b70c7b25..00000000000000 --- a/examples/lighting-app/nrf5/BUILD.gn +++ /dev/null @@ -1,117 +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. - -import("//build_overrides/chip.gni") -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -import("${nrf5_sdk_build_root}/nrf5_executable.gni") -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") - -assert(current_os == "freertos") - -nrf5_platform_dir = "${chip_root}/examples/platform/nrf528xx" - -nrf5_sdk("sdk") { - include_dirs = [ - "main/include", - "main", - "${nrf5_platform_dir}/app/project_include", - "${nrf5_platform_dir}/util/include", - "${nrf5_platform_dir}/app/include", - "${nrf5_sdk_root}/components/libraries/uart", - "${chip_root}/src/app/util", - ] - - sources = [ - "${nrf5_platform_dir}/app/project_include/CHIPProjectConfig.h", - "${nrf5_platform_dir}/app/project_include/FreeRTOSConfig.h", - "${nrf5_platform_dir}/app/project_include/OpenThreadConfig.h", - "${nrf5_platform_dir}/app/project_include/freertos_tasks_c_additions.h", - "${nrf5_platform_dir}/app/project_include/nrf_log_ctrl_internal.h", - "main/include/app_config.h", - ] - - defines = [] - if (is_debug) { - defines += [ "BUILD_RELEASE=0" ] - } else { - defines += [ "BUILD_RELEASE=1" ] - } - - defines += [ - "USE_APP_CONFIG", - "ENABLE_CHIP_SHELL", - "NRF_SHELL_STREAMER", - "MBEDTLS_PK_WRITE_C", - "MBEDTLS_X509_CREATE_C", - "MBEDTLS_X509_CSR_WRITE_C", - "OPENTHREAD_CONFIG_CLI_TRANSPORT=OT_CLI_TRANSPORT_CONSOLE", - "OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS_MANAGEMENT=1", - ] -} - -nrf5_executable("lighting_app") { - output_name = "chip-nrf52840-lighting-example" - - sources = [ - "${nrf5_platform_dir}/app/Service.cpp", - "${nrf5_platform_dir}/app/chipinit.cpp", - "${nrf5_platform_dir}/app/include/Service.h", - "${nrf5_platform_dir}/app/include/chipinit.h", - "${nrf5_platform_dir}/app/support/CXXExceptionStubs.cpp", - "${nrf5_platform_dir}/app/support/nRF5Sbrk.c", - "${nrf5_platform_dir}/util/LEDWidget.cpp", - "${nrf5_platform_dir}/util/include/LEDWidget.h", - "${nrf5_platform_dir}/util/streamer/streamer_nrf5.cpp", - "main/AppTask.cpp", - "main/LightingCLI.cpp", - "main/LightingManager.cpp", - "main/ZclCallbacks.cpp", - "main/include/AppEvent.h", - "main/include/AppTask.h", - "main/include/LightingManager.h", - "main/main.cpp", - ] - - deps = [ - ":sdk", - "${chip_root}/examples/common/chip-app-server:chip-app-server", - "${chip_root}/examples/lighting-app/lighting-common", - "${chip_root}/examples/shell/shell_common:shell_common", - "${chip_root}/src/lib", - "${chip_root}/src/setup_payload", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libnordicsemi_nrf52840_radio_driver_softdevice", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libopenthread-nrf52840-softdevice-sdk", - "${nrf5_platform_dir}/app/support:freertos_debugging_hooks", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support_test", - "${openthread_root}:libopenthread-cli-ftd", - "${openthread_root}:libopenthread-ftd", - ] - - output_dir = root_out_dir - - ldscript = "${nrf5_platform_dir}/app/ldscripts/chip-nrf52840-example.ld" - - ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] -} - -group("nrf5") { - deps = [ ":lighting_app" ] -} - -group("default") { - deps = [ ":nrf5" ] -} diff --git a/examples/lighting-app/nrf5/README.md b/examples/lighting-app/nrf5/README.md deleted file mode 100644 index fb88921781cee2..00000000000000 --- a/examples/lighting-app/nrf5/README.md +++ /dev/null @@ -1,248 +0,0 @@ -# CHIP nRF52840 Lighting Example Application - -### :warning: nRF5 platform deprecated - -> This platform based on the nRF5 SDK for Thread and Zigbee is in maintenance -> mode and support for it will be removed from the CHIP project -> repository.

To develop CHIP applications on Nordic Semiconductor -> devices such as nRF52840, use the platform based on the -> [nRF Connect SDK](https://www.nordicsemi.com/Software-and-tools/Software/nRF-Connect-SDK), -> located in the **[lighting-app/nrfconnect](../nrfconnect)** directory. - -An example application showing the use -[CHIP](https://github.com/project-chip/connectedhomeip) on the Nordic nRF52840. - -
- -- [CHIP nRF52840 Lighting Example Application](#chip-nrf52840-lighting-example-application) - - [Introduction](#introduction) - - [Device UI](#device-ui) - - [Building](#building) - - [Using CHIP's VSCode `devcontainer`](#using-chips-vscode-devcontainer) - - [Using Native Shell](#using-native-shell) - - [Initializing the nRF52840 DK](#initializing-the-nrf52840-dk) - - [Flashing the Application](#flashing-the-application) - - [Viewing Logging Output](#viewing-logging-output) - -
- - - -## Introduction - -![nrf52840 DK](../../platform/nrf528xx/doc/images/nrf52840-dk.jpg) - -The nRF52840 lighting example application provides a working demonstration of a -connected lighting device, built using CHIP, and the Nordic nRF5 SDK. The -example supports remote access and control of a lighting over a low-power, -802.15.4 Thread network. It is capable of being paired into an existing CHIP -network along with other CHIP-enabled devices. The example targets the -[Nordic nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) -development kit, but is readily adaptable to other nRF52840-based hardware. - -The lighting example is intended to serve both as a means to explore the -workings of CHIP, as well as a template for creating real products based on the -Nordic platform. - -The example application builds upon the CHIP. The build system orchestrates the -entire build process, including building CHIP, and select files from the nRF5 -SDK. The resultant image file can be flashed directly onto the Nordic dev kit -hardware. - - - -## Device UI - -The example application provides a simple UI that depicts the state of the -device and offers basic user control. This UI is implemented via the -general-purpose LEDs and buttons built in to the nRF52840 DK dev board. - -**LED #1** shows the overall state of the device and its connectivity. Four -states are depicted: - -- _Short Flash On (50ms on/950ms off)_ — The device is in an - unprovisioned (unpaired) state and is waiting for a commissioning - application to connect. - -* _Rapid Even Flashing (100ms on/100ms off)_ — The device is in an - unprovisioned state and a commissioning application is connected via BLE. - -- _Short Flash Off (950ms on/50ms off)_ — The device is full - provisioned, but does not yet have full network (Thread) or service - connectivity. - -* _Solid On_ — The device is fully provisioned and has full network and - service connectivity. - -**Button #1** can be used to initiate a OTA software update as well as to reset -the device to a default state. - -Pressing and holding Button #1 for 6 seconds initiates a factory reset. After an -initial period of 3 seconds, all four LED will flash in unison to signal the -pending reset. Holding the button past 6 seconds will cause the device to reset -its persistent configuration and initiate a reboot. The reset action can be -cancelled by releasing the button at any point before the 6 second limit. - -**LED #2** shows the state of the lighting. - -**Button #2** can be used to change the state of the lighting. This can be used -to mimick a user manually switching the lighting. The button behaves as a -toggle, swapping the state every time it is pressed. - -The remaining two LEDs and buttons (#3 and #4) are unused. - - - -## Building - -### Using CHIP's VSCode `devcontainer` - -Tools and SDK are preinstalled in -[CHIP's VSCode devcontainer](https://github.com/project-chip/connectedhomeip/blob/master/docs/VSCODE_DEVELOPMENT.md). - -Other alternatives: - -- Run `Build nRF5 Lock Example` VSCode task. - -- Run the `Build & Test (all)` VSCode task. - -- Run the following commands in the Docker container shell. - - $ cd /workspaces/connectedhomeip/examples/lighting-app/nrf5 - - $ git submodule update --init - $ source third_party/connectedhomeip/scripts/activate.sh - $ gn gen out/debug --args="nrf5_sdk_root=\"${NRF5_SDK_ROOT}\"" - $ ninja -C out/debug - -### Using Native Shell - -- Download and install the - [Nordic nRF5 SDK for Thread and Zigbee](https://www.nordicsemi.com/Software-and-Tools/Software/nRF5-SDK-for-Thread-and-Zigbee) - ([Direct download link](https://www.nordicsemi.com/-/media/Software-and-other-downloads/SDKs/nRF5-SDK-for-Thread/nRF5-SDK-for-Thread-and-Zigbee/nRF5SDKforThreadandZigbeev400dc7186b.zip)) - -* Download and install the - [Nordic nRF5x Command Line Tools](https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Command-Line-Tools/Download) - (Direct download link: - [Linux](https://www.nordicsemi.com/-/media/Software-and-other-downloads/Desktop-software/nRF-command-line-tools/sw/Versions-10-x-x/10-7-0/nRFCommandLineTools1070Linuxamd64tar.gz) - [Mac OS X](https://www.nordicsemi.com/-/media/Software-and-other-downloads/Desktop-software/nRF-command-line-tools/sw/Versions-10-x-x/10-7-0/nRF-Command-Line-Tools_10_7_0_OSX.tar)) - -* Download and install a suitable ARM gcc tool chain: - [GNU Arm Embedded Toolchain 7-2018-q2-update](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) - [Linux](https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2) - [Mac OS X](https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-mac.tar.bz2)) - -- Install some additional tools: - - # Linux - $ sudo apt-get install git - -- Set the following environment variables based on the locations/versions of - the packages installed above: - - export NRF5_SDK_ROOT=${HOME}/tools/nRF5_SDK_for_Thread_and_Zigbee_v4.0.0 - export NRF5_TOOLS_ROOT=${HOME}/tools/nRF-Command-Line-Tools - export ARM_GCC_INSTALL_ROOT=${HOME}/tools/gcc-arm-none-eabi-9-2019-q4-major/bin - export PATH=${PATH}:${NRF5_TOOLS_ROOT}/nrfjprog - -

For convenience, place these settings in local script file (e.g. setup-env.sh) so that they can be loaded into the environment as needed (e.g. by running 'source ./setup-env.sh').

- -- Clone the [CHIP](https://github.com/project-chip/connectedhomeip) repo into - a local directory - - $ cd ~ - $ git clone https://github.com/project-chip/connectedhomeip.git - -* Run GN to build the application - - $ cd ~/connectedhomeip/examples/lighting-app/nrf5 - $ git submodule update --init - $ source third_party/connectedhomeip/scripts/activate.sh - $ gn gen out/debug --args="nrf5_sdk_root=\"${NRF5_SDK_ROOT}\"" - $ ninja -C out/debug - - - -## Initializing the nRF52840 DK - -The example application is designed to run on the -[Nordic nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) -development kit. Prior to installing the application, the device's flash memory -should be erased and the Nordic SoftDevice image installed. - -- Connect the host machine to the J-Link Interface MCU USB connector on the - nRF52840 DK. The Interface MCU connector is the one on the _short_ side of - the board. - -* If you are using the GN build, the flashing script will install the - SoftDevice image if it is not already present. If you prefer to do so - manually first, to verify your board function, run: - - $ python3 \ - ~/connectedhomeip/third_party/nrf5_sdk/nrf5_firmware_utils.py \ - --eraseall \ - --application $NRF5_SDK_ROOT/components/softdevice/s140/hex/s140_nrf52_*_softdevice.hex - -Once the above is complete, it shouldn't need be done again _unless_ the -SoftDevice image or the Nordic configuration storage (fds) area becomes corrupt. -To correct either of these problems erase the device and reflash the SoftDevice -and application again. - - - -## Flashing the Application - -To flash the example app, run the following commands: - - $ cd ~/connectedhomeip/examples/lighting-app/nrf5 - $ python3 out/debug/chip-nrf52840-lighting-example.flash.py - -> The [VSCode devcontainer](#using-chips-vscode-devcontainer) cannot communicate -> with the nRF device. So, the above command must be run from a native shell. -> This also means that the `nRF command line tools` must be installed on your -> development machine. - -## Viewing Logging Output - -The example application is built to use the SEGGER Real Time Transfer (RTT) -facility for log output. RTT is a feature built-in to the J-Link Interface MCU -on the development kit board. It allows bi-directional communication with an -embedded application without the need for a dedicated UART. - -Using the RTT facility requires downloading and installing the _SEGGER J-Link -Software and Documentation Pack_ -([web site](https://www.segger.com/downloads/jlink#J-LinkSoftwareAndDocumentationPack)). - -- Download the J-Link installer by navigating to the appropriate URL and - agreeing to the license agreement. - -

Linux: JLink_Linux_x86_64.deb

-

MacOS: JLink_MacOSX.pkg

- -- Install the J-Link software - - $ cd ~/Downloads - $ sudo dpkg -i JLink_Linux_V*_x86_64.deb - -* In Linux, grant the logged in user the ability to talk to the development - hardware via the linux tty device (/dev/ttyACMx) by adding them to the - dialout group. - - $ sudo usermod -a -G dialout ${USER} - -Once the above is complete, log output can be viewed using the JLinkExe tool in -combination with JLinkRTTClient as follows: - -- Run the JLinkExe tool with arguments to autoconnect to the nRF82480 DK - board: - - $ JLinkExe -device NRF52840_XXAA -if SWD -speed 4000 -autoconnect 1 - -- In a second terminal, run the JLinkRTTClient: - - $ JLinkRTTClient - -Logging output will appear in the second terminal. - -An alternate method for viewing log output is to use the J-Link GDB server -described in the following section. diff --git a/examples/lighting-app/nrf5/args.gni b/examples/lighting-app/nrf5/args.gni deleted file mode 100644 index a76696893dd2b7..00000000000000 --- a/examples/lighting-app/nrf5/args.gni +++ /dev/null @@ -1,20 +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. - -import("//build_overrides/chip.gni") - -import("${chip_root}/examples/platform/nrf528xx/args.gni") - -# SDK target. This is overriden to add our SDK app_config.h & defines. -nrf5_sdk_target = get_label_info(":sdk", "label_no_toolchain") diff --git a/examples/lighting-app/nrf5/build b/examples/lighting-app/nrf5/build deleted file mode 120000 index d56ed62ae4d1ff..00000000000000 --- a/examples/lighting-app/nrf5/build +++ /dev/null @@ -1 +0,0 @@ -third_party/connectedhomeip/build \ No newline at end of file diff --git a/examples/lighting-app/nrf5/build_overrides b/examples/lighting-app/nrf5/build_overrides deleted file mode 120000 index e578e73312ebd1..00000000000000 --- a/examples/lighting-app/nrf5/build_overrides +++ /dev/null @@ -1 +0,0 @@ -../../build_overrides \ No newline at end of file diff --git a/examples/lighting-app/nrf5/main/AppTask.cpp b/examples/lighting-app/nrf5/main/AppTask.cpp deleted file mode 100644 index 94ea2e55cae909..00000000000000 --- a/examples/lighting-app/nrf5/main/AppTask.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AppTask.h" -#include "AppEvent.h" -#include "LEDWidget.h" -#include "LightingCLI.h" -#include "LightingManager.h" -#include "Server.h" -#include "Service.h" - -#include "app_button.h" -#include "app_config.h" -#include "app_timer.h" -#include "boards.h" - -#include "nrf_log.h" - -#include "FreeRTOS.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "attribute-storage.h" -#include "gen/cluster-id.h" - -APP_TIMER_DEF(sFunctionTimer); - -namespace { - -constexpr int kFactoryResetTriggerTimeout = 3000; -constexpr int kFactoryResetCancelWindowTimeout = 3000; -constexpr size_t kAppTaskStackSize = 4096; -constexpr int kAppTaskPriority = 2; -constexpr int kAppEventQueueSize = 10; - -SemaphoreHandle_t sCHIPEventLock; - -TaskHandle_t sAppTaskHandle; -QueueHandle_t sAppEventQueue; - -LEDWidget sStatusLED; -LEDWidget sUnusedLED; -LEDWidget sUnusedLED_1; - -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -bool sIsThreadAttached = false; -bool sIsPairedToAccount = false; -bool sHaveBLEConnections = false; -bool sHaveServiceConnectivity = false; - -} // namespace - -using namespace ::chip::DeviceLayer; - -AppTask AppTask::sAppTask; - -int AppTask::StartAppTask() -{ - ret_code_t ret = NRF_SUCCESS; - - sAppEventQueue = xQueueCreate(kAppEventQueueSize, sizeof(AppEvent)); - if (sAppEventQueue == NULL) - { - NRF_LOG_INFO("Failed to allocate app event queue"); - ret = NRF_ERROR_NULL; - APP_ERROR_HANDLER(ret); - } - - // Start App task. - if (xTaskCreate(AppTaskMain, "APP", kAppTaskStackSize / sizeof(StackType_t), NULL, kAppTaskPriority, &sAppTaskHandle) != pdPASS) - { - ret = NRF_ERROR_NULL; - } - - NRF_LOG_INFO("App Task Started"); - - return ret; -} - -int AppTask::Init() -{ - ret_code_t ret; - - StartShellTask(); - - // Init ZCL Data Model and start server - InitServer(); - - // Initialize LEDs - sStatusLED.Init(SYSTEM_STATE_LED); - - sUnusedLED.Init(BSP_LED_2); - sUnusedLED_1.Init(BSP_LED_3); - - // Initialize buttons - static app_button_cfg_t sButtons[] = { - { LIGHTING_BUTTON, APP_BUTTON_ACTIVE_LOW, BUTTON_PULL, ButtonEventHandler }, - { FUNCTION_BUTTON, APP_BUTTON_ACTIVE_LOW, BUTTON_PULL, ButtonEventHandler }, - }; - - ret = app_button_init(sButtons, ARRAY_SIZE(sButtons), pdMS_TO_TICKS(FUNCTION_BUTTON_DEBOUNCE_PERIOD_MS)); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_button_init() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = app_button_enable(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_button_enable() failed"); - APP_ERROR_HANDLER(ret); - } - - // Initialize Timer for Function Selection - ret = app_timer_init(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_init() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = app_timer_create(&sFunctionTimer, APP_TIMER_MODE_SINGLE_SHOT, TimerEventHandler); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_create() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = LightingMgr().Init(LIGHTING_GPIO); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("LightingMgr().Init() failed"); - APP_ERROR_HANDLER(ret); - } - - LightingMgr().SetCallbacks(ActionInitiated, ActionCompleted); - - sCHIPEventLock = xSemaphoreCreateMutex(); - if (sCHIPEventLock == NULL) - { - NRF_LOG_INFO("xSemaphoreCreateMutex() failed"); - APP_ERROR_HANDLER(NRF_ERROR_NULL); - } - - { - CHIP_ERROR err = CHIP_NO_ERROR; - chip::SetupPayload payload; - uint32_t setUpPINCode = 0; - uint16_t setUpDiscriminator = 0; - uint16_t vendorId = 0; - uint16_t productId = 0; - - err = ConfigurationMgr().GetSetupPinCode(setUpPINCode); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetSetupPinCode() failed: %s", chip::ErrorStr(err)); - } - - err = ConfigurationMgr().GetSetupDiscriminator(setUpDiscriminator); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetSetupDiscriminator() failed: %s", chip::ErrorStr(err)); - } - - err = ConfigurationMgr().GetVendorId(vendorId); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err)); - } - - err = ConfigurationMgr().GetVendorId(productId); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err)); - } - - payload.version = 1; - payload.vendorID = vendorId; - payload.productID = productId; - payload.setUpPINCode = setUpPINCode; - payload.discriminator = setUpDiscriminator; - chip::QRCodeSetupPayloadGenerator generator(payload); - - // TODO: Usage of STL will significantly increase the image size, this should be changed to more efficient method for - // generating payload - std::string result; - err = generator.payloadBase41Representation(result); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_ERROR("Failed to generate QR Code"); - } - - NRF_LOG_INFO("SetupPINCode: [%" PRIu32 "]", setUpPINCode); - // There might be whitespace in setup QRCode, add brackets to make it clearer. - NRF_LOG_INFO("SetupQRCode: [%s]", result.c_str()); - } - - return ret; -} - -void AppTask::AppTaskMain(void * pvParameter) -{ - ret_code_t ret; - AppEvent event; - uint64_t mLastChangeTimeUS = 0; - - ret = sAppTask.Init(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("AppTask.Init() failed"); - APP_ERROR_HANDLER(ret); - } - - SetDeviceName("LightingDemo._chip._udp.local."); - - GetAppTask().UpdateClusterState(); - - while (true) - { - BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); - while (eventReceived == pdTRUE) - { - sAppTask.DispatchEvent(&event); - eventReceived = xQueueReceive(sAppEventQueue, &event, 0); - } - - // Collect connectivity and configuration state from the CHIP stack. Because the - // CHIP event loop is being run in a separate task, the stack must be locked - // while these values are queried. However we use a non-blocking lock request - // (TryLockChipStack()) to avoid blocking other UI activities when the CHIP - // task is busy (e.g. with a long crypto operation). - if (PlatformMgr().TryLockChipStack()) - { - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); - sIsThreadAttached = ConnectivityMgr().IsThreadAttached(); - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - sHaveServiceConnectivity = ConnectivityMgr().HaveServiceConnectivity(); - PlatformMgr().UnlockChipStack(); - } - - // Consider the system to be "fully connected" if it has service - // connectivity and it is able to interact with the service on a regular basis. - bool isFullyConnected = sHaveServiceConnectivity; - - // Update the status LED if factory reset has not been initiated. - // - // If system has "full connectivity", keep the LED On constantly. - // - // If thread and service provisioned, but not attached to the thread network yet OR no - // connectivity to the service OR subscriptions are not fully established - // THEN blink the LED Off for a short period of time. - // - // If the system has ble connection(s) uptill the stage above, THEN blink the LEDs at an even - // rate of 100ms. - // - // Otherwise, blink the LED ON for a very short time. - if (sAppTask.mFunction != kFunction_FactoryReset) - { - if (isFullyConnected) - { - sStatusLED.Set(true); - } - else if (sIsThreadProvisioned && sIsThreadEnabled && sIsPairedToAccount && (!sIsThreadAttached || !isFullyConnected)) - { - sStatusLED.Blink(950, 50); - } - else if (sHaveBLEConnections) - { - sStatusLED.Blink(100, 100); - } - else - { - sStatusLED.Blink(50, 950); - } - } - - sStatusLED.Animate(); - sUnusedLED.Animate(); - sUnusedLED_1.Animate(); - GetAppTask().UpdateClusterState(); - - uint64_t nowUS = chip::System::Platform::Layer::GetClock_Monotonic(); - uint64_t nextChangeTimeUS = mLastChangeTimeUS + 5 * 1000 * 1000UL; - - if (nowUS > nextChangeTimeUS) - { - PublishService(); - mLastChangeTimeUS = nowUS; - } - } -} - -void AppTask::LightingActionEventHandler(AppEvent * aEvent) -{ - bool initiated = false; - LightingManager::Action_t action; - ret_code_t ret = NRF_SUCCESS; - - if (aEvent->Type == AppEvent::kEventType_Lighting) - { - action = static_cast(aEvent->LightingEvent.Action); - } - else if (aEvent->Type == AppEvent::kEventType_Button) - { - if (LightingMgr().IsTurnedOn()) - { - action = LightingManager::OFF_ACTION; - } - else - { - action = LightingManager::ON_ACTION; - } - } - else - { - ret = NRF_ERROR_NULL; - } - - if (ret == NRF_SUCCESS) - { - initiated = LightingMgr().InitiateAction(action); - - if (!initiated) - { - NRF_LOG_INFO("Action is already in progress or active."); - } - } -} - -void AppTask::ButtonEventHandler(uint8_t pin_no, uint8_t button_action) -{ - if (pin_no != LIGHTING_BUTTON && pin_no != FUNCTION_BUTTON) - { - return; - } - - AppEvent button_event = {}; - button_event.Type = AppEvent::kEventType_Button; - button_event.ButtonEvent.PinNo = pin_no; - button_event.ButtonEvent.Action = button_action; - - if (pin_no == LIGHTING_BUTTON && button_action == APP_BUTTON_PUSH) - { - button_event.Handler = LightingActionEventHandler; - } - else if (pin_no == FUNCTION_BUTTON) - { - button_event.Handler = FunctionHandler; - } - else - { - return; - } - - sAppTask.PostEvent(&button_event); -} - -void AppTask::TimerEventHandler(void * p_context) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = p_context; - event.Handler = FunctionTimerEventHandler; - sAppTask.PostEvent(&event); -} - -void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) -{ - if (aEvent->Type != AppEvent::kEventType_Timer) - return; - - // If we reached here, the button was held past kFactoryResetTriggerTimeout, initiate factory reset - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_SoftwareUpdate) - { - NRF_LOG_INFO("Factory Reset Triggered. Release button within %ums to cancel.", kFactoryResetTriggerTimeout); - - // Start timer for kFactoryResetCancelWindowTimeout to allow user to cancel, if required. - sAppTask.StartTimer(kFactoryResetCancelWindowTimeout); - - sAppTask.mFunction = kFunction_FactoryReset; - - // Turn off all LEDs before starting blink to make sure blink is co-ordinated. - sStatusLED.Set(false); - sUnusedLED_1.Set(false); - sUnusedLED.Set(false); - - sStatusLED.Blink(500); - sUnusedLED.Blink(500); - sUnusedLED_1.Blink(500); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Actually trigger Factory Reset - sAppTask.mFunction = kFunction_NoneSelected; - ConfigurationMgr().InitiateFactoryReset(); - } -} - -void AppTask::FunctionHandler(AppEvent * aEvent) -{ - if (aEvent->ButtonEvent.PinNo != FUNCTION_BUTTON) - return; - - // To trigger software update: press the FUNCTION_BUTTON button briefly (< kFactoryResetTriggerTimeout) - // To initiate factory reset: press the FUNCTION_BUTTON for kFactoryResetTriggerTimeout + kFactoryResetCancelWindowTimeout - // All LEDs start blinking after kFactoryResetTriggerTimeout to signal factory reset has been initiated. - // To cancel factory reset: release the FUNCTION_BUTTON once all LEDs start blinking within the - // kFactoryResetCancelWindowTimeout - if (aEvent->ButtonEvent.Action == APP_BUTTON_PUSH) - { - if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_NoneSelected) - { - sAppTask.StartTimer(kFactoryResetTriggerTimeout); - - sAppTask.mFunction = kFunction_SoftwareUpdate; - } - } - else - { - // If the button was released before factory reset got initiated, trigger a software update. - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_SoftwareUpdate) - { - sAppTask.CancelTimer(); - sAppTask.mFunction = kFunction_NoneSelected; - NRF_LOG_INFO("Software update is not implemented"); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - sUnusedLED.Set(false); - sUnusedLED_1.Set(false); - - sAppTask.CancelTimer(); - - // Change the function to none selected since factory reset has been canceled. - sAppTask.mFunction = kFunction_NoneSelected; - - NRF_LOG_INFO("Factory Reset has been Canceled"); - } - } -} - -void AppTask::CancelTimer() -{ - ret_code_t ret; - - ret = app_timer_stop(sFunctionTimer); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_stop() failed"); - APP_ERROR_HANDLER(ret); - } - - mFunctionTimerActive = false; -} - -void AppTask::StartTimer(uint32_t aTimeoutInMs) -{ - ret_code_t ret; - - ret = app_timer_start(sFunctionTimer, pdMS_TO_TICKS(aTimeoutInMs), this); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_start() failed"); - APP_ERROR_HANDLER(ret); - } - - mFunctionTimerActive = true; -} - -void AppTask::ActionInitiated(LightingManager::Action_t aAction) -{ - // If the action has been initiated by the lock, update the bolt lock trait - // and start flashing the LEDs rapidly to indicate action initiation. - if (aAction == LightingManager::ON_ACTION) - { - NRF_LOG_INFO("Turn On Action has been initiated") - } - else if (aAction == LightingManager::OFF_ACTION) - { - NRF_LOG_INFO("Turn Off Action has been initiated") - } -} - -void AppTask::ActionCompleted(LightingManager::Action_t aAction) -{ - // if the action has been completed by the lock, update the bolt lock trait. - // Turn on the lock LED if in a LOCKED state OR - // Turn off the lock LED if in an UNLOCKED state. - if (aAction == LightingManager::ON_ACTION) - { - NRF_LOG_INFO("Turn On Action has been completed") - } - else if (aAction == LightingManager::OFF_ACTION) - { - NRF_LOG_INFO("Turn Off Action has been completed") - } -} - -void AppTask::PostLightingActionRequest(LightingManager::Action_t aAction) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Lighting; - event.LightingEvent.Action = aAction; - event.Handler = LightingActionEventHandler; - PostEvent(&event); -} - -void AppTask::PostEvent(const AppEvent * aEvent) -{ - if (sAppEventQueue != NULL) - { - if (!xQueueSend(sAppEventQueue, aEvent, 1)) - { - NRF_LOG_INFO("Failed to post event to app task event queue"); - } - } -} - -void AppTask::DispatchEvent(AppEvent * aEvent) -{ - - if (aEvent->Handler) - { - aEvent->Handler(aEvent); - } - else - { - NRF_LOG_INFO("Event received with no handler. Dropping event."); - } -} - -void AppTask::UpdateClusterState(void) -{ - uint8_t newValue = LightingMgr().IsTurnedOn(); - - // write the new on/off value - EmberAfStatus status = emberAfWriteAttribute(1, ZCL_ON_OFF_CLUSTER_ID, ZCL_ON_OFF_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, - (uint8_t *) &newValue, ZCL_BOOLEAN_ATTRIBUTE_TYPE); - if (status != EMBER_ZCL_STATUS_SUCCESS) - { - NRF_LOG_INFO("ERR: updating on/off %x", status); - } -} diff --git a/examples/lighting-app/nrf5/main/LightingCLI.cpp b/examples/lighting-app/nrf5/main/LightingCLI.cpp deleted file mode 100644 index 542269d4750ed7..00000000000000 --- a/examples/lighting-app/nrf5/main/LightingCLI.cpp +++ /dev/null @@ -1,214 +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. - */ - -/** - * @file - * The CLI interface of CHIP Lighting App - */ - -#include "FreeRTOS.h" -#include "task.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -using namespace ::chip; -using namespace ::chip::DeviceLayer; -using namespace ::chip::Shell; - -namespace { - -enum CLIEvents -{ - kCLIEvent_LightOn = 0, - kCLIEvent_LightOff, - kCLIEvent_LightToggle, - - kCLIEvent_FactoryReset, -}; - -void CLIAppEventHandler(AppEvent * event) -{ - switch (event->CLIEvent.Event) - { - case kCLIEvent_LightOn: - LightingMgr().InitiateAction(LightingManager::ON_ACTION); - break; - case kCLIEvent_LightOff: - LightingMgr().InitiateAction(LightingManager::OFF_ACTION); - break; - case kCLIEvent_LightToggle: { - LightingManager::Action_t action; - if (LightingMgr().IsTurnedOn()) - { - action = LightingManager::OFF_ACTION; - } - else - { - action = LightingManager::ON_ACTION; - } - LightingMgr().InitiateAction(action); - break; - } - case kCLIEvent_FactoryReset: - ConfigurationMgr().InitiateFactoryReset(); - break; - default: - ChipLogError(Shell, "Unknown event received: %d", event->CLIEvent.Event); - break; - } -} - -int cmd_light(int argc, char ** argv) -{ - // TODO: Add or remove multiple endpoints support. - bool read_state = false; - int end_point = 1; - AppEvent event; - event.Type = AppEvent::kEventType_CLI; - event.Handler = CLIAppEventHandler; - - VerifyOrExit(argc > 0 && argc <= 2, streamer_printf(streamer_get(), "light on/off/toggle/state [endpoint=1]\n\r")); - - if (strcmp(argv[0], "on") == 0) - { - event.CLIEvent.Event = kCLIEvent_LightOn; - } - else if (strcmp(argv[0], "off") == 0) - { - event.CLIEvent.Event = kCLIEvent_LightOff; - } - else if (strcmp(argv[0], "toggle") == 0) - { - event.CLIEvent.Event = kCLIEvent_LightToggle; - } - else if (strcmp(argv[0], "state") == 0) - { - read_state = true; - } - - if (argc == 2) - { - sscanf(argv[1], "%d", &end_point); - } - - if (read_state) - { - streamer_printf(streamer_get(), "%d\n\r", LightingMgr().IsTurnedOn()); - } - else - { - GetAppTask().PostEvent(&event); - } -exit: - streamer_printf(streamer_get(), "\n\r"); - return 0; -} - -int cmd_app(int argc, char ** argv) -{ - int end_point = 1; - AppEvent event; - event.Type = AppEvent::kEventType_CLI; - event.Handler = CLIAppEventHandler; - - VerifyOrExit(argc > 0, streamer_printf(streamer_get(), "app subcommand|help\n\r")); - - if (strcmp(argv[0], "factoryrst") == 0) - { - event.CLIEvent.Event = kCLIEvent_FactoryReset; - } - else - { - streamer_printf(streamer_get(), "app factoryrst : Do factory reset\n\r"); - } - - GetAppTask().PostEvent(&event); -exit: - streamer_printf(streamer_get(), "\n\r"); - return 0; -} - -shell_command_t cmd_lightingcli[] = { - { &cmd_light, "light", "Lighting control" }, - { &cmd_app, "app", "App utilities" }, -}; - -void cmd_app_init(void) -{ - shell_register(cmd_lightingcli, ArraySize(cmd_lightingcli)); -} - -} // namespace - -namespace { - -const size_t kShellTaskStackSize = 2048; -const int kShellTaskPriority = 1; -TaskHandle_t sShellTaskHandle; - -void LightingCLIMain(void * pvParameter) -{ - // Initialize the default streamer that was linked. - const int rc = streamer_init(streamer_get()); - - if (rc != 0) - { - ChipLogError(Shell, "Streamer initialization failed: %d", rc); - return; - } - - ChipLogDetail(Shell, "Initializing CHIP shell", rc); - - cmd_misc_init(); - cmd_app_init(); - cmd_btp_init(); - cmd_otcli_init(); - - ChipLogDetail(Shell, "Run CHIP shell Task", rc); - - shell_task(NULL); -} - -} // namespace - -int StartShellTask() -{ - ret_code_t ret = NRF_SUCCESS; - - // Start App task. - if (xTaskCreate(LightingCLIMain, "SHELL", kShellTaskStackSize / sizeof(StackType_t), NULL, kShellTaskPriority, - &sShellTaskHandle) != pdPASS) - { - ret = NRF_ERROR_NULL; - } - - return ret; -} diff --git a/examples/lighting-app/nrf5/main/LightingManager.cpp b/examples/lighting-app/nrf5/main/LightingManager.cpp deleted file mode 100644 index 209262db3dc881..00000000000000 --- a/examples/lighting-app/nrf5/main/LightingManager.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "LightingManager.h" - -#include "app_config.h" -#include "app_timer.h" -#include "boards.h" -#include "nrf_log.h" - -#include "AppTask.h" -#include "FreeRTOS.h" - -LightingManager LightingManager::sLight; - -int LightingManager::Init(uint32_t gpioNum) -{ - mState = kState_On; - mGPIONum = gpioNum; - // We use a gpioNum instead of a LEDWidget here because we want to use PWM - // and other features instead of just on/off. - - nrf_gpio_cfg_output(gpioNum); - Set(false); - - return NRF_SUCCESS; -} - -bool LightingManager::IsTurnedOn() -{ - return mState == kState_On; -} - -void LightingManager::SetCallbacks(LightingCallback_fn aActionInitiated_CB, LightingCallback_fn aActionCompleted_CB) -{ - mActionInitiated_CB = aActionInitiated_CB; - mActionCompleted_CB = aActionCompleted_CB; -} - -bool LightingManager::InitiateAction(Action_t aAction) -{ - // TODO: this function is called InitiateAction because we want to implement some features such as ramping up here. - bool action_initiated = false; - State_t new_state; - - // Initiate On/Off Action only when the previous one is complete. - if (mState == kState_Off && aAction == ON_ACTION) - { - action_initiated = true; - new_state = kState_On; - } - else if (mState == kState_On && aAction == OFF_ACTION) - { - action_initiated = true; - new_state = kState_Off; - } - - if (action_initiated) - { - if (mActionInitiated_CB) - { - mActionInitiated_CB(aAction); - } - - Set(new_state == kState_On); - - if (mActionCompleted_CB) - { - mActionCompleted_CB(aAction); - } - } - - return action_initiated; -} - -void LightingManager::Set(bool aOn) -{ - if (aOn) - { - mState = kState_On; - nrf_gpio_pin_write(mGPIONum, LEDS_ACTIVE_STATE ? 1 : 0); - } - else - { - mState = kState_Off; - nrf_gpio_pin_write(mGPIONum, LEDS_ACTIVE_STATE ? 0 : 1); - } -} diff --git a/examples/lighting-app/nrf5/main/ZclCallbacks.cpp b/examples/lighting-app/nrf5/main/ZclCallbacks.cpp deleted file mode 100644 index 9de4df2464b676..00000000000000 --- a/examples/lighting-app/nrf5/main/ZclCallbacks.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gen/attribute-id.h" -#include "gen/cluster-id.h" -#include "gen/znet-bookkeeping.h" -#include -#include -#include -#include - -#include "LightingManager.h" - -extern "C" { -void emberAfPostAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, - uint16_t manufacturerCode, uint8_t type, uint8_t size, uint8_t * value) -{ - if (clusterId != ZCL_ON_OFF_CLUSTER_ID) - { - ChipLogProgress(Zcl, "Unknown cluster ID: %d", clusterId); - return; - } - - if (attributeId != ZCL_ON_OFF_ATTRIBUTE_ID) - { - ChipLogProgress(Zcl, "Unknown attribute ID: %d", attributeId); - return; - } - - if (*value) - { - LightingMgr().InitiateAction(LightingManager::ON_ACTION); - } - else - { - LightingMgr().InitiateAction(LightingManager::OFF_ACTION); - } -} - -/** @brief On/off Cluster Server Post Init - * - * Following resolution of the On/Off state at startup for this endpoint, - * perform any additional initialization needed; e.g., synchronize hardware - * state. - * - * @param endpoint Endpoint that is being initialized Ver.: always - */ -void emberAfPluginOnOffClusterServerPostInitCallback(uint8_t endpoint) -{ - // TODO: implement any additional On/off Cluster Server post init actions -} -} diff --git a/examples/lighting-app/nrf5/main/include/AppEvent.h b/examples/lighting-app/nrf5/main/include/AppEvent.h deleted file mode 100644 index bf33a34dd1923e..00000000000000 --- a/examples/lighting-app/nrf5/main/include/AppEvent.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Copyright (c) 2018 Nest Labs, Inc. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -struct AppEvent; -typedef void (*EventHandler)(AppEvent *); - -struct AppEvent -{ - enum AppEventTypes - { - kEventType_Button = 0, - kEventType_Timer, - kEventType_Lighting, - kEventType_Install, - kEventType_CLI, - }; - - uint16_t Type; - - union - { - struct - { - uint8_t PinNo; - uint8_t Action; - } ButtonEvent; - struct - { - void * Context; - } TimerEvent; - struct - { - uint8_t Action; - } LightingEvent; - struct - { - uint8_t Event; - } CLIEvent; - }; - - EventHandler Handler; -}; diff --git a/examples/lighting-app/nrf5/main/include/AppTask.h b/examples/lighting-app/nrf5/main/include/AppTask.h deleted file mode 100644 index 3141b26b3842f0..00000000000000 --- a/examples/lighting-app/nrf5/main/include/AppTask.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "FreeRTOS.h" -#include "semphr.h" -#include "task.h" - -#include "AppEvent.h" -#include "LightingManager.h" - -class AppTask -{ -public: - int StartAppTask(); - static void AppTaskMain(void * pvParameter); - - void PostLightingActionRequest(LightingManager::Action_t aAction); - void PostEvent(const AppEvent * event); - -private: - friend AppTask & GetAppTask(void); - - int Init(); - - static void ActionInitiated(LightingManager::Action_t aAction); - static void ActionCompleted(LightingManager::Action_t aAction); - - void CancelTimer(void); - - void DispatchEvent(AppEvent * event); - void UpdateClusterState(void); - - static void FunctionTimerEventHandler(AppEvent * aEvent); - static void FunctionHandler(AppEvent * aEvent); - static void LightingActionEventHandler(AppEvent * aEvent); - - static void ButtonEventHandler(uint8_t pin_no, uint8_t button_action); - static void TimerEventHandler(void * p_context); - - void StartTimer(uint32_t aTimeoutInMs); - - enum Function_t - { - kFunction_NoneSelected = 0, - kFunction_SoftwareUpdate = 0, - kFunction_FactoryReset, - - kFunction_Invalid - } Function; - - Function_t mFunction; - bool mFunctionTimerActive; - - static AppTask sAppTask; -}; - -inline AppTask & GetAppTask(void) -{ - return AppTask::sAppTask; -} diff --git a/examples/lighting-app/nrf5/main/include/LightingCLI.h b/examples/lighting-app/nrf5/main/include/LightingCLI.h deleted file mode 100644 index f4647263244423..00000000000000 --- a/examples/lighting-app/nrf5/main/include/LightingCLI.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int StartShellTask(); diff --git a/examples/lighting-app/nrf5/main/include/LightingManager.h b/examples/lighting-app/nrf5/main/include/LightingManager.h deleted file mode 100644 index 6100e5ac2743e0..00000000000000 --- a/examples/lighting-app/nrf5/main/include/LightingManager.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include - -#include "AppEvent.h" - -class LightingManager -{ -public: - enum Action_t - { - ON_ACTION = 0, - OFF_ACTION, - - INVALID_ACTION - } Action; - - enum State_t - { - kState_On = 0, - kState_Off, - } State; - - int Init(uint32_t gpioNum); - bool IsTurnedOn(); - bool InitiateAction(Action_t aAction); - - using LightingCallback_fn = std::function; - - void SetCallbacks(LightingCallback_fn aActionInitiated_CB, LightingCallback_fn aActionCompleted_CB); - -private: - friend LightingManager & LightingMgr(void); - State_t mState; - uint32_t mGPIONum; - - LightingCallback_fn mActionInitiated_CB; - LightingCallback_fn mActionCompleted_CB; - - void Set(bool aOn); - - static LightingManager sLight; -}; - -inline LightingManager & LightingMgr(void) -{ - return LightingManager::sLight; -} diff --git a/examples/lighting-app/nrf5/main/include/app_config.h b/examples/lighting-app/nrf5/main/include/app_config.h deleted file mode 100644 index 7534841e25f785..00000000000000 --- a/examples/lighting-app/nrf5/main/include/app_config.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -// ----- Memory Config ----- - -#define MEM_MANAGER_ENABLED 1 -#define MEMORY_MANAGER_SMALL_BLOCK_COUNT 4 -#define MEMORY_MANAGER_SMALL_BLOCK_SIZE 32 -#define MEMORY_MANAGER_MEDIUM_BLOCK_COUNT 4 -#define MEMORY_MANAGER_MEDIUM_BLOCK_SIZE 256 -#define MEMORY_MANAGER_LARGE_BLOCK_COUNT 1 -#define MEMORY_MANAGER_LARGE_BLOCK_SIZE 1024 - -// ----- Crypto Config ----- - -#define NRF_CRYPTO_ENABLED 0 - -// ----- Soft Device Config ----- - -#define SOFTDEVICE_PRESENT 1 -#define NRF_SDH_ENABLED 1 -#define NRF_SDH_SOC_ENABLED 1 -#define NRF_SDH_BLE_ENABLED 1 -#define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1 -#define NRF_SDH_BLE_VS_UUID_COUNT 2 -#define NRF_BLE_GATT_ENABLED 1 -#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 251 -#define NRF_SDH_BLE_GAP_DATA_LENGTH 251 - -// ----- FDS / Flash Config ----- - -#define FDS_ENABLED 1 -#define FDS_BACKEND NRF_FSTORAGE_SD -#define NRF_FSTORAGE_ENABLED 1 -// Number of virtual flash pages used for FDS data storage. -// NOTE: This value must correspond to FDS_FLASH_PAGES specified in -// linker directives (.ld) file. -#define FDS_VIRTUAL_PAGES 2 - -// ----- Logging Config ----- - -#define NRF_LOG_ENABLED 1 -#define NRF_LOG_DEFAULT_LEVEL 4 -#define NRF_LOG_DEFERRED 0 -#define NRF_LOG_STR_PUSH_BUFFER_SIZE 16 -#define NRF_LOG_USES_TIMESTAMP 1 -#define NRF_LOG_STR_FORMATTER_TIMESTAMP_FORMAT_ENABLED 0 - -#define NRF_LOG_BACKEND_RTT_ENABLED 1 -#define NRF_LOG_BACKEND_UART_ENABLED 0 - -#define APP_UART_ENABLED 1 -#define APP_FIFO_ENABLED 1 -#define UART_ENABLED 1 -#define UART1_ENABLED 1 -#define NRFX_UARTE_ENABLED 1 -#define APP_UART_DRIVER_INSTANCE 1 -#define NRFX_UART_ENABLED 0 -#define UART_LEGACY_SUPPORT 0 - -#if NRF_LOG_BACKEND_UART_ENABLED - -#define NRF_LOG_BACKEND_UART_TX_PIN 6 -#define NRF_LOG_BACKEND_UART_BAUDRATE 30801920 -#define NRF_LOG_BACKEND_UART_TEMP_BUFFER_SIZE 64 - -#endif // NRF_LOG_BACKEND_UART_ENABLED - -#if NRF_LOG_BACKEND_RTT_ENABLED - -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 4096 -#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 1 -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16 -#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 1 - -// <0=> SKIP -// <1=> TRIM -// <2=> BLOCK_IF_FIFO_FULL -#define SEGGER_RTT_CONFIG_DEFAULT_MODE 1 - -#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS 1 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_CNT 3 - -#endif // NRF_LOG_BACKEND_RTT_ENABLED - -// ----- Misc Config ----- - -// Enable the Nordic ASSERT() macro. This also has the effect of enabling -// FreeRTOS configASSERT() due to logic in FreeRTOSConfig.h -#define DEBUG_NRF 1 - -#define NRF_CLOCK_ENABLED 1 -#define NRF_FPRINTF_ENABLED 1 -#define NRF_STRERROR_ENABLED 1 -#define NRF_QUEUE_ENABLED 1 -#define APP_TIMER_ENABLED 1 -#define BUTTON_ENABLED 1 - -#define GPIOTE_ENABLED 1 -#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 2 - -#define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10 - -// ---- Lock Example App Config ---- - -#define LIGHTING_BUTTON BUTTON_2 -#define FUNCTION_BUTTON BUTTON_1 -#define FUNCTION_BUTTON_DEBOUNCE_PERIOD_MS 50 - -#define SYSTEM_STATE_LED BSP_LED_0 -#define LIGHTING_GPIO NRF_GPIO_PIN_MAP(0, 14) - -// Time it takes in ms for the simulated actuator to move from one -// state to another. -#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 - -// ---- Lock Example SWU Config ---- -#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours -#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours - -// ---- Thread Polling Config ---- -#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 -#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 diff --git a/examples/lighting-app/nrf5/main/main.cpp b/examples/lighting-app/nrf5/main/main.cpp deleted file mode 100644 index e25af93c8665fd..00000000000000 --- a/examples/lighting-app/nrf5/main/main.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include - -#include "boards.h" -#include "nrf_delay.h" -#include "nrf_log.h" -#ifdef SOFTDEVICE_PRESENT -#include "nrf_sdh.h" -#include "nrf_sdh_ble.h" -#include "nrf_sdh_soc.h" -#endif -#include "nrf_drv_clock.h" -#if NRF_CRYPTO_ENABLED -#include "nrf_crypto.h" -#endif -#include "mem_manager.h" -#if CHIP_ENABLE_OPENTHREAD -extern "C" { -#include "multiprotocol_802154_config.h" -#include "nrf_802154.h" -#include "nrf_cc310_platform_abort.h" -#include "nrf_cc310_platform_mutex.h" -#include -} -#endif // CHIP_ENABLE_OPENTHREAD - -#if NRF_LOG_ENABLED -#include "nrf_log_backend_uart.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -#endif // NRF_LOG_ENABLED - -#include "chipinit.h" -#include "nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.h" -#include -#include - -using namespace ::chip; -using namespace ::chip::Inet; -using namespace ::chip::DeviceLayer; - -extern "C" size_t GetHeapTotalSize(void); - -// ================================================================================ -// Logging Support -// ================================================================================ - -#if NRF_LOG_ENABLED - -#if NRF_LOG_USES_TIMESTAMP - -uint32_t LogTimestamp(void) -{ - return 0; -} - -#define LOG_TIMESTAMP_FUNC LogTimestamp -#define LOG_TIMESTAMP_FREQ 1000 - -#else // NRF_LOG_USES_TIMESTAMP - -#define LOG_TIMESTAMP_FUNC NULL -#define LOG_TIMESTAMP_FREQ 0 - -#endif // NRF_LOG_USES_TIMESTAMP - -#endif // NRF_LOG_ENABLED - -// ================================================================================ -// SoftDevice Support -// ================================================================================ - -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - -static void OnSoCEvent(uint32_t sys_evt, void * p_context) -{ -#if CHIP_ENABLE_OPENTHREAD - otSysSoftdeviceSocEvtHandler(sys_evt); -#endif - UNUSED_PARAMETER(p_context); -} - -#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - -// ================================================================================ -// J-Link Monitor Mode Debugging Support -// ================================================================================ - -#if JLINK_MMD - -extern "C" void JLINK_MONITOR_OnExit(void) {} - -extern "C" void JLINK_MONITOR_OnEnter(void) {} - -extern "C" void JLINK_MONITOR_OnPoll(void) {} - -#endif // JLINK_MMD - -// ================================================================================ -// Main Code -// ================================================================================ - -int main(void) -{ - ret_code_t ret; - -#if JLINK_MMD - NVIC_SetPriority(DebugMonitor_IRQn, _PRIO_SD_LOWEST); -#endif - - // Initialize clock driver. - ret = nrf_drv_clock_init(); - APP_ERROR_CHECK(ret); - - nrf_drv_clock_lfclk_request(NULL); - - // Wait for the clock to be ready. - while (!nrf_clock_lf_is_running()) - { - } - -#if NRF_LOG_ENABLED - - // Initialize logging component - ret = NRF_LOG_INIT(LOG_TIMESTAMP_FUNC, LOG_TIMESTAMP_FREQ); - APP_ERROR_CHECK(ret); - - // Initialize logging backends - NRF_LOG_DEFAULT_BACKENDS_INIT(); - -#endif - - NRF_LOG_INFO("=================================================="); - NRF_LOG_INFO("chip-nrf52840-lighting-example starting"); -#if BUILD_RELEASE - NRF_LOG_INFO("*** PSEUDO-RELEASE BUILD ***"); -#else - NRF_LOG_INFO("*** DEVELOPMENT BUILD ***"); -#endif - NRF_LOG_INFO("=================================================="); - NRF_LOG_FLUSH(); - -#ifndef NDEBUG - // TODO: Move this into a standalone test. - freertos_newlib_lock_test(); -#endif - -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - NRF_LOG_INFO("Enabling SoftDevice"); - - ret = nrf_sdh_enable_request(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("nrf_sdh_enable_request() failed"); - APP_ERROR_HANDLER(ret); - } - - NRF_LOG_INFO("Waiting for SoftDevice to be enabled"); - - while (!nrf_sdh_is_enabled()) - { - } - - // Register a handler for SOC events. - NRF_SDH_SOC_OBSERVER(m_soc_observer, NRF_SDH_SOC_STACK_OBSERVER_PRIO, OnSoCEvent, NULL); - - NRF_LOG_INFO("SoftDevice enable complete"); - -#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - { - uint32_t appRAMStart = 0; - - // Configure the BLE stack using the default settings. - // Fetch the start address of the application RAM. - ret = nrf_sdh_ble_default_cfg_set(CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG, &appRAMStart); - APP_ERROR_CHECK(ret); - - // Enable BLE stack. - ret = nrf_sdh_ble_enable(&appRAMStart); - APP_ERROR_CHECK(ret); - NRF_LOG_INFO("SoftDevice BLE enabled"); - } - -#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - ret = ChipInit(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("ChipInit() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = GetAppTask().StartAppTask(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("GetAppTask().Init() failed"); - APP_ERROR_HANDLER(ret); - } - - // Activate deep sleep mode - SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; - -#if CHIP_CONFIG_MEMORY_MGMT_MALLOC && __GNU_LIBRARY__ - { - struct mallinfo minfo = mallinfo(); - NRF_LOG_INFO("System Heap Utilization: heap size %" PRId32 ", arena size %" PRId32 ", in use %" PRId32 ", free %" PRId32, - GetHeapTotalSize(), minfo.arena, minfo.uordblks, minfo.fordblks); - } -#endif // CHIP_CONFIG_MEMORY_MGMT_MALLOC && __GNU_LIBRARY__ - - NRF_LOG_INFO("Starting FreeRTOS scheduler"); - - /* Start FreeRTOS scheduler. */ - vTaskStartScheduler(); - - // Should never get here - NRF_LOG_INFO("vTaskStartScheduler() failed"); - APP_ERROR_HANDLER(0); -} diff --git a/examples/lighting-app/nrf5/third_party/connectedhomeip b/examples/lighting-app/nrf5/third_party/connectedhomeip deleted file mode 120000 index c866b86874994d..00000000000000 --- a/examples/lighting-app/nrf5/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../.. \ No newline at end of file diff --git a/examples/lock-app/nrf5/.gn b/examples/lock-app/nrf5/.gn deleted file mode 100644 index 89dc9a6fcb5f6c..00000000000000 --- a/examples/lock-app/nrf5/.gn +++ /dev/null @@ -1,26 +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. - -# The location of the build configuration file. -buildconfig = "//build/config/BUILDCONFIG.gn" - -# CHIP uses angle bracket includes. -check_system_includes = true - -default_args = { - target_cpu = "arm" - target_os = "freertos" - - import("//args.gni") -} diff --git a/examples/lock-app/nrf5/BUILD.gn b/examples/lock-app/nrf5/BUILD.gn deleted file mode 100644 index f80a743ec00331..00000000000000 --- a/examples/lock-app/nrf5/BUILD.gn +++ /dev/null @@ -1,109 +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. - -import("//build_overrides/chip.gni") -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -import("${nrf5_sdk_build_root}/nrf5_executable.gni") -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") - -assert(current_os == "freertos") - -nrf5_platform_dir = "${chip_root}/examples/platform/nrf528xx" - -nrf5_sdk("sdk") { - include_dirs = [ - "main/include", - "main", - "${nrf5_platform_dir}/app/project_include", - "${nrf5_platform_dir}/util/include", - "${nrf5_platform_dir}/app/include", - "${chip_root}/src/app/util", - ] - - sources = [ - "${nrf5_platform_dir}/app/project_include/CHIPProjectConfig.h", - "${nrf5_platform_dir}/app/project_include/FreeRTOSConfig.h", - "${nrf5_platform_dir}/app/project_include/OpenThreadConfig.h", - "${nrf5_platform_dir}/app/project_include/freertos_tasks_c_additions.h", - "${nrf5_platform_dir}/app/project_include/nrf_log_ctrl_internal.h", - "main/include/app_config.h", - ] - - defines = [] - if (is_debug) { - defines += [ "BUILD_RELEASE=0" ] - } else { - defines += [ "BUILD_RELEASE=1" ] - } - - defines += [ - "USE_APP_CONFIG", - "MBEDTLS_PK_WRITE_C", - "MBEDTLS_X509_CREATE_C", - "MBEDTLS_X509_CSR_WRITE_C", - ] -} - -nrf5_executable("lock_app") { - output_name = "chip-nrf52840-lock-example" - - sources = [ - "${nrf5_platform_dir}/app/Service.cpp", - "${nrf5_platform_dir}/app/chipinit.cpp", - "${nrf5_platform_dir}/app/include/Service.h", - "${nrf5_platform_dir}/app/include/chipinit.h", - "${nrf5_platform_dir}/app/support/CXXExceptionStubs.cpp", - "${nrf5_platform_dir}/app/support/nRF5Sbrk.c", - "${nrf5_platform_dir}/util/LEDWidget.cpp", - "${nrf5_platform_dir}/util/include/LEDWidget.h", - "main/AppTask.cpp", - "main/BoltLockManager.cpp", - "main/ZclCallbacks.cpp", - "main/include/AppEvent.h", - "main/include/AppTask.h", - "main/include/BoltLockManager.h", - "main/main.cpp", - ] - - deps = [ - ":sdk", - "${chip_root}/examples/common/chip-app-server:chip-app-server", - "${chip_root}/examples/lock-app/lock-common", - "${chip_root}/src/lib", - "${chip_root}/src/setup_payload", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libnordicsemi_nrf52840_radio_driver_softdevice", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libopenthread-nrf52840-softdevice-sdk", - "${nrf5_platform_dir}/app/support:freertos_debugging_hooks", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support_test", - "${openthread_root}:libopenthread-cli-ftd", - "${openthread_root}:libopenthread-ftd", - ] - - output_dir = root_out_dir - - ldscript = "${nrf5_platform_dir}/app/ldscripts/chip-nrf52840-example.ld" - - ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] -} - -group("nrf5") { - deps = [ ":lock_app" ] -} - -group("default") { - deps = [ ":nrf5" ] -} diff --git a/examples/lock-app/nrf5/README.md b/examples/lock-app/nrf5/README.md deleted file mode 100644 index 550150bef805e0..00000000000000 --- a/examples/lock-app/nrf5/README.md +++ /dev/null @@ -1,253 +0,0 @@ -# CHIP nRF52840 Lock Example Application - -### :warning: nRF5 platform deprecated - -> This platform based on the nRF5 SDK for Thread and Zigbee is in maintenance -> mode and support for it will be removed from the CHIP project -> repository.

To develop CHIP applications on Nordic Semiconductor -> devices such as nRF52840, use the platform based on the -> [nRF Connect SDK](https://www.nordicsemi.com/Software-and-tools/Software/nRF-Connect-SDK), -> located in the **[lock-app/nrfconnect](../nrfconnect)** directory. - -An example application showing the use -[CHIP](https://github.com/project-chip/connectedhomeip) on the Nordic nRF52840. - -
- -- [CHIP nRF52840 Lock Example Application](#chip-nrf52840-lock-example-application) - - [Introduction](#introduction) - - [Device UI](#device-ui) - - [Building](#building) - - [Using CHIP's VSCode `devcontainer`](#using-chips-vscode-devcontainer) - - [Using Native Shell](#using-native-shell) - - [Initializing the nRF52840 DK](#initializing-the-nrf52840-dk) - - [Flashing the Application](#flashing-the-application) - - [Viewing Logging Output](#viewing-logging-output) - -
- - - -## Introduction - -![nrf52840 DK](../../platform/nrf528xx/doc/images/nrf52840-dk.jpg) - -The nRF52840 lock example application provides a working demonstration of a -connected door lock device, built using CHIP, and the Nordic nRF5 SDK. The -example supports remote access and control of a simulated door lock over a -low-power, 802.15.4 Thread network. It is capable of being paired into an -existing CHIP network along with other CHIP-enabled devices. The example targets -the -[Nordic nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) -development kit, but is readily adaptable to other nRF52840-based hardware. - -The lock example is intended to serve both as a means to explore the workings of -CHIP, as well as a template for creating real products based on the Nordic -platform. - -The example application builds upon the CHIP. The build system orchestrates the -entire build process, including building CHIP, and select files from the nRF5 -SDK. The resultant image file can be flashed directly onto the Nordic dev kit -hardware. - - - -## Device UI - -The example application provides a simple UI that depicts the state of the -device and offers basic user control. This UI is implemented via the -general-purpose LEDs and buttons built in to the nRF52840 DK dev board. - -**LED #1** shows the overall state of the device and its connectivity. Four -states are depicted: - -- _Short Flash On (50ms on/950ms off)_ — The device is in an - unprovisioned (unpaired) state and is waiting for a commissioning - application to connect. - -* _Rapid Even Flashing (100ms on/100ms off)_ — The device is in an - unprovisioned state and a commissioning application is connected via BLE. - -- _Short Flash Off (950ms on/50ms off)_ — The device is full - provisioned, but does not yet have full network (Thread) or service - connectivity. - -* _Solid On_ — The device is fully provisioned and has full network and - service connectivity. - -**Button #1** can be used to initiate a OTA software update as well as to reset -the device to a default state. - -Pressing and holding Button #1 for 6 seconds initiates a factory reset. After an -initial period of 3 seconds, all four LED will flash in unison to signal the -pending reset. Holding the button past 6 seconds will cause the device to reset -its persistent configuration and initiate a reboot. The reset action can be -cancelled by releasing the button at any point before the 6 second limit. - -**LED #2** shows the state of the simulated lock bolt. When the LED is lit the -bolt is extended (i.e. door locked); when not lit, the bolt is retracted (door -unlocked). The LED will flash whenever the simulated bolt is in motion from one -position to another. - -**Button #2** can be used to change the state of the simulated bolt. This can be -used to mimick a user manually operating the lock. The button behaves as a -toggle, swapping the state every time it is pressed. - -The remaining two LEDs and buttons (#3 and #4) are unused. - - - -## Building - -### Using CHIP's VSCode `devcontainer` - -Tools and SDK are preinstalled in -[CHIP's VSCode devcontainer](https://github.com/project-chip/connectedhomeip/blob/master/docs/VSCODE_DEVELOPMENT.md). - -Run one of the following tasks in VSCode to build: - -- Run `Build nRF5 Lighting Example` VSCode task. - -- Run the `Build & Test (all)` VSCode task. - -- Run the following commands in the Docker container shell. - - $ cd /workspaces/connectedhomeip-vscode/examples/lock-app/nrf5 - - $ git submodule update --init - $ source third_party/connectedhomeip/scripts/activate.sh - $ gn gen out/debug --args="nrf5_sdk_root=\"${NRF5_SDK_ROOT}\"" - $ ninja -C out/debug - -### Using Native Shell - -- Download and install the - [Nordic nRF5 SDK for Thread and Zigbee](https://www.nordicsemi.com/Software-and-Tools/Software/nRF5-SDK-for-Thread-and-Zigbee) - ([Direct download link](https://www.nordicsemi.com/-/media/Software-and-other-downloads/SDKs/nRF5-SDK-for-Thread/nRF5-SDK-for-Thread-and-Zigbee/nRF5SDKforThreadandZigbeev400dc7186b.zip)) - -* Download and install the - [Nordic nRF5x Command Line Tools](https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Command-Line-Tools/Download) - (Direct download link: - [Linux](https://www.nordicsemi.com/-/media/Software-and-other-downloads/Desktop-software/nRF-command-line-tools/sw/Versions-10-x-x/10-7-0/nRFCommandLineTools1070Linuxamd64tar.gz) - [Mac OS X](https://www.nordicsemi.com/-/media/Software-and-other-downloads/Desktop-software/nRF-command-line-tools/sw/Versions-10-x-x/10-7-0/nRF-Command-Line-Tools_10_7_0_OSX.tar)) - -* Download and install a suitable ARM gcc tool chain: - [GNU Arm Embedded Toolchain 7-2018-q2-update](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) - (Direct download link: - [Linux](https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2) - [Mac OS X](https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-mac.tar.bz2)) - -- Install some additional tools: - - # Linux - $ sudo apt-get install git - -- Set the following environment variables based on the locations/versions of - the packages installed above: - - export NRF5_SDK_ROOT=${HOME}/tools/nRF5_SDK_for_Thread_and_Zigbee_v4.0.0 - export NRF5_TOOLS_ROOT=${HOME}/tools/nRF-Command-Line-Tools - export ARM_GCC_INSTALL_ROOT=${HOME}/tools/gcc-arm-none-eabi-9-2019-q4-major/bin - export PATH=${PATH}:${NRF5_TOOLS_ROOT}/nrfjprog - -

For convenience, place these settings in local script file (e.g. setup-env.sh) so that they can be loaded into the environment as needed (e.g. by running 'source ./setup-env.sh').

- -- Clone the [CHIP](https://github.com/project-chip/connectedhomeip) repo into - a local directory - - $ cd ~ - $ git clone https://github.com/project-chip/connectedhomeip.git - -* Run GN to build the application - - $ cd ~/connectedhomeip/examples/lock-app/nrf5 - $ git submodule update --init - $ source third_party/connectedhomeip/scripts/activate.sh - $ gn gen out/debug --args="nrf5_sdk_root=\"${NRF5_SDK_ROOT}\"" - $ ninja -C out/debug - - - -## Initializing the nRF52840 DK - -The example application is designed to run on the -[Nordic nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) -development kit. Prior to installing the application, the device's flash memory -should be erased and the Nordic SoftDevice image installed. - -- Connect the host machine to the J-Link Interface MCU USB connector on the - nRF52840 DK. The Interface MCU connector is the one on the _short_ side of - the board. - -* If you are using the GN build, the flashing script will install the - SoftDevice image if it is not already present. If you prefer to do so - manually first, to verify your board function, run: - - $ python3 \ - ~/connectedhomeip/third_party/nrf5_sdk/nrf5_firmware_utils.py \ - --eraseall \ - --application $NRF5_SDK_ROOT/components/softdevice/s140/hex/s140_nrf52_*_softdevice.hex - -Once the above is complete, it shouldn't need be done again _unless_ the -SoftDevice image or the Nordic configuration storage (fds) area becomes corrupt. -To correct either of these problems erase the device and reflash the SoftDevice -and application again. - - - -## Flashing the Application - -To flash the example app, run the following commands: - - $ cd ~/connectedhomeip/examples/lock-app/nrf5 - $ python3 out/debug/chip-nrf52840-lock-example.flash.py - -> The [VSCode devcontainer](#using-chips-vscode-devcontainer) cannot communicate -> with the nRF device. So, the above command must be run from a native shell. -> This also means that the `nRF command line tools` must be installed on your -> development machine. - -## Viewing Logging Output - -The example application is built to use the SEGGER Real Time Transfer (RTT) -facility for log output. RTT is a feature built-in to the J-Link Interface MCU -on the development kit board. It allows bi-directional communication with an -embedded application without the need for a dedicated UART. - -Using the RTT facility requires downloading and installing the _SEGGER J-Link -Software and Documentation Pack_ -([web site](https://www.segger.com/downloads/jlink#J-LinkSoftwareAndDocumentationPack)). - -- Download the J-Link installer by navigating to the appropriate URL and - agreeing to the license agreement. - -

Linux: JLink_Linux_x86_64.deb

-

MacOS: JLink_MacOSX.pkg

- -- Install the J-Link software - - $ cd ~/Downloads - $ sudo dpkg -i JLink_Linux_V*_x86_64.deb - -* In Linux, grant the logged in user the ability to talk to the development - hardware via the linux tty device (/dev/ttyACMx) by adding them to the - dialout group. - - $ sudo usermod -a -G dialout ${USER} - -Once the above is complete, log output can be viewed using the JLinkExe tool in -combination with JLinkRTTClient as follows: - -- Run the JLinkExe tool with arguments to autoconnect to the nRF82480 DK - board: - - $ JLinkExe -device NRF52840_XXAA -if SWD -speed 4000 -autoconnect 1 - -- In a second terminal, run the JLinkRTTClient: - - $ JLinkRTTClient - -Logging output will appear in the second terminal. - -An alternate method for viewing log output is to use the J-Link GDB server -described in the following section. diff --git a/examples/lock-app/nrf5/args.gni b/examples/lock-app/nrf5/args.gni deleted file mode 100644 index a76696893dd2b7..00000000000000 --- a/examples/lock-app/nrf5/args.gni +++ /dev/null @@ -1,20 +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. - -import("//build_overrides/chip.gni") - -import("${chip_root}/examples/platform/nrf528xx/args.gni") - -# SDK target. This is overriden to add our SDK app_config.h & defines. -nrf5_sdk_target = get_label_info(":sdk", "label_no_toolchain") diff --git a/examples/lock-app/nrf5/build b/examples/lock-app/nrf5/build deleted file mode 120000 index d56ed62ae4d1ff..00000000000000 --- a/examples/lock-app/nrf5/build +++ /dev/null @@ -1 +0,0 @@ -third_party/connectedhomeip/build \ No newline at end of file diff --git a/examples/lock-app/nrf5/build_overrides b/examples/lock-app/nrf5/build_overrides deleted file mode 120000 index e578e73312ebd1..00000000000000 --- a/examples/lock-app/nrf5/build_overrides +++ /dev/null @@ -1 +0,0 @@ -../../build_overrides \ No newline at end of file diff --git a/examples/lock-app/nrf5/main/AppTask.cpp b/examples/lock-app/nrf5/main/AppTask.cpp deleted file mode 100644 index ac18258324f660..00000000000000 --- a/examples/lock-app/nrf5/main/AppTask.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AppTask.h" -#include "AppEvent.h" -#include "LEDWidget.h" -#include "Server.h" -#include "Service.h" - -#include "app_button.h" -#include "app_config.h" -#include "app_timer.h" -#include "boards.h" - -#include "nrf_log.h" - -#include "FreeRTOS.h" - -#include -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#include -#endif -#include -#include - -#include -#include - -#include - -#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 -#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 -#define APP_TASK_STACK_SIZE (4096) -#define APP_TASK_PRIORITY 2 -#define APP_EVENT_QUEUE_SIZE 10 - -APP_TIMER_DEF(sFunctionTimer); - -static SemaphoreHandle_t sCHIPEventLock; - -static TaskHandle_t sAppTaskHandle; -static QueueHandle_t sAppEventQueue; - -static LEDWidget sStatusLED; -static LEDWidget sLockLED; -static LEDWidget sUnusedLED; -static LEDWidget sUnusedLED_1; - -static LEDWidget sLockStatusLED; - -static bool sIsThreadProvisioned = false; -static bool sIsThreadEnabled = false; -static bool sIsThreadAttached = false; -static bool sIsPairedToAccount = false; -static bool sHaveBLEConnections = false; -static bool sHaveServiceConnectivity = false; - -using namespace ::chip::DeviceLayer; - -AppTask AppTask::sAppTask; - -int AppTask::StartAppTask() -{ - ret_code_t ret = NRF_SUCCESS; - - sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); - if (sAppEventQueue == NULL) - { - NRF_LOG_INFO("Failed to allocate app event queue"); - ret = NRF_ERROR_NULL; - APP_ERROR_HANDLER(ret); - } - - // Start App task. - if (xTaskCreate(AppTaskMain, "APP", APP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, APP_TASK_PRIORITY, &sAppTaskHandle) != - pdPASS) - { - ret = NRF_ERROR_NULL; - } - - return ret; -} - -int AppTask::Init() -{ - ret_code_t ret; - - // Init ZCL Data Model and start server - InitServer(); - - // Initialize LEDs - sStatusLED.Init(SYSTEM_STATE_LED); - - sLockLED.Init(LOCK_STATE_LED); - sLockLED.Set(!BoltLockMgr().IsUnlocked()); - - sLockStatusLED.Init(LOCK_STATE_LED_GPIO); - sLockStatusLED.Set(!BoltLockMgr().IsUnlocked()); - - sUnusedLED.Init(BSP_LED_2); - sUnusedLED_1.Init(BSP_LED_3); - - // Initialize buttons - static app_button_cfg_t sButtons[] = { - { LOCK_BUTTON, APP_BUTTON_ACTIVE_LOW, BUTTON_PULL, ButtonEventHandler }, - { FUNCTION_BUTTON, APP_BUTTON_ACTIVE_LOW, BUTTON_PULL, ButtonEventHandler }, -#if CHIP_ENABLE_OPENTHREAD - { JOIN_BUTTON, APP_BUTTON_ACTIVE_LOW, BUTTON_PULL, ButtonEventHandler }, -#endif - }; - - ret = app_button_init(sButtons, ARRAY_SIZE(sButtons), pdMS_TO_TICKS(FUNCTION_BUTTON_DEBOUNCE_PERIOD_MS)); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_button_init() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = app_button_enable(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_button_enable() failed"); - APP_ERROR_HANDLER(ret); - } - - // Initialize Timer for Function Selection - ret = app_timer_init(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_init() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = app_timer_create(&sFunctionTimer, APP_TIMER_MODE_SINGLE_SHOT, TimerEventHandler); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_create() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = BoltLockMgr().Init(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("BoltLockMgr().Init() failed"); - APP_ERROR_HANDLER(ret); - } - - BoltLockMgr().SetCallbacks(ActionInitiated, ActionCompleted); - - sCHIPEventLock = xSemaphoreCreateMutex(); - if (sCHIPEventLock == NULL) - { - NRF_LOG_INFO("xSemaphoreCreateMutex() failed"); - APP_ERROR_HANDLER(NRF_ERROR_NULL); - } - - { - CHIP_ERROR err = CHIP_NO_ERROR; - chip::SetupPayload payload; - uint32_t setUpPINCode = 0; - uint16_t setUpDiscriminator = 0; - uint16_t vendorId = 0; - uint16_t productId = 0; - - err = ConfigurationMgr().GetSetupPinCode(setUpPINCode); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetSetupPinCode() failed: %s", chip::ErrorStr(err)); - } - - err = ConfigurationMgr().GetSetupDiscriminator(setUpDiscriminator); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetSetupDiscriminator() failed: %s", chip::ErrorStr(err)); - } - - err = ConfigurationMgr().GetVendorId(vendorId); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err)); - } - - err = ConfigurationMgr().GetProductId(productId); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConfigurationMgr().GetProductId() failed: %s", chip::ErrorStr(err)); - } - - payload.version = 1; - payload.vendorID = vendorId; - payload.productID = productId; - payload.setUpPINCode = setUpPINCode; - payload.discriminator = setUpDiscriminator; - chip::QRCodeSetupPayloadGenerator generator(payload); - - // TODO: Usage of STL will significantly increase the image size, this should be changed to more efficient method for - // generating payload - std::string result; - err = generator.payloadBase41Representation(result); - if (err != CHIP_NO_ERROR) - { - NRF_LOG_INFO("Failed to generate QR Code"); - } - - NRF_LOG_INFO("SetupPINCode: [%" PRIu32 "]", setUpPINCode); - // There might be whitespace in setup QRCode, add brackets to make it clearer. - NRF_LOG_INFO("SetupQRCode: [%s]", result.c_str()); - } - - return ret; -} - -void AppTask::AppTaskMain(void * pvParameter) -{ - ret_code_t ret; - AppEvent event; - uint64_t mLastChangeTimeUS = 0; - - ret = sAppTask.Init(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("AppTask.Init() failed: %s", chip::ErrorStr(ret)); - APP_ERROR_HANDLER(ret); - } - - SetDeviceName("LockDemo._chip._udp.local."); - - while (true) - { - BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); - while (eventReceived == pdTRUE) - { - sAppTask.DispatchEvent(&event); - eventReceived = xQueueReceive(sAppEventQueue, &event, 0); - } - - // Collect connectivity and configuration state from the CHIP stack. Because the - // CHIP event loop is being run in a separate task, the stack must be locked - // while these values are queried. However we use a non-blocking lock request - // (TryLockChipStack()) to avoid blocking other UI activities when the CHIP - // task is busy (e.g. with a long crypto operation). - if (PlatformMgr().TryLockChipStack()) - { - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); - sIsThreadAttached = ConnectivityMgr().IsThreadAttached(); - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - sHaveServiceConnectivity = ConnectivityMgr().HaveServiceConnectivity(); - PlatformMgr().UnlockChipStack(); - } - - // Consider the system to be "fully connected" if it has service - // connectivity and it is able to interact with the service on a regular basis. - bool isFullyConnected = sHaveServiceConnectivity; - - // Update the status LED if factory reset has not been initiated. - // - // If system has "full connectivity", keep the LED On constantly. - // - // If thread and service provisioned, but not attached to the thread network yet OR no - // connectivity to the service OR subscriptions are not fully established - // THEN blink the LED Off for a short period of time. - // - // If the system has ble connection(s) uptill the stage above, THEN blink the LEDs at an even - // rate of 100ms. - // - // Otherwise, blink the LED ON for a very short time. - if (sAppTask.mFunction != kFunction_FactoryReset) - { - if (isFullyConnected) - { - sStatusLED.Set(true); - } - else if (sIsThreadProvisioned && sIsThreadEnabled && sIsPairedToAccount && (!sIsThreadAttached || !isFullyConnected)) - { - sStatusLED.Blink(950, 50); - } - else if (sHaveBLEConnections) - { - sStatusLED.Blink(100, 100); - } - else - { - sStatusLED.Blink(50, 950); - } - } - - sStatusLED.Animate(); - sLockLED.Animate(); - sUnusedLED.Animate(); - sUnusedLED_1.Animate(); - - sLockStatusLED.Set(!BoltLockMgr().IsUnlocked()); - sLockStatusLED.Animate(); - - uint64_t nowUS = chip::System::Platform::Layer::GetClock_Monotonic(); - uint64_t nextChangeTimeUS = mLastChangeTimeUS + 5 * 1000 * 1000UL; - - if (nowUS > nextChangeTimeUS) - { - PublishService(); - mLastChangeTimeUS = nowUS; - } - } -} - -void AppTask::LockActionEventHandler(AppEvent * aEvent) -{ - bool initiated = false; - BoltLockManager::Action_t action; - int32_t actor = 0; - ret_code_t ret = NRF_SUCCESS; - - if (aEvent->Type == AppEvent::kEventType_Lock) - { - action = static_cast(aEvent->LockEvent.Action); - actor = aEvent->LockEvent.Actor; - } - else if (aEvent->Type == AppEvent::kEventType_Button) - { - if (BoltLockMgr().IsUnlocked()) - { - action = BoltLockManager::LOCK_ACTION; - } - else - { - action = BoltLockManager::UNLOCK_ACTION; - } - } - else - { - ret = NRF_ERROR_NULL; - } - - if (ret == NRF_SUCCESS) - { - initiated = BoltLockMgr().InitiateAction(actor, action); - - if (!initiated) - { - NRF_LOG_INFO("Action is already in progress or active."); - } - } -} - -#if CHIP_ENABLE_OPENTHREAD -void AppTask::JoinHandler(AppEvent * aEvent) -{ - if (aEvent->ButtonEvent.PinNo != JOIN_BUTTON) - return; - - CHIP_ERROR error = ThreadStackMgr().JoinerStart(); - NRF_LOG_INFO("Thread joiner triggered: %s", chip::ErrorStr(error)); -} -#endif - -void AppTask::ButtonEventHandler(uint8_t pin_no, uint8_t button_action) -{ - if (pin_no != LOCK_BUTTON -#if CHIP_ENABLE_OPENTHREAD - && pin_no != JOIN_BUTTON -#endif - && pin_no != FUNCTION_BUTTON) - { - return; - } - - AppEvent button_event = {}; - button_event.Type = AppEvent::kEventType_Button; - button_event.ButtonEvent.PinNo = pin_no; - button_event.ButtonEvent.Action = button_action; - - if (pin_no == LOCK_BUTTON && button_action == APP_BUTTON_PUSH) - { - button_event.Handler = LockActionEventHandler; - } - else if (pin_no == FUNCTION_BUTTON) - { - button_event.Handler = FunctionHandler; - } -#if CHIP_ENABLE_OPENTHREAD - else if (pin_no == JOIN_BUTTON && button_action == APP_BUTTON_RELEASE) - { - button_event.Handler = JoinHandler; - } -#endif - else - { - return; - } - - sAppTask.PostEvent(&button_event); -} - -void AppTask::TimerEventHandler(void * p_context) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = p_context; - event.Handler = FunctionTimerEventHandler; - sAppTask.PostEvent(&event); -} - -void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) -{ - if (aEvent->Type != AppEvent::kEventType_Timer) - return; - - // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, initiate factory reset - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_SoftwareUpdate) - { - NRF_LOG_INFO("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_TRIGGER_TIMEOUT); - - // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to cancel, if required. - sAppTask.StartTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - sAppTask.mFunction = kFunction_FactoryReset; - - // Turn off all LEDs before starting blink to make sure blink is co-ordinated. - sStatusLED.Set(false); - sLockLED.Set(false); - sUnusedLED_1.Set(false); - sUnusedLED.Set(false); - - sStatusLED.Blink(500); - sLockLED.Blink(500); - sUnusedLED.Blink(500); - sUnusedLED_1.Blink(500); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Actually trigger Factory Reset - sAppTask.mFunction = kFunction_NoneSelected; - ConfigurationMgr().InitiateFactoryReset(); - } -} - -void AppTask::FunctionHandler(AppEvent * aEvent) -{ - if (aEvent->ButtonEvent.PinNo != FUNCTION_BUTTON) - return; - - // To trigger software update: press the FUNCTION_BUTTON button briefly (< FACTORY_RESET_TRIGGER_TIMEOUT) - // To initiate factory reset: press the FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + FACTORY_RESET_CANCEL_WINDOW_TIMEOUT - // All LEDs start blinking after FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. - // To cancel factory reset: release the FUNCTION_BUTTON once all LEDs start blinking within the - // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT - if (aEvent->ButtonEvent.Action == APP_BUTTON_PUSH) - { - if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_NoneSelected) - { - sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); - - sAppTask.mFunction = kFunction_SoftwareUpdate; - } - } - else - { - // If the button was released before factory reset got initiated, trigger a software update. - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_SoftwareUpdate) - { - sAppTask.CancelTimer(); - sAppTask.mFunction = kFunction_NoneSelected; - NRF_LOG_INFO("Software update is not implemented"); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - sUnusedLED.Set(false); - sUnusedLED_1.Set(false); - - // Set lock status LED back to show state of lock. - sLockLED.Set(!BoltLockMgr().IsUnlocked()); - - sAppTask.CancelTimer(); - - // Change the function to none selected since factory reset has been canceled. - sAppTask.mFunction = kFunction_NoneSelected; - - NRF_LOG_INFO("Factory Reset has been Canceled"); - } - } -} - -void AppTask::CancelTimer() -{ - ret_code_t ret; - - ret = app_timer_stop(sFunctionTimer); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_stop() failed"); - APP_ERROR_HANDLER(ret); - } - - mFunctionTimerActive = false; -} - -void AppTask::StartTimer(uint32_t aTimeoutInMs) -{ - ret_code_t ret; - - ret = app_timer_start(sFunctionTimer, pdMS_TO_TICKS(aTimeoutInMs), this); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_start() failed"); - APP_ERROR_HANDLER(ret); - } - - mFunctionTimerActive = true; -} - -void AppTask::ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor) -{ - // If the action has been initiated by the lock, update the bolt lock trait - // and start flashing the LEDs rapidly to indicate action initiation. - if (aAction == BoltLockManager::LOCK_ACTION) - { - NRF_LOG_INFO("Lock Action has been initiated"); - } - else if (aAction == BoltLockManager::UNLOCK_ACTION) - { - NRF_LOG_INFO("Unlock Action has been initiated"); - } - - sLockLED.Blink(50, 50); -} - -void AppTask::ActionCompleted(BoltLockManager::Action_t aAction) -{ - // if the action has been completed by the lock, update the bolt lock trait. - // Turn on the lock LED if in a LOCKED state OR - // Turn off the lock LED if in an UNLOCKED state. - if (aAction == BoltLockManager::LOCK_ACTION) - { - NRF_LOG_INFO("Lock Action has been completed"); - - sLockLED.Set(true); - } - else if (aAction == BoltLockManager::UNLOCK_ACTION) - { - NRF_LOG_INFO("Unlock Action has been completed"); - - sLockLED.Set(false); - } -} - -void AppTask::PostLockActionRequest(int32_t aActor, BoltLockManager::Action_t aAction) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Lock; - event.LockEvent.Actor = aActor; - event.LockEvent.Action = aAction; - event.Handler = LockActionEventHandler; - PostEvent(&event); -} - -void AppTask::PostEvent(const AppEvent * aEvent) -{ - if (sAppEventQueue != NULL) - { - if (!xQueueSend(sAppEventQueue, aEvent, 1)) - { - NRF_LOG_INFO("Failed to post event to app task event queue"); - } - } -} - -void AppTask::DispatchEvent(AppEvent * aEvent) -{ - if (aEvent->Handler) - { - aEvent->Handler(aEvent); - } - else - { - NRF_LOG_INFO("Event received with no handler. Dropping event."); - } -} diff --git a/examples/lock-app/nrf5/main/BoltLockManager.cpp b/examples/lock-app/nrf5/main/BoltLockManager.cpp deleted file mode 100644 index 5b9f61036b4d14..00000000000000 --- a/examples/lock-app/nrf5/main/BoltLockManager.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BoltLockManager.h" - -#include "app_config.h" -#include "app_timer.h" -#include "nrf_log.h" - -#include "AppTask.h" -#include "FreeRTOS.h" - -BoltLockManager BoltLockManager::sLock; - -APP_TIMER_DEF(sLockTimer); - -int BoltLockManager::Init() -{ - ret_code_t ret; - - ret = app_timer_create(&sLockTimer, APP_TIMER_MODE_SINGLE_SHOT, TimerEventHandler); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_create() failed"); - APP_ERROR_HANDLER(ret); - } - - mState = kState_LockingCompleted; - mAutoLockTimerArmed = false; - mAutoRelock = false; - mAutoLockDuration = 0; - - return ret; -} - -void BoltLockManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) -{ - mActionInitiated_CB = aActionInitiated_CB; - mActionCompleted_CB = aActionCompleted_CB; -} - -bool BoltLockManager::IsActionInProgress() -{ - return (mState == kState_LockingInitiated || mState == kState_UnlockingInitiated) ? true : false; -} - -bool BoltLockManager::IsUnlocked() -{ - return (mState == kState_UnlockingCompleted) ? true : false; -} - -void BoltLockManager::EnableAutoRelock(bool aOn) -{ - mAutoRelock = aOn; -} - -void BoltLockManager::SetAutoLockDuration(uint32_t aDurationInSecs) -{ - mAutoLockDuration = aDurationInSecs; -} - -bool BoltLockManager::InitiateAction(int32_t aActor, Action_t aAction) -{ - bool action_initiated = false; - State_t new_state; - - // Initiate Lock/Unlock Action only when the previous one is complete. - if (mState == kState_LockingCompleted && aAction == UNLOCK_ACTION) - { - action_initiated = true; - - new_state = kState_UnlockingInitiated; - } - else if (mState == kState_UnlockingCompleted && aAction == LOCK_ACTION) - { - action_initiated = true; - - new_state = kState_LockingInitiated; - } - - if (action_initiated) - { - if (mAutoLockTimerArmed && new_state == kState_LockingInitiated) - { - // If auto lock timer has been armed and someone initiates locking, - // cancel the timer and continue as normal. - mAutoLockTimerArmed = false; - - CancelTimer(); - } - - StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); - - // Since the timer started successfully, update the state and trigger callback - mState = new_state; - - if (mActionInitiated_CB) - { - mActionInitiated_CB(aAction, aActor); - } - } - - return action_initiated; -} - -void BoltLockManager::StartTimer(uint32_t aTimeoutMs) -{ - ret_code_t ret; - ret = app_timer_start(sLockTimer, pdMS_TO_TICKS(aTimeoutMs), this); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_start() failed"); - APP_ERROR_HANDLER(ret); - } -} - -void BoltLockManager::CancelTimer(void) -{ - ret_code_t ret; - ret = app_timer_stop(sLockTimer); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("app_timer_stop() failed"); - APP_ERROR_HANDLER(ret); - } -} - -void BoltLockManager::TimerEventHandler(void * p_context) -{ - BoltLockManager * lock = static_cast(p_context); - - // The timer event handler will be called in the context of the timer task - // once sLockTimer expires. Post an event to apptask queue with the actual handler - // so that the event can be handled in the context of the apptask. - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = p_context; - if (lock->mAutoLockTimerArmed) - { - event.Handler = AutoReLockTimerEventHandler; - } - else - { - event.Handler = ActuatorMovementTimerEventHandler; - } - GetAppTask().PostEvent(&event); -} - -void BoltLockManager::AutoReLockTimerEventHandler(AppEvent * aEvent) -{ - BoltLockManager * lock = static_cast(aEvent->TimerEvent.Context); - int32_t actor = 0; - - // Make sure auto lock timer is still armed. - if (!lock->mAutoLockTimerArmed) - { - return; - } - - lock->mAutoLockTimerArmed = false; - - NRF_LOG_INFO("Auto Re-Lock has been triggered!"); - - lock->InitiateAction(actor, LOCK_ACTION); -} - -void BoltLockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) -{ - Action_t actionCompleted = INVALID_ACTION; - - BoltLockManager * lock = static_cast(aEvent->TimerEvent.Context); - - if (lock->mState == kState_LockingInitiated) - { - lock->mState = kState_LockingCompleted; - actionCompleted = LOCK_ACTION; - } - else if (lock->mState == kState_UnlockingInitiated) - { - lock->mState = kState_UnlockingCompleted; - actionCompleted = UNLOCK_ACTION; - } - - if (actionCompleted != INVALID_ACTION) - { - if (lock->mActionCompleted_CB) - { - lock->mActionCompleted_CB(actionCompleted); - } - - if (lock->mAutoRelock && actionCompleted == UNLOCK_ACTION) - { - // Start the timer for auto relock - lock->StartTimer(lock->mAutoLockDuration * 1000); - - lock->mAutoLockTimerArmed = true; - - NRF_LOG_INFO("Auto Re-lock enabled. Will be triggered in %u seconds", lock->mAutoLockDuration); - } - } -} diff --git a/examples/lock-app/nrf5/main/ZclCallbacks.cpp b/examples/lock-app/nrf5/main/ZclCallbacks.cpp deleted file mode 100644 index b4bceaff343a8b..00000000000000 --- a/examples/lock-app/nrf5/main/ZclCallbacks.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "BoltLockManager.h" - -#include "gen/attribute-id.h" -#include "gen/cluster-id.h" -#include "gen/znet-bookkeeping.h" -#include -#include -#include -#include - -using namespace ::chip; - -extern "C" { -void emberAfPostAttributeChangeCallback(uint8_t endpoint, EmberAfClusterId clusterId, EmberAfAttributeId attributeId, uint8_t mask, - uint16_t manufacturerCode, uint8_t type, uint8_t size, uint8_t * value) -{ - if (clusterId != ZCL_ON_OFF_CLUSTER_ID) - { - ChipLogProgress(Zcl, "Unknown cluster ID: %d", clusterId); - return; - } - - if (attributeId != ZCL_ON_OFF_ATTRIBUTE_ID) - { - ChipLogProgress(Zcl, "Unknown attribute ID: %d", attributeId); - return; - } - - if (*value) - { - BoltLockMgr().InitiateAction(0, BoltLockManager::LOCK_ACTION); - } - else - { - BoltLockMgr().InitiateAction(0, BoltLockManager::UNLOCK_ACTION); - } -} - -/** @brief On/off Cluster Server Post Init - * - * Following resolution of the On/Off state at startup for this endpoint, - * perform any additional initialization needed; e.g., synchronize hardware - * state. - * - * @param endpoint Endpoint that is being initialized Ver.: always - */ -void emberAfPluginOnOffClusterServerPostInitCallback(uint8_t endpoint) -{ - // TODO: implement any additional On/off Cluster Server post init actions -} -} diff --git a/examples/lock-app/nrf5/main/include/AppEvent.h b/examples/lock-app/nrf5/main/include/AppEvent.h deleted file mode 100644 index ebcdfd9e1abfd5..00000000000000 --- a/examples/lock-app/nrf5/main/include/AppEvent.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Copyright (c) 2018 Nest Labs, Inc. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -struct AppEvent; -typedef void (*EventHandler)(AppEvent *); - -struct AppEvent -{ - enum AppEventTypes - { - kEventType_Button = 0, - kEventType_Timer, - kEventType_Lock, - kEventType_Install, - }; - - uint16_t Type; - - union - { - struct - { - uint8_t PinNo; - uint8_t Action; - } ButtonEvent; - struct - { - void * Context; - } TimerEvent; - struct - { - uint8_t Action; - int32_t Actor; - } LockEvent; - }; - - EventHandler Handler; -}; diff --git a/examples/lock-app/nrf5/main/include/AppTask.h b/examples/lock-app/nrf5/main/include/AppTask.h deleted file mode 100644 index a3613337c71215..00000000000000 --- a/examples/lock-app/nrf5/main/include/AppTask.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "FreeRTOS.h" -#include "semphr.h" -#include "task.h" - -#include "AppEvent.h" -#include "BoltLockManager.h" - -class AppTask -{ -public: - int StartAppTask(); - static void AppTaskMain(void * pvParameter); - - void PostLockActionRequest(int32_t aActor, BoltLockManager::Action_t aAction); - void PostEvent(const AppEvent * event); - -private: - friend AppTask & GetAppTask(void); - - int Init(); - - static void ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor); - static void ActionCompleted(BoltLockManager::Action_t aAction); - - void CancelTimer(void); - - void DispatchEvent(AppEvent * event); - - static void FunctionTimerEventHandler(AppEvent * aEvent); - static void FunctionHandler(AppEvent * aEvent); - static void JoinHandler(AppEvent * aEvent); - static void LockActionEventHandler(AppEvent * aEvent); - - static void ButtonEventHandler(uint8_t pin_no, uint8_t button_action); - static void TimerEventHandler(void * p_context); - - void StartTimer(uint32_t aTimeoutInMs); - - enum Function_t - { - kFunction_NoneSelected = 0, - kFunction_SoftwareUpdate = 0, - kFunction_FactoryReset, - - kFunction_Invalid - } Function; - - Function_t mFunction; - bool mFunctionTimerActive; - - static AppTask sAppTask; -}; - -inline AppTask & GetAppTask(void) -{ - return AppTask::sAppTask; -} diff --git a/examples/lock-app/nrf5/main/include/BoltLockManager.h b/examples/lock-app/nrf5/main/include/BoltLockManager.h deleted file mode 100644 index f7e419bf9b92af..00000000000000 --- a/examples/lock-app/nrf5/main/include/BoltLockManager.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -class BoltLockManager -{ -public: - enum Action_t - { - LOCK_ACTION = 0, - UNLOCK_ACTION, - - INVALID_ACTION - } Action; - - enum State_t - { - kState_LockingInitiated = 0, - kState_LockingCompleted, - kState_UnlockingInitiated, - kState_UnlockingCompleted, - } State; - - int Init(); - bool IsUnlocked(); - void EnableAutoRelock(bool aOn); - void SetAutoLockDuration(uint32_t aDurationInSecs); - bool IsActionInProgress(); - bool InitiateAction(int32_t aActor, Action_t aAction); - - typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor); - typedef void (*Callback_fn_completed)(Action_t); - void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); - -private: - friend BoltLockManager & BoltLockMgr(void); - State_t mState; - - Callback_fn_initiated mActionInitiated_CB; - Callback_fn_completed mActionCompleted_CB; - - bool mAutoRelock; - uint32_t mAutoLockDuration; - bool mAutoLockTimerArmed; - - void CancelTimer(void); - void StartTimer(uint32_t aTimeoutMs); - - static void TimerEventHandler(void * p_context); - static void AutoReLockTimerEventHandler(AppEvent * aEvent); - static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); - - static BoltLockManager sLock; -}; - -inline BoltLockManager & BoltLockMgr(void) -{ - return BoltLockManager::sLock; -} diff --git a/examples/lock-app/nrf5/main/include/app_config.h b/examples/lock-app/nrf5/main/include/app_config.h deleted file mode 100644 index d1edec4629723c..00000000000000 --- a/examples/lock-app/nrf5/main/include/app_config.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -// ----- Memory Config ----- - -#define MEM_MANAGER_ENABLED 1 -#define MEMORY_MANAGER_SMALL_BLOCK_COUNT 4 -#define MEMORY_MANAGER_SMALL_BLOCK_SIZE 32 -#define MEMORY_MANAGER_MEDIUM_BLOCK_COUNT 4 -#define MEMORY_MANAGER_MEDIUM_BLOCK_SIZE 256 -#define MEMORY_MANAGER_LARGE_BLOCK_COUNT 1 -#define MEMORY_MANAGER_LARGE_BLOCK_SIZE 1024 - -// ----- Crypto Config ----- - -#define NRF_CRYPTO_ENABLED 0 - -// ----- Soft Device Config ----- - -#define SOFTDEVICE_PRESENT 1 -#define NRF_SDH_ENABLED 1 -#define NRF_SDH_SOC_ENABLED 1 -#define NRF_SDH_BLE_ENABLED 1 -#define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1 -#define NRF_SDH_BLE_VS_UUID_COUNT 2 -#define NRF_BLE_GATT_ENABLED 1 -#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 251 -#define NRF_SDH_BLE_GAP_DATA_LENGTH 251 - -// ----- FDS / Flash Config ----- - -#define FDS_ENABLED 1 -#define FDS_BACKEND NRF_FSTORAGE_SD -#define NRF_FSTORAGE_ENABLED 1 -// Number of virtual flash pages used for FDS data storage. -// NOTE: This value must correspond to FDS_FLASH_PAGES specified in -// linker directives (.ld) file. -#define FDS_VIRTUAL_PAGES 2 - -// ----- Logging Config ----- - -#define NRF_LOG_ENABLED 1 -#define NRF_LOG_DEFAULT_LEVEL 4 -#define NRF_LOG_DEFERRED 0 -#define NRF_LOG_STR_PUSH_BUFFER_SIZE 16 -#define NRF_LOG_USES_TIMESTAMP 1 -#define NRF_LOG_STR_FORMATTER_TIMESTAMP_FORMAT_ENABLED 0 - -#define NRF_LOG_BACKEND_RTT_ENABLED 1 -#define NRF_LOG_BACKEND_UART_ENABLED 0 - -#define UART_ENABLED 1 -#define UART1_ENABLED 1 - -#if NRF_LOG_BACKEND_UART_ENABLED - -#define NRF_LOG_BACKEND_UART_TX_PIN 6 -#define NRF_LOG_BACKEND_UART_BAUDRATE 30801920 -#define NRF_LOG_BACKEND_UART_TEMP_BUFFER_SIZE 64 - -#define UART0_ENABLED 1 -#define NRFX_UARTE_ENABLED 1 -#define NRFX_UART_ENABLED 1 -#define UART_LEGACY_SUPPORT 0 - -#endif // NRF_LOG_BACKEND_UART_ENABLED - -#if NRF_LOG_BACKEND_RTT_ENABLED - -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 4096 -#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 1 -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16 -#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 1 - -// <0=> SKIP -// <1=> TRIM -// <2=> BLOCK_IF_FIFO_FULL -#define SEGGER_RTT_CONFIG_DEFAULT_MODE 1 - -#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS 1 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_CNT 3 - -#endif // NRF_LOG_BACKEND_RTT_ENABLED - -// ----- Misc Config ----- - -// Enable the Nordic ASSERT() macro. This also has the effect of enabling -// FreeRTOS configASSERT() due to logic in FreeRTOSConfig.h -#define DEBUG_NRF 1 - -#define NRF_CLOCK_ENABLED 1 -#define NRF_FPRINTF_ENABLED 1 -#define NRF_STRERROR_ENABLED 1 -#define NRF_QUEUE_ENABLED 1 -#define APP_TIMER_ENABLED 1 -#define BUTTON_ENABLED 1 - -#define GPIOTE_ENABLED 1 -#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 3 - -#define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10 - -// ---- Lock Example App Config ---- - -#define LOCK_BUTTON BUTTON_2 -#define FUNCTION_BUTTON BUTTON_1 -#define JOIN_BUTTON BUTTON_4 -#define FUNCTION_BUTTON_DEBOUNCE_PERIOD_MS 50 - -#define SYSTEM_STATE_LED BSP_LED_0 -#define LOCK_STATE_LED BSP_LED_1 -#define LOCK_STATE_LED_GPIO 3 - -// Time it takes in ms for the simulated actuator to move from one -// state to another. -#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 - -// ---- Lock Example SWU Config ---- -#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours -#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours - -// ---- Thread Polling Config ---- -#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 -#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 diff --git a/examples/lock-app/nrf5/main/main.cpp b/examples/lock-app/nrf5/main/main.cpp deleted file mode 100644 index 66d046821d5eb7..00000000000000 --- a/examples/lock-app/nrf5/main/main.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include - -#include "boards.h" -#include "nrf_delay.h" -#include "nrf_log.h" -#ifdef SOFTDEVICE_PRESENT -#include "nrf_sdh.h" -#include "nrf_sdh_ble.h" -#include "nrf_sdh_soc.h" -#endif -#include "nrf_drv_clock.h" -#if NRF_CRYPTO_ENABLED -#include "nrf_crypto.h" -#endif -#include "mem_manager.h" -#if CHIP_ENABLE_OPENTHREAD -extern "C" { -#include "multiprotocol_802154_config.h" -#include "nrf_802154.h" -#include "nrf_cc310_platform_abort.h" -#include "nrf_cc310_platform_mutex.h" -#include -} -#endif // CHIP_ENABLE_OPENTHREAD - -#if NRF_LOG_ENABLED -#include "nrf_log_backend_uart.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -#endif // NRF_LOG_ENABLED - -#include "chipinit.h" -#include "nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.h" -#include -#include - -using namespace ::chip; -using namespace ::chip::Inet; -using namespace ::chip::DeviceLayer; - -extern "C" size_t GetHeapTotalSize(void); - -// ================================================================================ -// Logging Support -// ================================================================================ - -#if NRF_LOG_ENABLED - -#if NRF_LOG_USES_TIMESTAMP - -uint32_t LogTimestamp(void) -{ - return 0; -} - -#define LOG_TIMESTAMP_FUNC LogTimestamp -#define LOG_TIMESTAMP_FREQ 1000 - -#else // NRF_LOG_USES_TIMESTAMP - -#define LOG_TIMESTAMP_FUNC NULL -#define LOG_TIMESTAMP_FREQ 0 - -#endif // NRF_LOG_USES_TIMESTAMP - -#endif // NRF_LOG_ENABLED - -// ================================================================================ -// SoftDevice Support -// ================================================================================ - -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - -static void OnSoCEvent(uint32_t sys_evt, void * p_context) -{ -#if CHIP_ENABLE_OPENTHREAD - otSysSoftdeviceSocEvtHandler(sys_evt); -#endif - UNUSED_PARAMETER(p_context); -} - -#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - -// ================================================================================ -// J-Link Monitor Mode Debugging Support -// ================================================================================ - -#if JLINK_MMD - -extern "C" void JLINK_MONITOR_OnExit(void) {} - -extern "C" void JLINK_MONITOR_OnEnter(void) {} - -extern "C" void JLINK_MONITOR_OnPoll(void) {} - -#endif // JLINK_MMD - -// ================================================================================ -// Main Code -// ================================================================================ - -int main(void) -{ - ret_code_t ret; - -#if JLINK_MMD - NVIC_SetPriority(DebugMonitor_IRQn, _PRIO_SD_LOWEST); -#endif - - // Initialize clock driver. - ret = nrf_drv_clock_init(); - APP_ERROR_CHECK(ret); - - nrf_drv_clock_lfclk_request(NULL); - - // Wait for the clock to be ready. - while (!nrf_clock_lf_is_running()) - { - } - -#if NRF_LOG_ENABLED - - // Initialize logging component - ret = NRF_LOG_INIT(LOG_TIMESTAMP_FUNC, LOG_TIMESTAMP_FREQ); - APP_ERROR_CHECK(ret); - - // Initialize logging backends - NRF_LOG_DEFAULT_BACKENDS_INIT(); - -#endif - - NRF_LOG_INFO("=================================================="); - NRF_LOG_INFO("chip-nrf52840-lock-example starting"); -#if BUILD_RELEASE - NRF_LOG_INFO("*** PSEUDO-RELEASE BUILD ***"); -#else - NRF_LOG_INFO("*** DEVELOPMENT BUILD ***"); -#endif - NRF_LOG_INFO("=================================================="); - NRF_LOG_FLUSH(); - -#ifndef NDEBUG - // TODO: Move this into a standalone test. - freertos_newlib_lock_test(); -#endif - -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - NRF_LOG_INFO("Enabling SoftDevice"); - - ret = nrf_sdh_enable_request(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("nrf_sdh_enable_request() failed"); - APP_ERROR_HANDLER(ret); - } - - NRF_LOG_INFO("Waiting for SoftDevice to be enabled"); - - while (!nrf_sdh_is_enabled()) - { - } - - // Register a handler for SOC events. - NRF_SDH_SOC_OBSERVER(m_soc_observer, NRF_SDH_SOC_STACK_OBSERVER_PRIO, OnSoCEvent, NULL); - - NRF_LOG_INFO("SoftDevice enable complete"); - -#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - { - uint32_t appRAMStart = 0; - - // Configure the BLE stack using the default settings. - // Fetch the start address of the application RAM. - ret = nrf_sdh_ble_default_cfg_set(CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG, &appRAMStart); - APP_ERROR_CHECK(ret); - - // Enable BLE stack. - ret = nrf_sdh_ble_enable(&appRAMStart); - APP_ERROR_CHECK(ret); - NRF_LOG_INFO("SoftDevice BLE enabled"); - } - -#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - ret = ChipInit(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("ChipInit() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = GetAppTask().StartAppTask(); - if (ret != NRF_SUCCESS) - { - NRF_LOG_INFO("GetAppTask().Init() failed"); - APP_ERROR_HANDLER(ret); - } - - // Activate deep sleep mode - SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; - -#if CHIP_CONFIG_MEMORY_MGMT_MALLOC && __GNU_LIBRARY__ - { - struct mallinfo minfo = mallinfo(); - NRF_LOG_INFO("System Heap Utilization: heap size %" PRId32 ", arena size %" PRId32 ", in use %" PRId32 ", free %" PRId32, - GetHeapTotalSize(), minfo.arena, minfo.uordblks, minfo.fordblks); - } -#endif // CHIP_CONFIG_MEMORY_MGMT_MALLOC && __GNU_LIBRARY__ - - NRF_LOG_INFO("Starting FreeRTOS scheduler"); - - /* Start FreeRTOS scheduler. */ - vTaskStartScheduler(); - - // Should never get here - NRF_LOG_INFO("vTaskStartScheduler() failed"); - APP_ERROR_HANDLER(0); -} diff --git a/examples/lock-app/nrf5/third_party/connectedhomeip b/examples/lock-app/nrf5/third_party/connectedhomeip deleted file mode 120000 index c866b86874994d..00000000000000 --- a/examples/lock-app/nrf5/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../.. \ No newline at end of file diff --git a/examples/pigweed-app/nrf5/.gn b/examples/pigweed-app/nrf5/.gn deleted file mode 100644 index 89dc9a6fcb5f6c..00000000000000 --- a/examples/pigweed-app/nrf5/.gn +++ /dev/null @@ -1,26 +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. - -# The location of the build configuration file. -buildconfig = "//build/config/BUILDCONFIG.gn" - -# CHIP uses angle bracket includes. -check_system_includes = true - -default_args = { - target_cpu = "arm" - target_os = "freertos" - - import("//args.gni") -} diff --git a/examples/pigweed-app/nrf5/BUILD.gn b/examples/pigweed-app/nrf5/BUILD.gn deleted file mode 100644 index 7d4213e743c13c..00000000000000 --- a/examples/pigweed-app/nrf5/BUILD.gn +++ /dev/null @@ -1,77 +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. - -import("//build_overrides/chip.gni") -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") -import("//build_overrides/pigweed.gni") -import("$dir_pw_build/target_types.gni") - -import("${nrf5_sdk_build_root}/nrf5_executable.gni") -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") - -assert(current_os == "freertos") - -nrf5_platform_dir = "${chip_root}/examples/platform/nrf528xx" - -pw_static_library("hdlc_server") { - public_configs = [ "${dir_pigweed}/pw_hdlc_lite:default_config" ] - sources = [ - "${dir_pigweed}/pw_hdlc_lite/rpc_example/hdlc_rpc_server.cc", - "main/include/app_config.h", - "main/main.cpp", - ] - deps = [ - "$dir_pw_rpc:server", - "$dir_pw_rpc/nanopb:echo_service", - "${dir_pigweed}/pw_hdlc_lite:pw_rpc", - "${nrf5_platform_dir}/app/support:freertos_debugging_hooks", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support", - "${nrf5_platform_dir}/pw_sys_io:pw_sys_io_baremetal_nrf528xx", - "${nrf5_platform_dir}/sdk:sdk", - dir_pw_hdlc_lite, - dir_pw_log, - ] -} - -nrf5_executable("pigweed_app") { - output_name = "chip-nrf52840-pigweed-example" - - deps = [ ":hdlc_server" ] - - output_dir = root_out_dir - - ldscript = "${nrf5_platform_dir}/app/ldscripts/chip-nrf52840-example.ld" - - ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] -} - -copy("mobly_tests") { - sources = [ - "mobly_tests/pigweed_mobly_config.yml", - "mobly_tests/pigweed_mobly_test.py", - ] - outputs = [ "$root_out_dir/{{source_file_part}}" ] -} - -group("nrf5") { - deps = [ - ":mobly_tests", - ":pigweed_app", - ] -} - -group("default") { - deps = [ ":nrf5" ] -} diff --git a/examples/pigweed-app/nrf5/args.gni b/examples/pigweed-app/nrf5/args.gni deleted file mode 100644 index 79f326880baba0..00000000000000 --- a/examples/pigweed-app/nrf5/args.gni +++ /dev/null @@ -1,35 +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. - -import("//build_overrides/chip.gni") - -import("${chip_root}/examples/platform/nrf528xx/args.gni") - -import("//build_overrides/pigweed.gni") - -pw_log_BACKEND = "$dir_pw_log_basic" -pw_assert_BACKEND = "$dir_pw_assert_log" -pw_sys_io_BACKEND = "${chip_root}/examples/platform/nrf528xx/pw_sys_io:pw_sys_io_baremetal_nrf528xx" - -dir_pw_third_party_nanopb = "${chip_root}/third_party/nanopb/repo" -pw_protobuf_GENERATORS = [ - "pwpb", - "nanopb_rpc", -] - -# SDK target. This is overriden to add our SDK app_config.h & defines. -nrf5_sdk_target = - get_label_info("${chip_root}/examples/platform/nrf528xx/sdk:sdk", - "label_no_toolchain") -nrf5_app_config_dir = get_path_info("main/include", "abspath") diff --git a/examples/pigweed-app/nrf5/build b/examples/pigweed-app/nrf5/build deleted file mode 120000 index d56ed62ae4d1ff..00000000000000 --- a/examples/pigweed-app/nrf5/build +++ /dev/null @@ -1 +0,0 @@ -third_party/connectedhomeip/build \ No newline at end of file diff --git a/examples/pigweed-app/nrf5/build_overrides b/examples/pigweed-app/nrf5/build_overrides deleted file mode 120000 index 194ee0b812dc3d..00000000000000 --- a/examples/pigweed-app/nrf5/build_overrides +++ /dev/null @@ -1 +0,0 @@ -../../build_overrides/ \ No newline at end of file diff --git a/examples/pigweed-app/nrf5/main/include/app_config.h b/examples/pigweed-app/nrf5/main/include/app_config.h deleted file mode 100644 index 8720b7f435c121..00000000000000 --- a/examples/pigweed-app/nrf5/main/include/app_config.h +++ /dev/null @@ -1,143 +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. - */ - -#pragma once - -// ----- Memory Config ----- - -#define MEM_MANAGER_ENABLED 1 -#define MEMORY_MANAGER_SMALL_BLOCK_COUNT 4 -#define MEMORY_MANAGER_SMALL_BLOCK_SIZE 32 -#define MEMORY_MANAGER_MEDIUM_BLOCK_COUNT 4 -#define MEMORY_MANAGER_MEDIUM_BLOCK_SIZE 256 -#define MEMORY_MANAGER_LARGE_BLOCK_COUNT 1 -#define MEMORY_MANAGER_LARGE_BLOCK_SIZE 1024 - -// ----- Crypto Config ----- - -#define NRF_CRYPTO_ENABLED 0 - -// ----- Soft Device Config ----- - -#define SOFTDEVICE_PRESENT 1 -#define NRF_SDH_ENABLED 1 -#define NRF_SDH_SOC_ENABLED 1 -#define NRF_SDH_BLE_ENABLED 1 -#define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1 -#define NRF_SDH_BLE_VS_UUID_COUNT 2 -#define NRF_BLE_GATT_ENABLED 1 -#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 251 -#define NRF_SDH_BLE_GAP_DATA_LENGTH 251 - -// ----- FDS / Flash Config ----- - -#define FDS_ENABLED 1 -#define FDS_BACKEND NRF_FSTORAGE_SD -#define NRF_FSTORAGE_ENABLED 1 -// Number of virtual flash pages used for FDS data storage. -// NOTE: This value must correspond to FDS_FLASH_PAGES specified in -// linker directives (.ld) file. -#define FDS_VIRTUAL_PAGES 2 - -// ----- Logging Config ----- - -#define NRF_LOG_ENABLED 1 -#define NRF_LOG_DEFAULT_LEVEL 4 -#define NRF_LOG_DEFERRED 0 -#define NRF_LOG_STR_PUSH_BUFFER_SIZE 16 -#define NRF_LOG_USES_TIMESTAMP 1 -#define NRF_LOG_STR_FORMATTER_TIMESTAMP_FORMAT_ENABLED 0 - -#define NRF_LOG_BACKEND_RTT_ENABLED 1 -#define NRF_LOG_BACKEND_UART_ENABLED 0 - -#define UART_ENABLED 1 -#define UART1_ENABLED 1 -#define NRFX_UART_ENABLED 1 -#define NRFX_UARTE_ENABLED 1 -#define NRFX_UARTE1_ENABLED 1 -#define UART_LEGACY_SUPPORT 0 - -#if NRF_LOG_BACKEND_UART_ENABLED - -#define NRF_LOG_BACKEND_UART_TX_PIN 6 -#define NRF_LOG_BACKEND_UART_BAUDRATE 30801920 -#define NRF_LOG_BACKEND_UART_TEMP_BUFFER_SIZE 64 - -#endif // NRF_LOG_BACKEND_UART_ENABLED - -#if NRF_LOG_BACKEND_RTT_ENABLED - -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 4096 -#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 1 -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16 -#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 1 - -// <0=> SKIP -// <1=> TRIM -// <2=> BLOCK_IF_FIFO_FULL -#define SEGGER_RTT_CONFIG_DEFAULT_MODE 1 - -#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS 1 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_CNT 3 - -#endif // NRF_LOG_BACKEND_RTT_ENABLED - -// ----- Misc Config ----- - -// Enable the Nordic ASSERT() macro. This also has the effect of enabling -// FreeRTOS configASSERT() due to logic in FreeRTOSConfig.h -#define DEBUG_NRF 1 - -#define NRF_CLOCK_ENABLED 1 -#define NRF_FPRINTF_ENABLED 1 -#define NRF_STRERROR_ENABLED 1 -#define NRF_QUEUE_ENABLED 1 -#define APP_TIMER_ENABLED 1 -#define BUTTON_ENABLED 1 -#define APP_UART_ENABLED 1 -#define APP_FIFO_ENABLED 1 -#define APP_UART_DRIVER_INSTANCE 1 - -#define GPIOTE_ENABLED 1 -#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 3 - -#define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10 - -// ---- Lock Example App Config ---- - -#define LOCK_BUTTON BUTTON_2 -#define FUNCTION_BUTTON BUTTON_1 -#define JOIN_BUTTON BUTTON_4 -#define FUNCTION_BUTTON_DEBOUNCE_PERIOD_MS 50 - -#define SYSTEM_STATE_LED BSP_LED_0 -#define LOCK_STATE_LED BSP_LED_1 -#define LOCK_STATE_LED_GPIO 3 - -// Time it takes in ms for the simulated actuator to move from one -// state to another. -#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 - -// ---- Lock Example SWU Config ---- -#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours -#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours - -// ---- Thread Polling Config ---- -#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 -#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 diff --git a/examples/pigweed-app/nrf5/main/main.cpp b/examples/pigweed-app/nrf5/main/main.cpp deleted file mode 100644 index 487858dddf5115..00000000000000 --- a/examples/pigweed-app/nrf5/main/main.cpp +++ /dev/null @@ -1,101 +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. - */ - -#include -#include -#include - -#include "boards.h" -#include "nrf_drv_clock.h" -#include "nrf_gpio.h" -#include "nrf_log.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -#include "pw_sys_io/sys_io.h" -#include "pw_sys_io_baremetal_nrf528xx/init.h" - -using std::byte; - -namespace hdlc_example { -extern void Start(); -} // namespace hdlc_example - -namespace { -constexpr uint32_t kLedActive = LEDS_ACTIVE_STATE ? 1 : 0; -bool led_state = true; - -uint32_t LogTimestamp(void) -{ - return 0; -} - -#define LOG_TIMESTAMP_FUNC LogTimestamp -#define LOG_TIMESTAMP_FREQ 1000 - -} // namespace - -int main() -{ - ret_code_t ret; - - pw_sys_io_Init(); - -#if JLINK_MMD - NVIC_SetPriority(DebugMonitor_IRQn, _PRIO_SD_LOWEST); -#endif - - // Initialize clock driver. - ret = nrf_drv_clock_init(); - APP_ERROR_CHECK(ret); - - nrf_drv_clock_lfclk_request(NULL); - - // Wait for the clock to be ready. - while (!nrf_clock_lf_is_running()) - { - } - -#if NRF_LOG_ENABLED - - // Initialize logging component - ret = NRF_LOG_INIT(LOG_TIMESTAMP_FUNC, LOG_TIMESTAMP_FREQ); - APP_ERROR_CHECK(ret); - - // Initialize logging backends - NRF_LOG_DEFAULT_BACKENDS_INIT(); - -#endif - - NRF_LOG_INFO("=================================================="); - NRF_LOG_INFO("chip-nrf52840-pigweed-example starting"); -#if BUILD_RELEASE - NRF_LOG_INFO("*** PSEUDO-RELEASE BUILD ***"); -#else - NRF_LOG_INFO("*** DEVELOPMENT BUILD ***"); -#endif - NRF_LOG_INFO("=================================================="); - NRF_LOG_FLUSH(); - - // Light up the LED as a visual feedback that the flash was - // successful. - nrf_gpio_cfg_output(SYSTEM_STATE_LED); - nrf_gpio_pin_write(SYSTEM_STATE_LED, led_state ? kLedActive : !kLedActive); - - hdlc_example::Start(); - - return 0; -} diff --git a/examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_config.yml b/examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_config.yml deleted file mode 100644 index 7c53d1eeeefa01..00000000000000 --- a/examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_config.yml +++ /dev/null @@ -1,25 +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. - -TestBeds: - # A test bed where pw_rpc will find a CHIP device - - Name: SampleTestBed - Controllers: - PigweedDevice: - - device_tty: /dev/ttyACM0 - baud: 115200 - platform_module: nrf5_firmware_utils - platform_args: - - application: chip-nrf52840-pigweed-example.hex - softdevice: s140_nrf52_7.0.1_softdevice.hex diff --git a/examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_test.py b/examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_test.py deleted file mode 100755 index d2e182ee89ebfe..00000000000000 --- a/examples/pigweed-app/nrf5/mobly_tests/pigweed_mobly_test.py +++ /dev/null @@ -1,43 +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. - -from chip_mobly import pigweed_device -from mobly import asserts -from mobly import base_test -from mobly import test_runner - - -class PigweedMoblyTest(base_test.BaseTestClass): - def setup_class(self): - # Registering pigweed_device controller module declares the test's - # dependency on CHIP/Pigweed device hardware. By default, we expect at least one - # object is created from this. - # Flashes the image passed in the configuration yml. - self.ads = self.register_controller(pigweed_device) - self.dut = self.ads[0] - self.dut.platform.flash() - - def test_hello(self): - expected = "hello!" - status, payload = self.dut.rpcs().EchoService.Echo(msg=expected) - asserts.assert_true(status.ok(), "Status is %s" % status) - asserts.assert_equal( - payload.msg, - expected, - 'Returned payload is "%s" expected "%s"' % (payload.msg, expected), - ) - - -if __name__ == "__main__": - test_runner.main() diff --git a/examples/pigweed-app/nrf5/third_party/connectedhomeip b/examples/pigweed-app/nrf5/third_party/connectedhomeip deleted file mode 120000 index c866b86874994d..00000000000000 --- a/examples/pigweed-app/nrf5/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../.. \ No newline at end of file diff --git a/examples/platform/nrf528xx/BUILD.gn b/examples/platform/nrf528xx/BUILD.gn deleted file mode 100644 index 768c066f6855c7..00000000000000 --- a/examples/platform/nrf528xx/BUILD.gn +++ /dev/null @@ -1,25 +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. - -import("//build_overrides/chip.gni") - -config("chip_examples_project_config") { - include_dirs = [ "app/project_include" ] -} - -source_set("openthread_core_config_nrf52840_chip_examples") { - sources = [ "app/project_include/OpenThreadConfig.h" ] - public_deps = [ "${chip_root}/third_party/openthread/platforms/nrf528xx:openthread_core_config_nrf52840" ] - public_configs = [ ":chip_examples_project_config" ] -} diff --git a/examples/platform/nrf528xx/app/Service.cpp b/examples/platform/nrf528xx/app/Service.cpp deleted file mode 100644 index 905887231f4b40..00000000000000 --- a/examples/platform/nrf528xx/app/Service.cpp +++ /dev/null @@ -1,117 +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. - */ - -/** - * @file - * This file implements the service publishing code for example usage. - */ - -#include "Service.h" - -#include "FreeRTOS.h" -#include "nrf_log.h" -#include "task.h" -#include -#include - -#include "lwip/err.h" -#include "lwip/sockets.h" -#include "lwip/sys.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#include -#include -#include -#endif - -using namespace ::chip; -using namespace ::chip::Inet; -using namespace ::chip::Transport; -using namespace ::chip::DeviceLayer; - -// Transport Callbacks -namespace { - -char deviceName[128]; -constexpr uint16_t kUDPBroadcastPort = 23367; - -} // namespace - -void SetDeviceName(const char * newDeviceName) -{ - strncpy(deviceName, newDeviceName, sizeof(deviceName) - 1); -} - -void PublishService() -{ - chip::Inet::IPAddress addr; - if (!ConnectivityMgrImpl().IsThreadAttached()) - { - return; - } - ThreadStackMgrImpl().LockThreadStack(); - otError error = OT_ERROR_NONE; - otMessageInfo messageInfo; - otUdpSocket mSocket; - otMessage * message = nullptr; - - memset(&mSocket, 0, sizeof(mSocket)); - memset(&messageInfo, 0, sizeof(messageInfo)); - - // Use mesh local EID by default, if we have GUA, use that IP address. - memcpy(&messageInfo.mSockAddr, otThreadGetMeshLocalEid(ThreadStackMgrImpl().OTInstance()), sizeof(messageInfo.mSockAddr)); - - // Select a address to send - const otNetifAddress * otAddrs = otIp6GetUnicastAddresses(ThreadStackMgrImpl().OTInstance()); - for (const otNetifAddress * otAddr = otAddrs; otAddr != NULL; otAddr = otAddr->mNext) - { - addr = chip::DeviceLayer::Internal::ToIPAddress(otAddr->mAddress); - if (otAddr->mValid && addr.IsIPv6GlobalUnicast()) - { - memcpy(&messageInfo.mSockAddr, &(otAddr->mAddress), sizeof(otAddr->mAddress)); - break; - } - } - - message = otUdpNewMessage(ThreadStackMgrImpl().OTInstance(), nullptr); - otIp6AddressFromString("ff03::1", &messageInfo.mPeerAddr); - messageInfo.mPeerPort = kUDPBroadcastPort; - otMessageAppend(message, deviceName, static_cast(strlen(deviceName))); - - error = otUdpSend(ThreadStackMgrImpl().OTInstance(), &mSocket, message, &messageInfo); - - if (error != OT_ERROR_NONE && message != nullptr) - { - otMessageFree(message); - NRF_LOG_INFO("Failed to otUdpSend: %d", error); - } - ThreadStackMgrImpl().UnlockThreadStack(); -} diff --git a/examples/platform/nrf528xx/app/chipinit.cpp b/examples/platform/nrf528xx/app/chipinit.cpp deleted file mode 100644 index 2ebb949dc68458..00000000000000 --- a/examples/platform/nrf528xx/app/chipinit.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "chipinit.h" - -#include - -#include -#include - -#include "boards.h" -#include "nrf_delay.h" -#include "nrf_log.h" -#ifdef SOFTDEVICE_PRESENT -#include "nrf_sdh.h" -#include "nrf_sdh_ble.h" -#include "nrf_sdh_soc.h" -#endif -#include "nrf_drv_clock.h" -#if NRF_CRYPTO_ENABLED -#include "nrf_crypto.h" -#endif -#include "mem_manager.h" -#if CHIP_ENABLE_OPENTHREAD -extern "C" { -#include "multiprotocol_802154_config.h" -#include "nrf_802154.h" -#include "nrf_cc310_platform_abort.h" -#include "nrf_cc310_platform_mutex.h" -#include -} -#endif // CHIP_ENABLE_OPENTHREAD - -#if NRF_LOG_ENABLED -#include "nrf_log_backend_uart.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -#endif // NRF_LOG_ENABLED - -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif // CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#include - -using namespace ::chip; -using namespace ::chip::DeviceLayer; - -#if CHIP_ENABLE_OPENTHREAD -static void * ot_calloc(size_t n, size_t size) -{ - void * p_ptr = NULL; - - p_ptr = pvPortMalloc(n * size); - - memset(p_ptr, 0, n * size); - - return p_ptr; -} - -static void ot_free(void * p_ptr) -{ - vPortFree(p_ptr); -} -#endif - -ret_code_t ChipInit() -{ - ret_code_t ret = CHIP_NO_ERROR; - - NRF_LOG_INFO("Init CHIP stack"); - ret = chip::Platform::MemoryInit(); - if (ret != CHIP_NO_ERROR) - { - NRF_LOG_INFO("PlatformMgr().InitChipStack() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = PlatformMgr().InitChipStack(); - if (ret != CHIP_NO_ERROR) - { - NRF_LOG_INFO("PlatformMgr().InitChipStack() failed"); - APP_ERROR_HANDLER(ret); - } - -#if CHIP_ENABLE_OPENTHREAD - NRF_LOG_INFO("Initializing OpenThread stack"); - - nrf_cc310_platform_abort_init(); - nrf_cc310_platform_mutex_init(); - mbedtls_platform_setup(NULL); - - otSysInit(0, NULL); - NRF_LOG_INFO("Initializing OpenThread stack"); - - // Configure multiprotocol to work with BLE. - { - uint32_t retval = multiprotocol_802154_mode_set(MULTIPROTOCOL_802154_MODE_FAST_SWITCHING_TIMES); - - if (retval != NRF_SUCCESS) - { - NRF_LOG_INFO("multiprotocol 15.4 failed"); - APP_ERROR_HANDLER(CHIP_ERROR_INTERNAL); - } - } - - ret = ThreadStackMgr().InitThreadStack(); - if (ret != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ThreadStackMgr().InitThreadStack() failed"); - APP_ERROR_HANDLER(ret); - } - - ret = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router); - if (ret != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ConnectivityMgr().SetThreadDeviceType() failed"); - APP_ERROR_HANDLER(ret); - } -#endif // CHIP_ENABLE_OPENTHREAD - - NRF_LOG_INFO("Starting CHIP task"); - ret = PlatformMgr().StartEventLoopTask(); - if (ret != CHIP_NO_ERROR) - { - NRF_LOG_INFO("PlatformMgr().StartEventLoopTask() failed"); - APP_ERROR_HANDLER(ret); - } - -#if CHIP_ENABLE_OPENTHREAD - NRF_LOG_INFO("Starting OpenThread task"); - - // Start OpenThread task - ret = ThreadStackMgrImpl().StartThreadTask(); - if (ret != CHIP_NO_ERROR) - { - NRF_LOG_INFO("ThreadStackMgr().StartThreadTask() failed"); - APP_ERROR_HANDLER(ret); - } -#endif // CHIP_ENABLE_OPENTHREAD - - return ret; -} diff --git a/examples/platform/nrf528xx/app/include/Service.h b/examples/platform/nrf528xx/app/include/Service.h deleted file mode 100644 index 1426ec65adec71..00000000000000 --- a/examples/platform/nrf528xx/app/include/Service.h +++ /dev/null @@ -1,21 +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. - */ - -#pragma once - -void SetDeviceName(const char * newDeviceName); -void PublishService(); diff --git a/examples/platform/nrf528xx/app/include/chipinit.h b/examples/platform/nrf528xx/app/include/chipinit.h deleted file mode 100644 index 446d8fe3622787..00000000000000 --- a/examples/platform/nrf528xx/app/include/chipinit.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "sdk_common.h" - -ret_code_t ChipInit(); diff --git a/examples/platform/nrf528xx/app/ldscripts/chip-nrf52840-example.ld b/examples/platform/nrf528xx/app/ldscripts/chip-nrf52840-example.ld deleted file mode 100644 index 46a6e165bdaf20..00000000000000 --- a/examples/platform/nrf528xx/app/ldscripts/chip-nrf52840-example.ld +++ /dev/null @@ -1,131 +0,0 @@ -SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) - -/* Total size of device FLASH in bytes */ -TOTAL_FLASH_SIZE = 0x100000; - -/* Total size of device RAM in bytes */ -TOTAL_RAM_SIZE = 0x40000; - -/* Size of an individual FLASH page in bytes */ -FLASH_PAGE_SIZE = 4096; - -/* Number of FLASH pages reserved for Nordic FDS. NOTE: This MUST correspond - * to the value specified for FDS_VIRTUAL_PAGES in app_config.h */ -FDS_FLASH_PAGES = 2; - -/* Number of FLASH pages reserved for OpenThread data storage. */ -OT_DATA_FLASH_PAGES = 4; - -MEMORY -{ - /* FLASH region occupied by the Nordic SoftDevice */ - SD_FLASH (rx) : ORIGIN = 0, LENGTH = 0x27000 - - /* RAM region used by the Nordic SoftDevice */ - SD_RAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x5800 - - /* FLASH region used for Nordic FDS value storage. */ - FDS_FLASH (rw) : ORIGIN = TOTAL_FLASH_SIZE - (FLASH_PAGE_SIZE * FDS_FLASH_PAGES), LENGTH = (FLASH_PAGE_SIZE * FDS_FLASH_PAGES) - - /* FLASH region used for OpenThread data storage. */ - OT_DATA_FLASH (rw) : ORIGIN = ORIGIN(FDS_FLASH) - (FLASH_PAGE_SIZE * OT_DATA_FLASH_PAGES), LENGTH = (FLASH_PAGE_SIZE * OT_DATA_FLASH_PAGES) - - /* FLASH region used for application code and read-only data. */ - FLASH (rx) : ORIGIN = ORIGIN(SD_FLASH) + LENGTH(SD_FLASH), LENGTH = ORIGIN(OT_DATA_FLASH) - ORIGIN(FLASH) - - /* RAM region used for application dynamic data. */ - RAM (rw) : ORIGIN = ORIGIN(SD_RAM) + LENGTH(SD_RAM), LENGTH = TOTAL_RAM_SIZE - LENGTH(SD_RAM) -} - -SECTIONS -{ - . = ALIGN(4); - - .log_dynamic_data : - { - PROVIDE(__start_log_dynamic_data = .); - KEEP(*(SORT(.log_dynamic_data*))) - PROVIDE(__stop_log_dynamic_data = .); - } > RAM - - .log_filter_data : - { - PROVIDE(__start_log_filter_data = .); - KEEP(*(SORT(.log_filter_data*))) - PROVIDE(__stop_log_filter_data = .); - } > RAM -} -INSERT AFTER .data; - -SECTIONS -{ - .sdh_soc_observers : - { - PROVIDE(__start_sdh_soc_observers = .); - KEEP(*(SORT(.sdh_soc_observers*))) - PROVIDE(__stop_sdh_soc_observers = .); - } > FLASH - - .sdh_ble_observers : - { - PROVIDE(__start_sdh_ble_observers = .); - KEEP(*(SORT(.sdh_ble_observers*))) - PROVIDE(__stop_sdh_ble_observers = .); - } > FLASH - - .sdh_stack_observers : - { - PROVIDE(__start_sdh_stack_observers = .); - KEEP(*(SORT(.sdh_stack_observers*))) - PROVIDE(__stop_sdh_stack_observers = .); - } > FLASH - - .sdh_req_observers : - { - PROVIDE(__start_sdh_req_observers = .); - KEEP(*(SORT(.sdh_req_observers*))) - PROVIDE(__stop_sdh_req_observers = .); - } > FLASH - - .sdh_state_observers : - { - PROVIDE(__start_sdh_state_observers = .); - KEEP(*(SORT(.sdh_state_observers*))) - PROVIDE(__stop_sdh_state_observers = .); - } > FLASH - - .crypto_data : - { - PROVIDE(__start_crypto_data = .); - KEEP(*(SORT(.crypto_data*))) - PROVIDE(__stop_crypto_data = .); - } > FLASH - - .log_const_data : - { - PROVIDE(__start_log_const_data = .); - KEEP(*(SORT(.log_const_data*))) - PROVIDE(__stop_log_const_data = .); - } > FLASH - - .log_backends : - { - PROVIDE(__start_log_backends = .); - KEEP(*(SORT(.log_backends*))) - PROVIDE(__stop_log_backends = .); - } > FLASH - - .nrf_balloc : - { - PROVIDE(__start_nrf_balloc = .); - KEEP(*(.nrf_balloc)) - PROVIDE(__stop_nrf_balloc = .); - } > FLASH - - __start_ot_flash_data = ORIGIN(OT_DATA_FLASH); - __stop_ot_flash_data = (ORIGIN(OT_DATA_FLASH) + LENGTH(OT_DATA_FLASH)); -} -INSERT AFTER .text - -INCLUDE "nrf_common.ld" diff --git a/examples/platform/nrf528xx/app/project_include/CHIPProjectConfig.h b/examples/platform/nrf528xx/app/project_include/CHIPProjectConfig.h deleted file mode 100644 index ea0c8a8aa53844..00000000000000 --- a/examples/platform/nrf528xx/app/project_include/CHIPProjectConfig.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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 - -#if !BUILD_RELEASE // development build - -// For convenience, Chip Security Test Mode can be enabled and the -// requirement for authentication in various protocols can be disabled. -// -// WARNING: These options make it possible to circumvent basic Chip security functionality, -// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. -// -#define CHIP_CONFIG_SECURITY_TEST_MODE 0 -#define CHIP_CONFIG_REQUIRE_AUTH 1 - -/** - * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY - * - * Enables the use of a hard-coded default CHIP device id and credentials if no device id - * is found in CHIP NV storage. - * - * This option is for testing only and should be disabled in production releases. - */ -#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 34 - -// Use a default pairing code if one hasn't been provisioned in flash. -#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 12345678 -#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 - -/** - * CHIP_DEVICE_CONFIG_USE_TEST_SERIAL_NUMBER - * - * Enables the use of a hard-coded default serial number if none - * is found in CHIP NV storage. - */ -#define CHIP_DEVICE_CONFIG_USE_TEST_SERIAL_NUMBER "DUMMY_SN" - -#endif // BUILD_RELEASE - -/** - * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID - * - * 0x235A: Chip's Vendor Id. - */ -#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0x235A - -/** - * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID - * - * 0xFE00: SDK Sample Lock Resource - */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0xFE00 - -/** - * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_REVISION - * - * The product revision number assigned to device or product by the device vendor. This - * number is scoped to the device product id, and typically corresponds to a revision of the - * physical device, a change to its packaging, and/or a change to its marketing presentation. - * This value is generally *not* incremented for device software revisions. - */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_REVISION 1 - -/** - * CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION - * - * A string identifying the firmware revision running on the device. - * CHIP currently expects the firmware version to be in the format - * {MAJOR_VERSION}.0d{MINOR_VERSION} - */ -#ifndef CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION -#define CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION "1.0d1" -#endif -/** - * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - * - * Enable support for CHIP-over-BLE (CHIPOBLE). - */ -#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 - -/** - * CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC - * - * Enables synchronizing the device's real time clock with a remote CHIP Time service - * using the CHIP Time Sync protocol. - */ -//#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 1 - -/** - * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS - * - * Enable recording UTC timestamps. - */ -#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 - -/** - * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE - * - * A size, in bytes, of the individual debug event logging buffer. - */ -#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) - -/** - * CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE - * - * For a development build, set the default importance of events to be logged as Debug. - * Since debug is the lowest importance level, this means all standard, critical, info and - * debug importance level vi events get logged. - */ -#if BUILD_RELEASE -#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Production -#else -#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Debug -#endif // BUILD_RELEASE diff --git a/examples/platform/nrf528xx/app/project_include/FreeRTOSConfig.h b/examples/platform/nrf528xx/app/project_include/FreeRTOSConfig.h deleted file mode 100644 index 93ee9843a2a33f..00000000000000 --- a/examples/platform/nrf528xx/app/project_include/FreeRTOSConfig.h +++ /dev/null @@ -1,216 +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. - */ - -/* - * FreeRTOS Kernel V10.0.0 - * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. If you wish to use our Amazon - * FreeRTOS name, please do so in a fair use way that does not cause confusion. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ - -#pragma once - -#include "sdk_config.h" -#ifdef SOFTDEVICE_PRESENT -#include "nrf_soc.h" -#endif -#include "app_util_platform.h" - -#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */ -#define FREERTOS_USE_SYSTICK 1 /**< Use SysTick timer for system */ - -#define configTICK_SOURCE FREERTOS_USE_RTC - -#define configUSE_PREEMPTION 1 -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 -#define configUSE_TICKLESS_IDLE 1 -#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 1 /* See into vPortSuppressTicksAndSleep source code for explanation */ -#define configCPU_CLOCK_HZ (SystemCoreClock) -#define configTICK_RATE_HZ 1024 -#define configMAX_PRIORITIES (3) -#define configMINIMAL_STACK_SIZE (100) -#define configTOTAL_HEAP_SIZE 0 /* FreeRTOS heap functions mapped to malloc/free (heap_3.c) */ -#define configMAX_TASK_NAME_LEN (8) -#define configUSE_16_BIT_TICKS 0 -#define configIDLE_SHOULD_YIELD 1 -#define configUSE_MUTEXES 1 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ -#define configQUEUE_REGISTRY_SIZE 2 -#define configUSE_QUEUE_SETS 0 -#define configUSE_TIME_SLICING 0 -#define configUSE_NEWLIB_REENTRANT 0 -#define configENABLE_BACKWARD_COMPATIBILITY 1 - -/* Hook function related definitions. */ -#define configUSE_IDLE_HOOK 0 -#define configUSE_TICK_HOOK 0 - -/* Run time and task stats gathering related definitions. */ -#define configGENERATE_RUN_TIME_STATS 0 -#define configUSE_STATS_FORMATTING_FUNCTIONS 0 - -/* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES (2) - -/* Software timer definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY (2) -#define configTIMER_QUEUE_LENGTH 32 - -// TODO: Fix high stack usage in GenericThreadStackManagerImpl_FreeRTOS -#define configTIMER_TASK_STACK_DEPTH (512) - -/* Tickless Idle configuration. */ -#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 - -/* Tickless idle/low power functionality. */ - -/* */ -#define configSUPPORT_DYNAMIC_ALLOCATION 1 - -/* Debugging support. */ -#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 -#define configUSE_TRACE_FACILITY 1 - -/* Define to trap errors during development. */ -#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER) -#define configASSERT(x) ASSERT(x) -#endif - -/* Diagnostic options. */ -#ifndef NDEBUG -#define configCHECK_FOR_STACK_OVERFLOW 2 -#define configUSE_MALLOC_FAILED_HOOK 1 -#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 1 -#endif - -/* FreeRTOS MPU specific definitions. */ -#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1 - -/* Optional functions - most linkers will remove unused functions anyway. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_xResumeFromISR 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 1 -#define INCLUDE_xTaskGetIdleTaskHandle 1 -#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 -#define INCLUDE_pcTaskGetTaskName 1 -#define INCLUDE_eTaskGetState 1 -#define INCLUDE_xEventGroupSetBitFromISR 1 -#define INCLUDE_xTimerPendFunctionCall 0 - -/* The lowest interrupt priority that can be used in a call to a "set priority" -function. */ -#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf - -/* The highest interrupt priority that can be used by any interrupt service -routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL -INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER -PRIORITY THAN THIS! (higher priorities are lower numeric values. */ -#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY _PRIO_APP_HIGH - -/* Interrupt priorities used by the kernel port layer itself. These are generic -to all Cortex-M ports, and do not rely on any particular library functions. */ -#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY -/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! -See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY - -/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS -standard names - or at least those used in the unmodified vector table. */ - -#define vPortSVCHandler SVC_Handler -#define xPortPendSVHandler PendSV_Handler - -/*----------------------------------------------------------- - * Settings that are generated automatically - * basing on the settings above - */ -#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK) -// do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically -// to CPU clock source -#define xPortSysTickHandler SysTick_Handler -#elif (configTICK_SOURCE == FREERTOS_USE_RTC) -#define configSYSTICK_CLOCK_HZ (32768UL) -#define xPortSysTickHandler RTC1_IRQHandler -#else -#error Unsupported configTICK_SOURCE value -#endif - -/* Code below should be only used by the compiler, and not the assembler. */ -#if !(defined(__ASSEMBLY__) || defined(__ASSEMBLER__)) -#include "nrf.h" -#include "nrf_assert.h" - -/* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */ -/* Cortex-M specific definitions. */ -#ifdef __NVIC_PRIO_BITS -/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ -#define configPRIO_BITS __NVIC_PRIO_BITS -#else -#error "This port requires __NVIC_PRIO_BITS to be defined" -#endif - -/* Access to current system core clock is required only if we are ticking the system by systimer */ -#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK) -#include -extern uint32_t SystemCoreClock; -#endif -#endif /* !assembler */ - -/** Implementation note: Use this with caution and set this to 1 ONLY for debugging - * ---------------------------------------------------------- - * Set the value of configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to below for enabling or disabling RTOS tick auto correction: - * 0. This is default. If the RTC tick interrupt is masked for more than 1 tick by higher priority interrupts, then most likely - * one or more RTC ticks are lost. The tick interrupt inside RTOS will detect this and make a correction needed. This is needed - * for the RTOS internal timers to be more accurate. - * 1. The auto correction for RTOS tick is disabled even though few RTC tick interrupts were lost. This feature is desirable when - * debugging the RTOS application and stepping though the code. After stepping when the application is continued in debug mode, the - * auto-corrections of RTOS tick might cause asserts. Setting configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG to 1 will make RTC and - * RTOS go out of sync but could be convenient for debugging. - */ -#define configUSE_DISABLE_TICK_AUTO_CORRECTION_DEBUG 0 diff --git a/examples/platform/nrf528xx/app/project_include/OpenThreadConfig.h b/examples/platform/nrf528xx/app/project_include/OpenThreadConfig.h deleted file mode 100644 index 26d426b900a03a..00000000000000 --- a/examples/platform/nrf528xx/app/project_include/OpenThreadConfig.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Overrides to default OpenThread configuration. - * - */ - -#pragma once - -// Disable the Nordic-supplied OpenThread logging facilities and use -// the facilities provided by the CHIP Device Layer -#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_APP - -// When operating in a less than ideal RF environment, having a more forgiving configuration -// of OpenThread makes thread a great deal more reliable. -#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY 120 // default is 28800 -#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT 15 // default is 3 -#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT 1 // default is 0 -#define OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS 16 // default is 4 - -// Enable periodic parent search to speed up finding a better parent. -#define OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE 1 // default is 0 -#define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -45 // default is -65 -#define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1 // default is 0 - -// Use smaller maximum interval to speed up reattaching. -#define OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_MAXIMUM_INTERVAL (60 * 10 * 1000) // default 1200000 ms - -#define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 0 -#define OPENTHREAD_CONFIG_JOINER_ENABLE 1 -#define OPENTHREAD_CONFIG_NCP_UART_ENABLE 1 -#define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 - -// overly large numbers consume too many memory, especially when the device are -// not intended to process large traffic -#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 44 - -// Use the Nordic-supplied default platform configuration for remainder -// of OpenThread config options. -// -// NB: This file gets included during the build of OpenThread. Hence -// it cannot use "openthread" in the path to the included file. -// -#include "openthread-core-nrf52840-config.h" diff --git a/examples/platform/nrf528xx/app/project_include/freertos_tasks_c_additions.h b/examples/platform/nrf528xx/app/project_include/freertos_tasks_c_additions.h deleted file mode 100644 index 33ce1e1cac200f..00000000000000 --- a/examples/platform/nrf528xx/app/project_include/freertos_tasks_c_additions.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Copyright (c) 2019 Nest Labs, Inc. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Defines a global data structure containing FreeRTOS configuration - * information that is used by the SEGGER FreeRTOS GDB extension to - * enable FreeRTOS-aware debugging. - * - * The file is included directly in FreeRTOS's tasks.c source file - * by means of the configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H - * configuration option. - */ - -#pragma once - -/* - * Version of the FreeRTOSDebugConfig structure - */ -#define FREERTOS_DEBUG_CONFIG_MAJOR_VERSION 1 -#define FREERTOS_DEBUG_CONFIG_MINOR_VERSION 1 - -/* - * The FreeRTOS memory allocation scheme in use. - * - * Must correspond to the heap_x.c source file included in the build (e.g. heap_1.c, heap_2.c, etc.). - */ -#ifndef FREERTOS_MEMORY_SCHEME -#define FREERTOS_MEMORY_SCHEME 1 -#endif - -/* - * FreeRTOS debugging configuration information structure. - */ -const uint8_t FreeRTOSDebugConfig[] __attribute__((section(".rodata"))) = { - FREERTOS_DEBUG_CONFIG_MAJOR_VERSION, - FREERTOS_DEBUG_CONFIG_MINOR_VERSION, - tskKERNEL_VERSION_MAJOR, - tskKERNEL_VERSION_MINOR, - tskKERNEL_VERSION_BUILD, - FREERTOS_MEMORY_SCHEME, - offsetof(struct tskTaskControlBlock, pxTopOfStack), -#if (tskKERNEL_VERSION_MAJOR > 8) - offsetof(struct tskTaskControlBlock, xStateListItem), -#else - offsetof(struct tskTaskControlBlock, xGenericListItem), -#endif - offsetof(struct tskTaskControlBlock, xEventListItem), - offsetof(struct tskTaskControlBlock, pxStack), - offsetof(struct tskTaskControlBlock, pcTaskName), - offsetof(struct tskTaskControlBlock, uxTCBNumber), - offsetof(struct tskTaskControlBlock, uxTaskNumber), - configMAX_TASK_NAME_LEN, - configMAX_PRIORITIES, - 0 /* padding */ -}; diff --git a/examples/platform/nrf528xx/app/project_include/nrf_log_ctrl_internal.h b/examples/platform/nrf528xx/app/project_include/nrf_log_ctrl_internal.h deleted file mode 100644 index b5b2d0ef3facc2..00000000000000 --- a/examples/platform/nrf528xx/app/project_include/nrf_log_ctrl_internal.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * 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 - * Wrapper header file for nrf_log_ctrl_internal.h supplied by - * the Nordic nRF5 SDK. - */ - -// Include the version of nrf_log_ctrl_internal.h supplied by the nRF5 SDK. -#include_next "nrf_log_ctrl_internal.h" - -// When using the non-deferred mode of the nRF5 loggging library in a multi-threaded -// application, calls to NRF_LOG_FLUSH must be serialized across all threads. Later -// versions of the nRF5 SDK provide built-in support for this serialization, via the -// NRF_LOG_NON_DEFFERED_CRITICAL_REGION_ENABLED option. If this feature is NOT -// available, or not enabled, then we override the NRF_LOG_INTERNAL_FLUSH macro to -// enforce serialization. -#if !NRF_LOG_NON_DEFFERED_CRITICAL_REGION_ENABLED - -// Override the NRF_LOG_INTERNAL_FLUSH define to wrap the process of flushing -// pending log entries in a critical section. -#undef NRF_LOG_INTERNAL_FLUSH -#define NRF_LOG_INTERNAL_FLUSH() \ - do \ - { \ - CRITICAL_REGION_ENTER(); \ - while (NRF_LOG_INTERNAL_PROCESS()) \ - ; \ - CRITICAL_REGION_EXIT(); \ - } while (0) - -#endif // !NRF_LOG_NON_DEFFERED_CRITICAL_REGION_ENABLED diff --git a/examples/platform/nrf528xx/app/support/AltPrintf.c b/examples/platform/nrf528xx/app/support/AltPrintf.c deleted file mode 100644 index 40138cbc9a0067..00000000000000 --- a/examples/platform/nrf528xx/app/support/AltPrintf.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * - * 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 - * Substitute newlib printf functions with an alternate, minimal implementation. - * - * This code is intended to work with the tiny printf implementation published by - * Marco Paland (https://github.com/mpaland/printf). - * - */ - -#include -#include -#include - -// Include header file from mpaland printf. -#include "printf.h" - -// Disable the mapping #defines from the printf.h header so the following functions don't get renamed. -#undef printf -#undef sprintf -#undef snprintf -#undef vsnprintf -#undef vprintf - -int printf(const char * format, ...) -{ - /* Stdio not supported */ - return -1; -} - -int sprintf(char * buffer, const char * format, ...) -{ - /* Dangerous; should not be called */ - buffer[0] = 0; - return -1; -} - -int snprintf(char * buffer, size_t count, const char * format, ...) -{ - int res; - va_list va; - va_start(va, format); - res = vsnprintf_(buffer, count, format, va); - va_end(va); - return res; -} - -int vprintf(const char * format, va_list va) -{ - /* Stdio not supported */ - return -1; -} - -int vsprintf(char * buffer, const char * format, va_list va) -{ - /* Dangerous; should not be called */ - buffer[0] = 0; - return -1; -} - -int vsnprintf(char * buffer, size_t count, const char * format, va_list va) -{ - return vsnprintf_(buffer, count, format, va); -} - -int fprintf(FILE * stream, const char * format, ...) -{ - /* Stdio not supported */ - return -1; -} - -int vfprintf(FILE * stream, const char * format, va_list ap) -{ - /* Stdio not supported */ - return -1; -} - -/* iprintf variants */ - -int iprintf(const char * format, ...) -{ - /* Stdio not supported */ - return -1; -} - -int siprintf(char * buffer, const char * format, ...) -{ - /* Dangerous; should not be called */ - buffer[0] = 0; - return -1; -} - -int sniprintf(char * buffer, size_t count, const char * format, ...) -{ - int res; - va_list va; - va_start(va, format); - res = vsnprintf_(buffer, count, format, va); - va_end(va); - return res; -} - -int viprintf(const char * format, va_list va) -{ - /* Stdio not supported */ - return -1; -} - -int vsiprintf(char * buffer, const char * format, va_list va) -{ - /* Dangerous; should not be called */ - buffer[0] = 0; - return -1; -} - -int vsniprintf(char * buffer, size_t count, const char * format, va_list va) -{ - return vsnprintf_(buffer, count, format, va); -} - -int fiprintf(FILE * stream, const char * format, ...) -{ - /* Stdio not supported */ - return -1; -} - -int vfiprintf(FILE * stream, const char * format, va_list ap) -{ - /* Stdio not supported */ - return -1; -} diff --git a/examples/platform/nrf528xx/app/support/BUILD.gn b/examples/platform/nrf528xx/app/support/BUILD.gn deleted file mode 100644 index a25cbc96f85a62..00000000000000 --- a/examples/platform/nrf528xx/app/support/BUILD.gn +++ /dev/null @@ -1,46 +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. - -import("//build_overrides/chip.gni") -import("//build_overrides/nrf5_sdk.gni") - -config("support_config") { - include_dirs = [ "../../.." ] -} - -source_set("freertos_newlib_lock_support") { - sources = [ "FreeRTOSNewlibLockSupport.c" ] - - public_deps = [ "${nrf5_sdk_build_root}:nrf5_sdk" ] - - public_configs = [ ":support_config" ] -} - -source_set("freertos_newlib_lock_support_test") { - sources = [ - "FreeRTOSNewlibLockSupport_test.c", - "FreeRTOSNewlibLockSupport_test.h", - ] - - public_deps = [ ":freertos_newlib_lock_support" ] -} - -source_set("freertos_debugging_hooks") { - sources = [ - "FreeRTOSDebuggingHooks.c", - "FreeRTOSDebuggingHooks.h", - ] - - public_deps = [ "${nrf5_sdk_build_root}:nrf5_sdk" ] -} diff --git a/examples/platform/nrf528xx/app/support/CXXExceptionStubs.cpp b/examples/platform/nrf528xx/app/support/CXXExceptionStubs.cpp deleted file mode 100644 index 0f8795191330cf..00000000000000 --- a/examples/platform/nrf528xx/app/support/CXXExceptionStubs.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * 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 - * Stub implementations of the C++ ABI exception handling functions. - * - * These functions replace the standard C++ exception code from the system's - * C++ runtime library with stub implementations that simply abort. This - * reduces overall code size as well as eliminating some calls to malloc() - * that occur during global initialization (see the code in eh_alloc.cc). - * This provides significant memory savings on resource constrained devices - * that don't use exceptions. - * - */ - -#include - -extern "C" { - -void * __cxa_allocate_exception(size_t) -{ - abort(); -} - -void __cxa_free_exception(void *) -{ - abort(); -} - -void * __cxa_allocate_dependent_exception() -{ - abort(); -} - -void __cxa_free_dependent_exception(void *) -{ - abort(); -} - -void __cxa_throw(void *, void *, void (*)(void *)) -{ - abort(); -} - -void __cxa_rethrow() -{ - abort(); -} - -// void * __cxa_begin_catch(void *) -// { -// abort(); -// } - -// void __cxa_end_catch() -// { -// abort(); -// } - -// void * __cxa_get_exception_ptr(void *) -// { -// abort(); -// } -} diff --git a/examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.c b/examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.c deleted file mode 100644 index 7c34363aef8be3..00000000000000 --- a/examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.c +++ /dev/null @@ -1,29 +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. - */ - -#include "FreeRTOSDebuggingHooks.h" - -__attribute__((optimize("no-optimize-sibling-calls"))) void vApplicationStackOverflowHook(xTaskHandle pxTask, - signed char * pcTaskName) -{ - ASSERT(0); -} - -__attribute__((optimize("no-optimize-sibling-calls"))) void vApplicationMallocFailedHook(void) -{ - ASSERT(0); -} diff --git a/examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.h b/examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.h deleted file mode 100644 index e5ea6eb7aeb26a..00000000000000 --- a/examples/platform/nrf528xx/app/support/FreeRTOSDebuggingHooks.h +++ /dev/null @@ -1,34 +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. - */ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Called by FreeRTOS when the stack overflows. -void vApplicationStackOverflowHook(xTaskHandle pxTask, signed char * pcTaskName); - -// Called by FreeRTOS when malloc fails. -void vApplicationMallocFailedHook(void); - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport.c b/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport.c deleted file mode 100644 index 43ec16e65350d8..00000000000000 --- a/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * 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 - * Implementation of newlib's retargetable locking functions and global - * locks for use on FreeRTOS systems. - * - */ - -#include "FreeRTOS.h" -#include "semphr.h" -#include "task.h" -#include -#include - -struct __lock -{ - SemaphoreHandle_t semaphore; -}; - -/* - * Global mutex objects used by newlib. - */ - -struct __lock __lock___sinit_recursive_mutex; -struct __lock __lock___sfp_recursive_mutex; -struct __lock __lock___atexit_recursive_mutex; -struct __lock __lock___at_quick_exit_mutex; -struct __lock __lock___malloc_recursive_mutex; -struct __lock __lock___env_recursive_mutex; -struct __lock __lock___tz_mutex; -struct __lock __lock___dd_hash_mutex; -struct __lock __lock___arc4random_mutex; - -/** - * Global "constructor" function for initializing newlib mutexes at system start. - * - * This is called automatically at system start by the C runtime. - */ -__attribute__((constructor)) static void InitNewlibMutexes(void) -{ - __lock___sinit_recursive_mutex.semaphore = xSemaphoreCreateRecursiveMutex(); - __lock___sfp_recursive_mutex.semaphore = xSemaphoreCreateRecursiveMutex(); - __lock___atexit_recursive_mutex.semaphore = xSemaphoreCreateRecursiveMutex(); - __lock___at_quick_exit_mutex.semaphore = xSemaphoreCreateMutex(); - __lock___env_recursive_mutex.semaphore = xSemaphoreCreateRecursiveMutex(); - __lock___tz_mutex.semaphore = xSemaphoreCreateMutex(); - __lock___dd_hash_mutex.semaphore = xSemaphoreCreateMutex(); - __lock___arc4random_mutex.semaphore = xSemaphoreCreateMutex(); -} - -/* - * Overrides for newlib's retargetable locking functions. - */ - -void __retarget_lock_init(_LOCK_T * lock_ptr) -{ - _LOCK_T lock = malloc(sizeof(*lock)); - ASSERT(lock); - *lock_ptr = lock; - lock->semaphore = xSemaphoreCreateMutex(); -} - -void __retarget_lock_init_recursive(_LOCK_T * lock_ptr) -{ - _LOCK_T lock = malloc(sizeof(*lock)); - ASSERT(lock); - *lock_ptr = lock; - lock->semaphore = xSemaphoreCreateRecursiveMutex(); -} - -void __retarget_lock_close(_LOCK_T lock) -{ - vSemaphoreDelete(lock->semaphore); - free(lock); -} - -void __retarget_lock_close_recursive(_LOCK_T lock) -{ - vSemaphoreDelete(lock->semaphore); - free(lock); -} - -void __retarget_lock_acquire(_LOCK_T lock) -{ - TickType_t waitTicks = (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) ? 0 : portMAX_DELAY; - xSemaphoreTake(lock->semaphore, waitTicks); -} - -void __retarget_lock_acquire_recursive(_LOCK_T lock) -{ - TickType_t waitTicks = (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) ? 0 : portMAX_DELAY; - xSemaphoreTakeRecursive(lock->semaphore, waitTicks); -} - -int __retarget_lock_try_acquire(_LOCK_T lock) -{ - return xSemaphoreTake(lock->semaphore, 0) == pdTRUE ? 1 : 0; -} - -int __retarget_lock_try_acquire_recursive(_LOCK_T lock) -{ - return xSemaphoreTakeRecursive(lock->semaphore, 0) == pdTRUE ? 1 : 0; -} - -void __retarget_lock_release(_LOCK_T lock) -{ - xSemaphoreGive(lock->semaphore); -} - -void __retarget_lock_release_recursive(_LOCK_T lock) -{ - xSemaphoreGiveRecursive(lock->semaphore); -} - -/* - * Overrides for newlib's malloc locking functions. - * - * These are overridden specially to use critical sections rather than FreeRTOS semaphores - * to improve speed. - */ - -void __malloc_lock(struct _reent * r) -{ - taskENTER_CRITICAL(); -} - -void __malloc_unlock(struct _reent * r) -{ - taskEXIT_CRITICAL(); -} diff --git a/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.c b/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.c deleted file mode 100644 index 15652cf3950d93..00000000000000 --- a/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.c +++ /dev/null @@ -1,86 +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. - */ - -#include "FreeRTOSNewlibLockSupport_test.h" - -#include -#include -#include -#include -#include - -#ifndef __SINGLE_THREAD__ -__LOCK_INIT(static, test_lock); -__LOCK_INIT_RECURSIVE(static, test_lock_recursive); - -struct __lock -{ - SemaphoreHandle_t semaphore; -}; - -struct __lock __lock_test_lock; -struct __lock __lock_test_lock_recursive; - -__attribute__((constructor)) static void init_static_lock_test_mutexes(void) -{ - __lock_test_lock.semaphore = xSemaphoreCreateMutex(); - __lock_test_lock_recursive.semaphore = xSemaphoreCreateRecursiveMutex(); -} - -void freertos_newlib_lock_test() -{ - __lock_acquire(test_lock); - bool acquired = __lock_try_acquire(test_lock); - ASSERT(!acquired); - __lock_release(test_lock); - acquired = __lock_try_acquire(test_lock); - ASSERT(acquired); - __lock_release(test_lock); - - __lock_acquire_recursive(test_lock_recursive); - __lock_acquire_recursive(test_lock_recursive); - acquired = __lock_try_acquire_recursive(test_lock_recursive); - ASSERT(acquired); - __lock_release_recursive(test_lock_recursive); - __lock_release_recursive(test_lock_recursive); - __lock_release_recursive(test_lock_recursive); - - _LOCK_T dynamic_lock; - __lock_init(dynamic_lock); - __lock_acquire(dynamic_lock); - acquired = __lock_try_acquire(dynamic_lock); - ASSERT(!acquired); - __lock_release(dynamic_lock); - acquired = __lock_try_acquire(dynamic_lock); - ASSERT(acquired); - __lock_release(dynamic_lock); - __lock_close(dynamic_lock); - - _LOCK_T dynamic_lock_recursive; - __lock_init_recursive(dynamic_lock_recursive); - __lock_acquire_recursive(dynamic_lock_recursive); - acquired = __lock_try_acquire_recursive(dynamic_lock_recursive); - ASSERT(acquired); - __lock_release_recursive(dynamic_lock_recursive); - acquired = __lock_try_acquire_recursive(dynamic_lock_recursive); - ASSERT(acquired); - __lock_release_recursive(dynamic_lock_recursive); - __lock_close_recursive(dynamic_lock_recursive); -} -#else -void freertos_newlib_lock_test() {} -#endif diff --git a/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.h b/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.h deleted file mode 100644 index 2c3fd65d724ac9..00000000000000 --- a/examples/platform/nrf528xx/app/support/FreeRTOSNewlibLockSupport_test.h +++ /dev/null @@ -1,27 +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. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -// Run newlib FreeRTOS locking selftest. -void freertos_newlib_lock_test(); - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/examples/platform/nrf528xx/app/support/nRF5Sbrk.c b/examples/platform/nrf528xx/app/support/nRF5Sbrk.c deleted file mode 100644 index 5a332dc923edb5..00000000000000 --- a/examples/platform/nrf528xx/app/support/nRF5Sbrk.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * 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 - * Alternate implementation of _sbrk() for use with gcc on nRF5 platforms. - * - */ - -#include -#include - -extern void OnSBRKFail(char * heapBase, char * heapLimit, char * heapBreak, ptrdiff_t inc); - -extern char __HeapBase; -extern char __HeapLimit; - -char * __HeapBreak = NULL; - -/** - * Alternate implementation of _sbrk() for use with gcc on nRF5 platforms. - * - * The default implementation of _sbrk() that comes with the GCC ARM toolchain - * (based on the newlib C library) is ill suited for use on RTOS-based embedded - * systems. In particular, the heap size limit check makes assumptions about - * the relative ordering in memory of the stack and heap that don't always hold - * true when _sbrk() is called from an RTOS task. - * - * This implementation uses the __HeapBase and __HeapLimit definitions declared - * in the Nordic GCC startup code (e.g. see gcc_startup_nrf52840.S) to properly - * limit the max heap size to the configured value. - */ -void * _sbrk(ptrdiff_t inc) -{ - void * res; - - if (__HeapBreak == NULL) - { - __HeapBreak = &__HeapBase; - } - - if (inc < 0 ? (inc < (&__HeapBase - __HeapBreak)) : (inc > (&__HeapLimit - __HeapBreak))) - { - OnSBRKFail(&__HeapBase, &__HeapLimit, __HeapBreak, inc); - - errno = ENOMEM; - return (void *) -1; - } - - res = __HeapBreak; - - __HeapBreak += inc; - - return res; -} - -size_t GetHeapTotalSize(void) -{ - return (size_t)(&__HeapLimit - &__HeapBase); -} - -size_t GetHeapFreeSize(void) -{ - return (size_t)(&__HeapLimit - __HeapBreak); -} - -void __attribute__((weak)) OnSBRKFail(char * heapBase, char * heapLimit, char * heapBreak, ptrdiff_t inc) {} diff --git a/examples/platform/nrf528xx/args.gni b/examples/platform/nrf528xx/args.gni deleted file mode 100644 index 38069e96a2a212..00000000000000 --- a/examples/platform/nrf528xx/args.gni +++ /dev/null @@ -1,41 +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. - -import("//build_overrides/chip.gni") - -import("${chip_root}/src/platform/nRF5/args.gni") - -arm_arch = "armv7e-m" -arm_float_abi = "hard" -arm_cpu = "cortex-m4" -arm_fpu = "fpv4-sp-d16" - -openthread_project_core_config_file = "OpenThreadConfig.h" -openthread_core_config_deps = [] -openthread_core_config_deps = [ "${chip_root}/examples/platform/nrf528xx:openthread_core_config_nrf52840_chip_examples" ] - -chip_ble_project_config_include = "" -chip_device_project_config_include = "" -chip_project_config_include = "" -chip_inet_project_config_include = "" -chip_system_project_config_include = "" - -chip_system_config_provide_statistics = false -chip_inet_config_enable_raw_endpoint = false -chip_with_nlfaultinjection = true - -segger_rtt_buffer_size_up = 4096 -segger_rtt_max_num_up_buffers = 2 -segger_rtt_max_num_down_buffers = 2 -segger_rtt_mode_default = "SEGGER_RTT_MODE_NO_BLOCK_TRIM" diff --git a/examples/platform/nrf528xx/doc/images/nrf52840-dk.jpg b/examples/platform/nrf528xx/doc/images/nrf52840-dk.jpg deleted file mode 100755 index 0231be503b48640a95be79570e679de56fe914bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224065 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�UU0@|xN$$Ors~eFXgZ8>qmP;;_D4I-Z({fZVP*Vj3bx_6 zSXGTqd#Z)SvH(&y^XT2F(!?Osa`k*^3&58vQs`sgg4G#cxjxMd%Gy4g``QR`Eu{Bk z$UNepq|6;>Nicl>C@Cy8JlYQIPYPdT{e~$NWvkIQTzv5Qo@HxwQ*Hd+LwOSFC!ubU zmOq~>J;8-Y4E)#jS|a&)?d#f$Tosiq(1&qXmsF=(FZf~WwMdZW8&SrnZ86n3&ZMsE zEIZ=?+k?O8ov%~-vuClr&P+si>~e2_Y)8=j>?*v*H-AOvRSgOs4b|3QAKk9OJ*(;v zqjK6_h`TSu+tqGj0d-n=nv39p+C&M1yaTb=_8+A;RGZ25yZQLGeUwfc9@7?DN^D}e zBTe2*=hd`EV62Pe8jk*8UzU4)kmz*6VA-rYo;krDet}^U`4a@@<=-QF+|4u!^>Q5S z25TuT+cZY$d_{o&Q?`!5xRf-zX{Z3-YEqwNZM;~$HGyVij%W1A=HpKHe6=FuRvg=x zyQfJmCh`-dJrynDtVUU?w102uDse}~F}6xFMDWYMiS-#oV2t=Q>9HuU@o-yP%{p^uI`N`5W1>ag z`qD$PsV>D`>ciJF8r3#cqhj0aN@8xNzb&yc&;LE~9BK{BQfb;2{`|Huk5Z0q zzo3My0f@ajRjKGnNvxx#O(Df-ot^qN6;dJ+O>f-{A8*yiWJl)f zB44C|^vdCIhMCN}=$JSBsEGA+>GOD(@2M=UTk6J@Yta~wTzQXt742Fuct<YQ+{w_J!Um7LI5W{KU~5s z6}AKF?&)6c0GXS5IEVc@16SVn<;BR!Dj%l^m zsG4}gu#Udc;B5LU!`?QP-PSzi!OO3Pt|_Qh=59c*wukKTJozA{>6xpUdwR2L?CoeM`Uu}yj|N<#bj@{)1J zM!lSkdL0(7kIMC^U%MpL>l+GqhwW(Jys;rD&Kanv2%r;84_l{?E2j!2@3#xLiW|B) zs*MP1CcKgttj#({xO=H=Z*j(7HP3kT1bl)_zuuwz@f54=Ga4TI6&cw#-wHD_WK-cw@@2Qa;<>Bm1NU zgbj+8VH-Q4h<$J+JeE5JcJ?eX>6^3t6K7dr#Peg11Hr*NvbAsCNK+z4P|?MqSWxln zU#gmjkk5`sTG=l@j4ZSq77h(&dP7w9hd&ICDwah!u?gfF&Gw2iCg|k$r!8>Y`IY;k zHfm{Mx)m9+9Hsx(9|ym;5KpPE{6hf$ z7;06aTM1FWO5}_gI+MF$p2^t(6w&29D5=QPAnWOm2f0Hw1^<@j!MX*po^6;{b)8&I zgQc8$@=QO@P)%G*!YE^Z3Brf)_;O-viPQf`R%vRc`=VL15)Val`wFllf+%+e!Ts-TR}+D0Wk?A)8&@lBIW^KLYb7elu_%sYod#j1fX;yD9 zq}8-O3#|Q->c0$f@PFcD4UQ9PaP$uiFRkVP@6F8=4y;U!?FK?!oAU zU&l2&ILZ2C;Qw_1QG0>njs>4S->K?pQ6(Ee&QaI9Y+!LxzY1&i(8fbjw|sJT|JnZ< zcRuBtrWQy^*(cee4}47X0Uydp?-UO+`lIC@Ok961c8O0Ld$Jm%_R zu2WoTx8Lg0J2}7MjOi+wNz`5tZVsgJc^*J!uXnp9-r3ii?GLza-@v%|r9wEj=lt`1 zZad}*uv_iEm$kLIBX@m+MuH&-J%ps9uT&bbxy2kaPf<4gMUETS2iK19obr|&)9lvl zln;|Uc{LWsc>fm!Dj`=W@A4hwo6YqXP+-&fUzbM(j?NZnZKV1Aj>OQ4?rp0VyCKrv zw{EIvts4)_4aoJq%D=X{dI;QND{e*sd#Xis4WUPJv`fuz+aYLmn-!)h8tm+uoJ-V^wueTp1wO~`eD(d@;h`p~cp zBm*K4=t1*T@7&mFIOv|M-LSPiy)ezhv&ifQ8;VByusBjy83jrX@{M)5K3b?V>6Ia2 zv^&6w#d&oj22kMXeRGFoggy%A2z4cS?cXwRdQ*CEDzbU;=W3CW~d!SPGsWBeQ$^SE9v$>ghp6>89pPc3Lv@yNr|GZbiRIrS&7P zfkNVoUmUu*+!892Ip>zT1UF-Zx2D^gW3hoWRTx8)YtgExy1Pr5B9pu}Oegp5@Fp&6 zA3JV0T1@IFYfL&y#=7vRzjKr$gXP0Z*R;%F)Swd3$})0C@l1K6JW#GXLPv2BPfg!R z%C-b%Z6xPR-Dne5a++nk6}%Gz0N8!$PfkYjCz^D!cG1fK2>BW!J99F&IncrRXk0-U zO*$E(t~9XmMsNvM7vOu$z_8&e?IOXN6Zdbu>UrA;DVvjyEI1*pumSOa|d@z%TA5N^UwW! z=e6Fd#0O`pq&IcCk6Fbpm~Rjyu$-KXPja9Gm=)jMZDotIa6cUU&w(6@^RS(N>>KQuOn^Cb ztG{y~=h$Ac_~=ltGU=p#Q!XvXJ)U???XW@5X$5cGhBUJ6!}AMSBABg06rcfq7}t=- zHI?9{;82v5QU^)uts2h-si!!BPjt*k4N?+Vi2GQ8g6qDLuASO`TKRI;<#F3|rHbU- zX;agYS=3Ur381dD;~>?O^mmTqw@3>ZX#?Uv7&DH>XT$3rN2)ne?FDjf{)RkoX5MrD zt&@p!`QjmmR3)nX{@ZP#0_XQl#zq2F``L;J~2-cWOz zhxRFN3Z8I>*wO8DrQ%XusM)PNM;SQCr4?M1Xj9sSrgQ=wDkEGmE^dvZgp`O?>!7)b`DD+2# zkk349<-dEVcUwn(mK<>lR*}kmLu!5}^A`;Xb9OVWX*UPNpg*Kk!LFfzY$=0f`*;Lb zP>Kr(Krc(e2}$U{Hx&H_?BN|Z4NlM9d-Q|2jj|8- znu|^6#OHJ8&tt?rN+xu5RngFLqBU`brlwe9ZBVPNkc-0^XA~3d?&3~&u+E1ks5YuJkeWPV>YuQ zQ26Cu{}~x8vZ0^Z@>$>}19NgL*-1ygRMSQSfPjKgQYkWj(}slzFlBDLE>~5KC`$AR zqv>B{m@h+Jfs?#pbSQKuRul1-n}Hr}Z++qGEA0tcG%~HLZmX|12|NmWZvJ*e zKq?5DY8CTO<{#^IksP=Z>%$(R{916nUgBo|-bTSjuy|WvOiXrYYO2*$$G13i@PCKC zo88ajFGYpp$11xYEWjIX`FU=IPGlCB6^}YMpPVo{XQ4;yp+-l0?p)5JFVwo}N0e_@ zc1WzSrZPY36HqE#vR4h()gP|{4SxHnXeyZMN4xF1kX-%Z_gyYk8g+68l2Ev$WnBC* zIm{gGC}Z^?*zZu;ff-Lik&1Iqb@3rPb&WPEb80Hi%qyD#;`|r;+D-WBxIjrV0CpDw zLb2bb=m3zvE<$&QeS@NIo+@(1{7t+Y<5D#INHcYhVKYidaMGeWH25w1#UGjvKYJ(B zPkorZWd%-IV!`I_&y6M1264gN#Wo9gg%uYUom0^EzmjXjFT=yundW)D#gondk-XSz zib*?}_Uw3s9CO{kT4Axxv%&=qtyZMWUr9VtQTdp$fy^-1}#y%o}#sYmTApu_^3;#3dxyhooQw2Y-Li*UF5o_&TF&^wyz3Nm)z-r9%E1%XsOXY+wkUdfCidzJB6`Hsh*F zxF_d;Sf6#?aORg4#>X1q)f+SW3C0Esuj3Ov6{LbWBRFHK_%ygo&IA{t}-`^dh( z4;ArOg#_m=ZiR8aTIu^!0NOjIR#hRAI>oNMfj05&1p8yMg=a1d%8PyO)n13QwoCN~ z^L76t@#-A@if&J6GmFF~DFw+7 zieK{nTW&#e6LkKY>6X0RVhC^c+q!A!hy*jfd0%iFjswy(5K4+}hquBCSimCqFMSo& z#UJT)ai_{tiO=6G%d8d!3uIojGn<`@*^j5_tFSX=noOSF=JupRaKBuZ3$GM69nqP}`kl=_Luhk*RFuUOrxOMf$a{at4(-RiHGFS0pZ z7UuE_K5JnwU*Gael}O$e|86yGxSAZaJ8T&S`w zG+waCGgO+FFsVHyopyS-9BJ4S^w6``z|rWEN#n58LyG(DgW6iy_%LOdWyjH490wHf z?#&>XFvo}AqvX)ct<%KhuqFs%smBr582`R5bT8yf1q*)mpWs7zCljNmE_WSa6Jr0c zfV}2@$;JY*D7#~MTpQ{+7;QF8I+^=s#&N- z{RBVnd~cgbWn+p);)HdZ2~)QZa>?1|X+a#AlMa2*C^hKnlAq`g~~_GU6!8U;UQdj#<^dt9UH!59(F?_3k` zbi(oJX#b_?e%uX$fBNOb;k}?5eny;zu&GGWPu>>0|B+;@{WEj?)-~3L;ntiwZQdp;BC!CZCv*5_12V1 zz7))}%5f28_WC;Cp99Mj6f<2~|fdpra0^KMZ`l35?V|8sCAv`z&ESrpQ39#Aqv-X6wS{ z2ex5SmseixMc=*suL$(VNt$V2hZ72DLtedg)9=|KMkD2Vy!dGlG2lfQhGH2mnG}&j z(4k9u<{|rtxL5O|#)NvePTWg!FMihk!eQpnZiZ(2=YGt|OUD=J(_wS;D0w=6bc+;0 zxD!bek4nGS;#}Y}FIP{vy=%%y;EILspHM%xHGNWVl|~D)V33n|6lps8>1}6~B{D@>M+W2g|)f z_q1|V5+1LqwY`g~;ZjI^p2v?&bror>m@LNZ==82u(%X)IpMDBu2cy|z{Q&)5!=mA*X#U4*RU;fbx*I` zl(li{%k*fZ^@kL#$?|87&JT_47-iz^pFBl!-roGfvyC&)0{S=IvsRp$vq)9f? zljt1Yo@J*OX4BLPEL@z;n_ljQJU-n#;QJD?G_u50TN$?dwS9H@?v*%^WtIAgzZ!ld z&7z1nf$AKa+tI#~clSg1B`ybRks6$ z37_+Sh}sWnP!Ri|->d7;`!+ugq){?@@An0ZP-RM8XoE*iLz>4j78sn^F)v3y4%~KLGSu z+v^8@Y~(u=K7sq|Mz^b`oZs*rk0mjB4%f`MDLhh+A_R?7@h<*{riPGoy4rLq(g#3H$3Rrscv!DW0C|FS$?)o|%NZ;~UZXDk58buhm5@M+ZyG`QO-pxM}yBk=#>9 zl-yM@+$YH*QwkG7?S+~H4TVS2&l9qtHCZXu2wA~=q9y^lI-yuFuv%Qu!s822N)2Uy zVC{Kr-nNWmWdb@)>=heY(TKyv7ci4qriT69b!+9!$PsF$44k_b&0GjnZqO^s+iJaFxe8c4nvmTz!4AfLoD z%AI^(1D$2Kcj4Z^!TGig&9UeXeb-jasehlnBwWT^u}QrMU|NfjIJMcaZl8 zVX^LdBA|HOjo@GCyCABlwIvP-4wy6Gmoy34ka0Vo%&8B zIJ28!H+`Zh7S&D-cI1x*3k=Q$z$AmhPui)7$^10KxMAojb@sV_U#j$F`{Ho=v%c=d0qvT$7_88MU)-9z`TTUYiGSaVf_ zX6J@ynj1Pq#Nu<7*zsOr7;2z^@MCi%Ut%8{)to(aTIwOYcYWeCd0qL)HEGX)Z}zgX zcZqb79iwAOwIPSnbN46F{D{qEj^DYIpOS7f@nxjm+M45z;l~jjF>DcaUWf%-$&u>S z0~*efiN3m~JY>94^kiiH9o1&0i28&-?rR0+dSD2pwV~s1A79B4qkb))SqO7Qu89J8 z$e?q$9y)j_O^LjptQ*@^G4-;K+J=`)LoXnegLdMTms|T>pd`^3yF5qTnNH!EPO-Ri zCPUXkAn#$hGYfXb1_brF6Ya2_bLugLJA(FeI5ASC+OZOmKX2A2_>cD})ayePo4#)! zE(9b7C=r5c=%QX!;FCiA=~h|z)$u_Qj1!LB#GoOsBA?~XB|7{~ z8fJ$l7UV>+?UxVZTWzj8#7%na{IEuc@snKn%=kaJ6x&&PFeb{x!qm(9n25^umz&`4 zDfRT0iNI*wwr8Vm(au8Un!OVZyNQQ7L&=g`6aIStr^)=@XphFGk@$-6u9Nj1Q7)U< z-ec%EHQ7Yo!_VO3zQ+iHZ(qu3(EHp!yCgM)nwBtm(;4{ zU_Fq}V>#^%Ox#sUEJ21><;l}KbXV^yh&GqvSIkWlEesgvyI1POXo8Vq?L_UOJdon~ zAIa4-vHy{LQEGYbFIBuHE{P1UL)ZzLKrZZ+U0G{g9l6>n-#k@*R;v+Ld+KO=D;;vtW4*CzYQIIi#B7T$P#kf1IXd>NeL`0%{edDh%hXtD+I!kipluR)=zC&R zT>R&Dk7;A6Qu;%g`#va?VN)NHy@GI>mNyskw2PXWXq}m^^0lU}4nH01Ocj>*JMP4H zuk_8HLq^#Cf%SWLzQ^;jR>O230nK*!QqJE3uMk&AbnZ=lT5q{>Eo(5dC&CN8d^*T0 zVIRmb=Ff&{mDswGnGj70_%iywUQ*{G;Us&=)gSQHJ((fh5}3mO3;Q!t%4#=B_$)Bh zMt=!`GHTV*H@*ZeSS^rOcB{GT@!(`a={@suBScE>{bPjQsr{U?p{~ZVR{nv?v|hEH zls}Z2%n>fQKv6YoYzYhL+|Z>jO(?h?J^o>R25#J zut{dBsOC(p?xq_dmzVqyvp1a+%e;=USIYcr|19}YIKvz_=~EVLQzNo0yjznrkZ^P!smtEiOQhz%#2J@QG! zFzwwRIV74abkq;>y-}!z+^aH%RmHbo9Wz) zu{~&e1Vq4D(z{tWP;*Q9mbpG(`gVF4;qe(6(W-<1tfFtR?aZ8MDb=?^r^*I#v3Rn^ zCaAqtl@Dbs=bU4Cw3+`KV#2C4x%w|3BOQbp&6bu=^!tz(RW0o@Pr}z#KTL5?>^X5w z@_s>@Bi?v>jWu_?AIy7b>`N8q_xjg{if+-`?)7x8jLAG4E@@wyyj$WYSgcZAP&h2E znxL_yE_2d!GIe2M;2~r|(D|8_J;1TYQ_Dv`Qu(0h`}rS(I0Z47$Tz(;9RJfYe>2Ai zz#q>+&KFPdS<2eqsfWx9qdGGE>hKg1z@zK6JcjC0Qwlyw! z{irKv0EY;RNUnNmzH@ju0jb(Poe7x+alRw#lNb2S&-ARHtAT;chTPrUJl^2)15a+Y z-QGEm^R;8fdBBe7l)bZho8EiCV5S(kPGDKDaJ*I95@x2+7DeaSX}<~1yAC?5^K(Rv$ZML*y8ZG=i72X-s`w!(PLaVc#}Z4}O~ zdh689R6Zvlqbu^+Kj3~p_3C+ua7fD`71e@o1B?s&-d;XO@A3n`g_fohtu?@iTGNP zAifmed$n51)YDWJTV~fLNOaHGiIaw>VHah!38O!r*G+bsaCiR%8|ET&t#ctej;`Pt z-KL%iBk9GMs+{qRsCIoYAWPl`6BSwiWCwK})upde<(Jsg0k_+p#EFkDYrLedFz8LRHDz^UWNuUP-e`(9)Lr`T z(I|I%lDXbY(M%z%M|*G+4L4D}rAl!>aHNhgjlM;-{PX9F8L9OIl}hEQG)0YMnoJq* z$W+~@PYPDIP%N)wX~7@2n|^I;m4a$NSYTEed0+g}aqQ3hd!8*4d;A|>yazCKT`7#O z63Dv`7<`=j<~XC;3Bvf1a_bVqV%ml04fZ^d$#W~DNAn9moH#g3;tGcSXxnn*23`vf z;8@iqgMN~Oy1%xE%Z9SmI90A_P!pj_c$g_CzOQgKO;K~EOjMTKCtGu@mio!gMd{3} zdGpK$I=^Nz2VEn5pWdUDL!q)6F(Q?cW~A8^yE||e&v*iy zZ!hLtct>KIn((!Yt$*nrs(rPZ=5^+V`}9|8x6&Q6Y0T`En}_Vr**fi&Wy7J+Xb1i7R(T9Zd{0vTP%Ltyp^nlm4TTY!VK#6@^`#b@IycCC<9TeL zGU)QN_nBi+H}9^KOqjw4Lm2ssdTZQret%(Vs< z+9|C8ETL#fKJ;U~0ve=Yh0g0V4s^8?3li&K8VH@1}5~F2Qs+Jt(ZgdDpxQD|u70Z% zMdsr6@>$!dq$2~)J&c}pqtTd3K#^U`Jdy0y{=ZR@(1i^KC*R{uMVf@c4G4)9F0|oH zGc+zX0~_r2fwMH=Y-h$oUMSGc9$0RW_i&G#lkkR>*6G@^(!=S~%g}^Y zt%+-ot9Fez8d&9u%}hmK5Gu6}bf2VS@Ns;IA5huq+tCN=6AnemzN7~YOO)M}J)0q; za!oDgMlLEqH$e6Pb6Z*&h+0xwt-u2+m;n56Wp0sIRnz4SU;+EXHvA3gyA2wlAW>JW zyNhjS{y&P&Ga#w=Z{wDgm8NAma#pS!XqkIv{ngaO+_@_=MM6bIaaWdmr5Tv%G%cqdt#N z6Up-|8RF!p<@E`xt#3W((^l_aHJu(XRWXCD)=jsOi*@=#v7`U7xO_e1nADuq^<8`? z%r60^t&!GqFEZcx^pjyYXV6-NBMUsE>n^JlYY7LF5vrzHlfeB%v=O?1A#&Xbc^W0~>Ei<8o zfcp@(B{uQTe)uZk2ftW2gcfKCKAr<78v(;F`-EGf@!D)}2|z_CBeW~`$ubm4LUrzhrmwWBq!*=bRi)_O7edFS)%v##l zK4EHeVZq0pDA(QB9QXQ4gl)ffg(Q6f`UZ16V%|HhV)*y%b1aJ57tC%h;LK)5TgFWf z!K-!uuDnH85H}$T|GZ!66tJrG-t*D$g|BaK;t@t(YQNqdw*a*@uWDW!Pc2aE`}03k z0<(Ni3gN?P#+sIf7rVKkuFOs*Y0Z!SW407`^t0YvgFbE!1g(N~M*~K}Ft#qRW6W`! z7{^hhPay{f`KO{^f~z)FSBo(5!k5c}S@HUP7&`Qjf8&fu=iT-xqoejDrtaQ%v#*jZ zHAv)x^T%r)=7@K5zN#F43GW_kcWfIO|0cTVv{6YB_9ZGA?P(7wsQZ|`e!2^bJP6*2W1r5dnfETJ;1cZxu4Vz8h6$4xSbZQe~yFmo;oXvH6`h* z`Ddd|JH@}!>Smu4YFW-*A4i-rSS#&Ur&$xOjZ29qKjggVbxAl#y${7>x*4l(mh;z3 zIA%Q|Kqx@y{XvYnKr6j&=E#8%I>WR=xU4T91m%{eC>ipfOW8g1AxK;(!LOYhE6j9{ z44&SGOX7PQZ(_Ktd&({1HFaZ%()k? zetxA_03s=4+TIaO{VpM%`?6o{oOi0Hw_EmVuqOc|{LYaJmAR#zG;%9ntrb8wJmr_4 zi+f{w8ZE-n~aUTRyVar4xoX7mb6gfI`7zNFv)B7 zayS!KQXL)L=FZG?fuF6Vt)AYcxx{uktW8!s^xwD&dhRV|@>B7Q7BqCpp@iQ6_nRk) zSM8DavH1z=IFS7J2bST2Tx~pv)DZy(yF@j+g+ws%`IC+=E2TQaP|Er0rqSPjf5Zox z8pD_EtdZ{U+$SwkeQmy0KHnf9tJn;~jkL-Wei;W}0esn=3Qf^7pLxRuR#;hsU8ukgn@joz`7 zYo|M%;xw};n74>$75FeB0XE^5{50}uEe@mkh`Jg#wn?U1(X8g?VV#Pzr^?+&hz;98M0I4!5J64GkGHmqWLT|=@A z1|i40Y_k8y!a3uiT4$TeD9|58%mWDkWJ7Jv_G}!2mD-b^xS2jJE{3wP)u?!Y5E zHJn!Cdz^V_MFqm7)%$wxWKr#XlTC-7#st^@Dar`|zlV8p)4}l{6Dz&Lxa^sD&B{1? zr?v#IBD|JzCCH|YtJyA$yd7O@Z+3h~dpo7_^iSl6NApJ+(5;%7J>GdAvW_rM~ z1(sMLB0JC+Wn__P{5S4inN5OKu>nuIhv_&*6cdnpLco|eVlaNuN|yPR=Bdcb86bR# zETK%skDkH|Ff7^}++bRMRlCZCoO0sb7h0HG>vh3U6$XCZJ62#0e{4v$Q(D!!5>(_e zApdpVjN4^x#NPAJsWzW4TK)mYgjzi5VuaiF#5%Gr4AZWZm?rqV^ruVK(IZi zoe>#>MaKn|&!xuzU}^v@_s$vCoO!ADawr1#ymb>!4m;P_ob5JUcPyj%1SWVC1n`1f zlY?PsZ-f8THV(ymfBO^pEN9ba_Ai)^Z&Eq?`JHYuN_re+pj1YFvDRUbB&=8Z z#VVc0Hm1dB6lGH`_UV~#c3NuOH}b~1mh$tvmL(Q@>&(+#8Ay%DboJ-)ohvm?R2?4N zl6M&R!6-Y@2vx2f^BcDp5$5a!xm@xr|wvVm4 z;Ou5r<5p^Jrbfi4V?FJ~_AHxLnz%(FZ$N5?yHHgp;JXQl)Zl!2dP=9*T|Jtxev9X< z^7rGg7BUc2_;fccIH7>g-n`)Qm#-9`y%l^E*Tk;Qa|57G|B=y7?^G*LBkD4y*rxMk zX>YBJZ!5Qt>ErAlpCpXS3zuX4Kr?&u+dBWNNWBZ!rIQ$owP9aBOR#N@&MPTakFM^wbe-hn5e@Wqd>6$ER za^?D@oXkV=Y?XmGXkLS~?lT+EAp1NQRPU&x!8Gdj5t9Y{hM`tG!H^1W5 z@y2S;$xmbStU{-O6(aIuYLtwcdpvyLD*D*OJ$$rf ze-qs_wYp8o3DX&WQcb|D7F~CI?(#+cWlcut{8G>T2a|9nFfoRqTgb3{PUFp?{EzA# zyP3$GiM^%;)v;VWyYOlES&2 zX6w3g*aunr5F%|kPpF`=2(k=8>k4YxZe1WVg<`@i(yk5D*|nuX=*e2y=`Penc-wQL z()dr6Yb!L4}BO_EFyUiAtrNz|dHElRgCQU|}oObI^V=LeZYIOR}KZcIw9Q zm4(fpaBg>I|EZOfBw}u;Za?~cvlv=EN{ z+Z8Pb%BDHMD^#`AGf*SCD}r@u+A~`P%hQTh#wMZXLQdY`*abZl1+EHt=u7QImQ4yZQ1on=mAH7uP1@zx4xr}YVCnfhslo*b!#@)29_9UF}* zC0dxYn2Fr3!7oxz+hEYwyN?U{Q8Acb21OlPOOcy{N|R3IzQZ?Eh$Bv* zI*p!mVz!3Ml=Gl?X4}h%ALQJcHGdf(QXgmuL}7A~{1SR4M*R}fM`}%yKmIL@{Xi7c zYW`TQk0Ax18HR)WG9Y=7x_J7Xu{6l~wx2i>Tvk>`FKwmHcC?5BPcl!14Bab-3kF|G z#T}cTA;6?x(Ktq)>mX4~AuS8v1BxhJ`{0o1yVUu6((aaqd-VKs&a7aCy9}nl$IGy# zu6ng$VXA-T_vK$v7Jj2ThK=BdBk!0ReQOTRppuxcy;t9B2dxJNz4}w4$ou?!dLl zE6Wr2qrelpK>7X%aggE0_vag-fTt{BQ4)@+vYxk}!WYEQ<@3}C5gi4>5|ZexooRzB zeKT!JR^`b!e&h{R7Q1Eh0<*_+A|H70?m1MpOHlmoc zQUj0IAKhQQ-6SH6+qW8rIsEe9v|szZ{j3&~2MK>c481a+998Y~_9Rlgy&zv#$w+`e16kA!VyLM*wz3=G$sxy1iEwSn}7_24Ffvl)mo5V5jc(Xw-d- zcr)N4AS_B&i25|!V-_Rci;?SqT+d=U>zY4<(;rBsW4%TA9KCjS~_@209G${hsQ z`pv53dEbS9XdHlf=|!m3d_Yb(S+`61o$nA1W4f%wX)0B7(}551+qOqs-CX1o<87nF z|3!riYS_&J>punDw4qOU%m0Y`-{YO%zkIlKtr-8YbRpPieC?GNj*VzmjZVo4%w*@J zRMPb>0hdqBJQT)u|6i{_)cY$RPsPCy32$u3Y%R8K zplBL*hh=?|FN6flKWS|;DJ#1* zZtq-hXV_bH(z&-=Uke(9-I?4QGcHX(Nfa`yN;J~z8S(+`_Uaro1vI!QPvgftgRQCv zZ^)+oA$At@w75X?ge*INa(p0g8i8^p>&9p}r%($hd>_2F_AganLxwrl4sS%bM=g!a z+Ixz+x0!tXvRx}%)Gwa7(~U%gQCkV>>Ihjz);v>JQ0PMN(?nyG^ZdFHoEa17?q&px`IXV>vK z0(v&)>3hAr9Dto;y?eBnD}eqx&$dpWGg^_(h z6O){vioNxGu26vJMkTe9k{`=-&=kYGV`pwR{bcy@G`kznY!c^=Or6=$wj0iOlknyQ zOq2Gb|5z+W-w4!wI(GT?6^7RBQf)LyzV%_(ZVWT~vDuBfP7!_I?cU2gNOH!WU+jIE zZ(jXXX`({%llt*R`a4d0e8rUnCr)b8}0Vh^5 zJ{)dLJT4|V=NP8NQR_ZxL5`e4!Q=ZboS;BrHgAp}N)HAV&raOT`q<2zPI!|y?}Pz6 zJHhd1O0?L37y=NH(ghQnoh}TZIt}vOXS!e5dqug!g+etLeiUKNuFsRl3f1+aTACFr zlP+|T8Yr0*Z>sorMPm|la22G1EWd)Zcj|(vWHzQ}^&al*>})NYH)VS}=TrDP%|7O{ zg$sGQuqv13Y$s@xYaF{=RX&`JRkH)YkUVnz6GCd2tQf61}o*SY& zD!{zEg&H`s!r@Xwl!vF4W3GC!2}#`w1(cETDMW*GJ=4Q--T8|uitf=)&fv_{klQ%g|SqOg|BZ-!?KG|s38^Q$jD)f*0~v~I=UUIP0r))>$IFC z%{Z@(u4hlj0cw%xmF%Hpk(6*qh5RjzkCtoK90w$(Prn2HC_Wc7)fpbvf>JHb8Ga#d zWcF>Il}5?7a?n8KjQzBHVS#aNqnn0TR!E39M9XJb%UkZJBk(f`5ZLK-U zKUQ!*QiH#losaHGW}j%yqv;xr%~O+N{U}UOhA2gwn2gf zCl#-JS3odCnAL2Yx#hwZ#J>(^sBZSj#x+ zzCD=@8Z^th3tR&lA8OlU@{t@kjAQ--=6r~2x_(A!z9_eL{YH5Kc)LjlNC;Jsic&H$ zf^F)W$6FI#H8fV)R3X$V{C|06P743e>Bc=XNWkLhFjOc}u=LClcZXrN6R2p}lpvM# zhzG!A4MinAD(B;8+3`7}&3R8FiNmaS>r$c9bhT3Qk_=*Telph6NT;J(z?1$$8)=5hIGZu{M_(cJKv zwFBn|8t6e3eYpp1td`bEpHzrZ9*8&Ee2H(?)s05gLu5^Aj+~A&Yi)`flaeC}`wRO# zpY^H6JBat-{au0bNc*hx@BDQFo+>rzIPgs4VoUBc&el}HA`={yjg}rr%~QQm^v@wD zBddu=a<63}12>IHK0`e%py`sg+tDT+2fM;jowM8(7nMA`%8;DXYI~!G)KJ59hucmY^3Pr^^*5`c?9wjnW%MXVvH6 zBnj4A535W6#aK(m6s8o|ECg57FkdeQc%?6)dPUQY23a8Cg9)iPv7b>!uAD2&Q0^M( z^EbAf^=v@)(2$&%g?sTH2hGK-BC1i4gwkJ4UzlY@mmjLFU@HM%D=yV2b}gz|k;J}t zrt-i4%&ckhIOz3zPu92}7%U-CiJEpt`L|jAO*Bq)D)X&_h-TKcO;=Jv0wcr4*V?FA zE-uc>6-dgU^B;%Rn)UmwmBl0@Psneb3_q<0b(3WLTf`qzCHXt}W@^5>^o`LIKWYfQ zol!^agd#fxv5C-tZ2mh07e}^AqDvNjREgLUlOk-9da;Ac8HZRbEWk$CQ z?5xuZ&QIDrytvuvrd;r;vzI?RL)Nn3qHRe`TxzAc#IS9KvWC3(MrrB?+{lX0c#nj0 zO@f$!MVa)YbOi|m&MC~iN^Vic^i;)Id4%6H&-5^B6N%GX zW0@BdqPFy9!lft?ACAKc^(dmOjJB@Ud!z1`7T0D3$I6xC?=1ShVxsiG?>W}gQfDAF zy;cRi6-e8WTLiJJR4bwRTfWe`hF&(n2ivsXU>j)3O@~bLjKf}|9+E+tlO?WaWgoZ- zGXu_Qo4zv>nn&GA3R*7dSb?rUf$G0l(^Arg!dSMa0$6V@1TPu+>pA)lJ#h{>=zYjP z{Ib8DxuE%7_nG28)32^=H2>kA(R|79fq`CAVrbfSDbqFK;DQ=RQr|nS2AX+&6~3Yn zn)^N_64BBz{Nmz#66XVa=FMwAuj?`m0j_E+2vo}FpoLet-&mlLAE2Mj^m?`LBPO=a z111A;B>%uQzU@kM--Fj2JZjHc4F42DcVAq8$My6CpL(~W&sT$~r_b%PxU=e}oJ*2c z^-)t}Q(H~`5}A-TF06e-dG|!feHK8F=kyy2+S6Lzc`;1_LjVW2eV_@S9hh}!3CCR| zHSJhdAr2$N88NAIxx!PbTFe^GxrNUU-mg66cn~GWrI(xQ7PF;3Me98G>Srsu7qr6m3MDRDX;u(c z7m^B1`^74T`rdVyO&I8B_U2dbW7y5@UT9=eVJ?ltT3=K@{p(l%0Bgc>(nT$y<@NTt z*V$p15eO-BTKPDC8Tt{SCpyDI^=oQXJ75-%%G}4_5>dVIOKU#Ce@joSc=@LAf|{5* zIih*CXms3*t}(k<)+RvfVI4155u9g+9xgWw-8-+Bn6KX6rwKpD z%u`pxf62tCd64-mfL`lV*ElJkxjx!-3E)jk2w&9Ne$}551GalDd7ts zBNt%P#BmdtDNSjj1?{)cmEMm^NU4TWNe1^gpY(>+FZhx8JBs74^|b*XY9R{hZqj?z zwk;Yzu_U*A@C^(LNWp6%*wnV*XL-+s1*vV4lKfJi^o28H+}Xz4hN3xR01S3(duIEY z1r}2c-kq&z`$9Ayg6>8HrXop9& z_yXQB1q5=5zjoig>i2B-!xQm$8ua#Gw_Y!^3b(ZH<=D|p!0V-Td3Av^q|~u;V!u<} zI7H)bIdJA7)0Oj>W51VAn5x%4mvmy7*`;Ce>whgB#~0U|A_7tC;VYQwS{K<(WaBl( zg)?qO^R9XK{fe4UuIl%j%K$|4 z<@6T_Ag4wyZB|{lemLS$(HGSh9Ee9rEIMEJ*AvpV$JI-+1cOdjZuZH3zGtSlNyvA6 zaoJer&?5s~dk8vc8v*vi;xk(U@rNsFS1-&o^eS3qEGNKv&9tM{2TcwF-ZQV}OW%iV zOb9i8wn3gfbdvx?L&tMxDVx0gkxOmRfcB6K;M=PTG) ziFxn3&xWw5sY#VAYySjZ>JSf;Zc+v#BL*XE?k;$}m5OHb+CTd9TT#(hr~cQu>j>x& zG`E)d6pBi3^m(hZgcdFf(bj@^m~B672?;w)+=-wMC)YUyn-uCoO~u>WpI_g7I-fC@ z|M)MoeIZyR`bMg)NyO47%zby$d*_v}NyPZ!Xz2k7aUc%%zBFakFgi zz3(D%N)XW=)nSLf8t!36m$Mv4DwdfEN9Bvy7ENP~H$^no!gjgsS0F6^_QI}>cl8qi z9KXGLlD?YD&rq|MB@>JY=N4S0f0^u&sgyb5_mQ2Q%aiKHD4gMkZL245>M}L}3+8~y zKB(8GSM~W!m9FF^6diF=94;GbOJfFx#}#l(@Dq5z;7 z$jwOI(#UUD8hJ@s9ym1;U7HFjH8uhotxQ>hS{>FhNR5l87{Atgj2dd%yl~oTzK{~v zRk%$r`?)6kJ{OmR{gk~~Wmvh(THq+-H@~uM%zRVT2Z(A{qkivuS1?b{3APm#qKy8O z*7Gl~d_B0(e!u4+ve|@UdSSqXAjNED4S<$S%OhX9YA+mI)6*tgclcMWD1+TKD7%68 z1_(rx9A?yM63sTjMQP-JuqG1+x5Uc5Ft24`JwXnp-+E0uWz65Lwrcz>WrF9A{l~+w zjEw}6RLn=tphRUQ^7&j}5_Wyc;R}*=@G+pfV*)jq6K}}77o`}7%;5hy@TN6|SSfS0 zlTc!8lfB;6_$sVaB-4 zEDmw?DGvlVb_#P3EMRmB4qsbsdzpGTZ#jw}3a+nwC*6fS z8rxQJeu@s(B3{~vxTx#N6{iu9f?|X_xf|e={$sf^s5~6wRWbL@hyt+G!@X{K0>I`> zxMJG!Hx!vt2OrTEKRqC0B6MKOO)7NZ^*p_er6wi%4kmB5n7ktC3uyNYf0g^7t5$xi zW|05&)xO=kZ}k6Kebz}m$~!^%7ZM?A6z zPf!zHnC)vT!HH8vJrHuN!1Nf$jw9xtwFV3dEn!BmuK|5O-X2;v-I@Hc2=c3p+MECg zSD?WfNlBsyv$h4ajgm)NgT=c#V1N<^9a1I{Sa6UW+lKw)a^?7XDcC+Ub22bV%iImU zhPX_H{SABk5dVTEg~)2$P7Cse3I*rZk>n{2cwF!3zIE$_xW@t5@87^&KFNE&E>eoX zeb8-&25B@CeVy&5e~V@6RzJZRYRShhVE3RVS|%YOkPsyU$XbwpMDgkE@F4;3?mW$h zZR29iRLSzH;X)4$HQN6~?zhm+L0x8^J4{WuT%5<$P)`u(^V7)0^sCB?gc2XO=FdhP zWAlen8?N)-mvm#BUsif-&ns{+IB#a-w*QA^LSZ4HvDWgTmSqn1>yx}0u4IrF`qi%f zIOp&+`-hEo=A1v0POV(yn1xR=8J-mA*U+$X@R1}@Bo~*NG0!gT>l@+>^6PIhwNvY> z&F(T}v*a<-fIB{-hxb}SVd_B<`tHbP9h%5WxeShV;)= zRHtY((Z*Sv5k_63cQLI5t^rD4u;^fum}6~mzO!Kp=G1auJN>{ikHd=hL4|8&=#!>r zxGnFB3W)!vfrEqkZSP!2xELegR4@`6BHWyVJaR*CxVUEpEbVe-$dvwctP*##efRK8 zzyOr8P{(ks1dGUwl8M*t>%$btocYBPqb(!lFEYLpkFC9ko9q>zlz$I{i&nD~lrx4( zy|-^g$;RKb_x{oTCaLIl-*r9?E-7qx*Cm-RL1SflozP1AS`n)<>ke=?5< zr3O|D^9o{oSvw=ZPcwHopB2(B*(BU{ruj=-qJd~N@lv4qVzQFd(ck(Z857s8d}_Yu zGq@#1H=&uYJoFI*G>7w#H3v*%iZ?f(*^wqaYd~w&dY)P1yzz}k8?%$>GfXUIoB`<8 z!HMP^+r~bPeq;QUhY{I*%0=iomg;ssm-f`<+B75hH)V*K;&d`JZ=o*8r+O0K;N0W3 zZR!%%RKD;IE%1qZKu~%qRlZ>ulPdK3h-f3cB@OY5(y%6Qvm>T;qmYp zhPa07OjZY}UYqJDWskKFc?r|(KldMtkB2BGzuk-t{_;4ClgZ%Vgl%&(+-*kzO355> zSt}fD(Be{g)K?W0R}6{s^k2T z_BEBUWxy6VnauvIz)2=UefdTSKH=M3gT;7;?`|8*e=M)JV|6$gWtFoaQJzq9x4BL3 zuE#{g(yT@OD9q`xZM;R2ll(xBhI1Z_0(R2g1F3q_RkO=&C!bagqg;{|dqaL@t(i?e z1~PDnGflN)d)`+z9HXgHjBP`u-8a(=S;6Q50G z^`|G6N%DyoPki^*UN}*{Z&vXxr6o!dkQ)Um>FO3sHLuDGcvK%ja3vPby)xxsrZQQL zlq?Vd$rhLRs)oD&3Co)s@MiW4C_g`TqO$cd^~C&y1)S7qMd$-saG$A&l8(ri|5#pt z4^(IFIb5ss6o_~1aV=eC3VwV&yikv<>OSxbQ*>{Riub1GtI593L>EI*F8`AUy^|S9 zc|{N6?S-)p|8xzgjE!H!{swiw1VsLf$RJ+l;nxoy0W@maU(vo5eG` z5}F^Qb>BB%0#g(?R#Y{5PEoR8jSB3ywMMTR$d4)gLhuqePxf(BTYYscKF%}C`A!5E zY1K>#;Ss;48X zmoTmn#`o9aN~S?jLH*$XSu`G_D;O$=(}IAgq+Y-2b(_X*W?`~UdZYNMSQ~-V4R9}q zM|Nea~mdu!UfltSKSXQpwLz3bS^4V~h!40Vo(zd(rcGf<1?# zv9Ojm{Ch@tn4r~98)+UXM@SdrjB)Rot3@&*NrD-Db?Z*DcDHioKcoo{$N8HE)4MvtIjBQPna+HK1!1Xl}eQ(d%uv%}HT6&#^MKveWD`yz?-`o9);s(!Pc2)i4((GHh@pUl0NkpX@m~ zt>nytg4~gw0+Ly!AOTx?(x)Pw_Z9r}DMiuF8iVNkp3`%TzWLJ5w{pF>?Zn!WCjIMLK7MPg`-+BSa}jBmGu_{#v^41O znEGO8`5dG;c~km#ut^3;O2)Egu_iUpu=Cl+pYZI@x&KzhDcPRT684ZJ>1inlpJJB8 zY|3E+CF1Og3r6*w(y&0NF>#Ioqt25RKI)P$;Eo@VH3#DJu0NqINB8EtQq=wPYxA!= zf(5j6L?gQk+4N1uba*HyrO!hf}4 z_98AF->2PS=Evy`lz4z{C$5KDMkZFmD%V=MqI>L{JX2=Zq>JP$xuX5I0baj7?;M!c zLmmUiU>|D`#K3I8W1_B`Xp{(mR+~{08rFbs)~Co0bLf{b{5mGtm_3$!35&SOJts*) zMwT-^n_@U}tgA~;T|In_Cz+nJkuIMZDsgiabo>X)b8KU`sg+4z$F&<<|J}B<*K9WaNBsLec~osFmw$s0GI*RNX^ySS>6u?IWPUflSBdL<5zNFX>iJ z4QbATVU%Q!L8^DhESpl>rS;(L9*AfUs~N!`5D0|0cb$qEHa3n`Dm&y1Z^9aTFmDlj zI3-Pp?$c!8sK9?L&+EsKgx8+{VGqcLo1$|NAbpoS+p~FJM`$(0$@7#C=f52l&htTA zr0a><6;XDN8NQ^`u<$jL&C7Vp5Ol!Wup?rv&z#1Y_QSJrt4_Q85JRO#2sGO%bPtM{ z$~q9NTNUB%PA&MT8uY03M7R2S#>gv%BimMIKokJS9N# zEt5Lu-!m>z#d<{KX&aRkGb}?&pIU*0fGBPJYuRSWgKeGbs}M9S@wzQ7FDuG_xOR~2 zee>}J6xn3nP33#Z>Y?@wwla}-QLa33cK8+4veWplBjByFqpgZ8H_d9yGY;*xDJ1|C z&r`QFp302$sZIS$_jtKV`L616?egBwtsBLqisncS|8%hnD>DZn{lCp}0v8G4c>C=x z7cSM9Q{iLD@qI{07oUz2!Mj}0a!i~cYGNuwF+Zt1KbBN6qSVh@@*m5^p3j8gn7w}+ zkbOv?evVPti*_&ON*>)itvknwWQ%VVb6yWtO$s%b;mq!H$@IPo7LjNik*nC!dR)3X zBgTvb;|n7@ch;W4-|XmKTQ~TR#d1_x^ddZ~(`VLW{C2ZK4`aD&5*4duHm?v9aj}&N zW_fvhk9x8{6wCbnjdA7wSZ=@#DC1_hv11nrpvvghvBb2lPK_KaV z*@>Ag(+2}RZ>$gkNVZ20N-XTHlTre_w1}yV=3@r({Sah%keK1M`-A5!uF#I#6bsqg z7ZNL;YixIP%bg*scfeY5>nsg90u~EHH=n7&F1v-Hw5`o!EyP@-+SSUMKKev`wO~Qt zxiW+_=z5PSSx~zj1;nRC>B?&+pMziTI(-oBKv3Qm28CbxIlAX$XoG1Yp!bbjiTh|R zIXdEIbtd7lQ1GW6F~!W($BXxPiFHq11`c*}orLNXDwE3wk79bw6E&>Cz(S;&p23ZK zduz7EB(Smn60QlGR+o|Wa^01Nq5d?IR>{pJU+mFWSCz?d2j*H}PyY3)jy7T5%))nj z51E2*{&}$T-Epku$p?J z%E=k#+XhEroF^wowsKPGC38-OCIn^8eBRlK^@8Wr`0|t7a2`{dCgn=rP+I|G+=>xFE^%f$@bW)~ z-VdVWSIr8mTDMTQGKxudcAlv{sP*8?RGOz`*OT#mk5JtUb)~DV!sFt2@v5{x162&U zzAHjryyocW0*%qcw@Tj~*qt%%7D;z*ESe7G*>yIS7!<gYF>#sfJY05voq&NO$z?D-#}HKm500Lymd=ik-B8aB&nM-8Zd7k#tEy`2Fg3Bf zGsKJEW5vvnZ4ljrNxtr3e!XwU4{Ar=P~D^U(43S3TO8VJdh&1{=rC<*From{X6tIq z%qI_CShh~jqTZZ{@z>*&gu}2%xdE~4s@RjlehD4+vKUQZzWjtE?b}W|Ew`nS=v`xH{#u* zKe?*d$8r9hVk-HLVWw_T1StQyhlnuK^4Io}d3bf7i{P&70$hYgI3^a<(t0Z6l&9U_ z);wRr-DOs_2aKUq?Elnex!U2ee?|J965ehqkzlC@U0edEL#-E15c?AfdzxH=p`HY6 zM&z@RP}>4z^>Yxei^8tSWF?$sByn+p4f}C#vbqju>fDMw56=(P`O$MOJ`E6fTSn0t zr<*Xq6&_hq^a7eDLla1yjmDyCsO!u_l(~)o?%1%>$!=}O$=PFad(zcZ*L>8uV-6>N z+BaU%Ok7GL&Kfo`og84aSmce8S3*$!IC-y+r52sI;tZW&oUy!l^QQ9M!g-l=N`af2 z(b`a>vYWBucLPt6iAS*YN2{IbH=G&@Y7d~M(?``tJBTyPfLstYxhwxN{P8oI0TU;B zDb$S?V%f;7Do~KmLc`-bXRcDi5)-~FI5XBX>f&^3yp-|YsPr%3!{&QAvBzbxa)aeF zXP{KP`3Oea(s>+nlxX`j|5?scDk`q|y6{#3x#jID{my~q7~pi=)jRm@i^NSzL*^3u zP4t_fPd(LN^282FcFnj5u*;<3QAi(OSLY0K%WQ2_i4A)+)9WPI(fBgcfjL2^DcLjq zQ)|J<>OLgskY4wec+bVzULFafv+Jko4AXzo0|DUX7pttW?CuR&*Ea8G zUhBeEiJke?{!0qVR8*Px`VG-hv&2(&M%bKg)G2>_Urj`(HLb4qa36b+=zR=8n-}sKHgZEiFcfVpDedKc@28o;Ecx zA}B541D(#SS-m?T=9zO#S*^1lZF0WLlf7WpW708+IhAHSaYOu`47d{#4^YqV7Xdh4 zxRXuKP4zD&=3TaR#LB2S`N;(O*2MWb9JSK>Nn^-(qzx1~%%k8cFsANAHdV@rFK!`~ z6%um}MOevgF$gj0;bT;vmTD&TPG@aaRr6?PS^c%^VsaxJf-%n*tvS!QL32-7$=mS) z9GzU7dD?sb%&i2wl(JOrZagYSyuOD0^Y~=_RdH^tFS}^28&x+>DgTBiul;FO#CPY( z2_2L~(s!@^oU;k5L9G9=^tJTlRz-QpZx&{n{aa&mz7oX%jA%)J4HM|Gd8JO9Rh zzUu3G`Og_OmJf!%A4;jIKPq3DQB4mLl}*5a3NfHElvk{z$ErafHrw-fy)w*td$;Z1 z$zotc(K@f&hPT|dSpCy~^gvLcXUeDBd_f9dIeuyNI7Lake%AD1`Op4cjHw3Eq^Q0n z;ZAhpryu`IkoDqzA{j8n^YQIX8`Vjk2C+M>t{B?u+Uqr|+Y)7YrM)wAWom3PHFrw; zZi&0uScM8Ls;lkg$x@uA8izk^W7YOF_wX<#OB~{??ti4d_}+1Xv_=`xQg~hSztpF< z>puSZ@nq?KLGyR3N^{HHbZz95Uf?}b1(0}Jf`V*ugYxTX+%)NxbXTUayiFuXT|3AX z7Ko$U;?@Z#EDSD6J|Fx6`Rs8B^()OKN(rrUWJO&{o;SN_7!no;E@u?&dEh-K_XK#l zZFdCW^damqHAEQ&1K_ zsB4t?c*--rrFcnIM6XW`IP+s0vhQBf&Hr9-8Z6loZn%1cWP$q_0dj1kfU1}Let zq>_@OMhK%zQba%)A)`l*+$aZ(z2Eu%g`M;4+|PYq_w~zubTyw0#sJ8nO2V<^WDMC( zvyo&seY9fqdeo$+K~gcyU0%U;@NzmJpWFGE4iAzNc@ef#uCF5+t-PEn6zWuvcD2Am z0@{0rDXCw=HtQbD zgR*V|yl3im<5<`0$UUPec}O@-P&Su~lEJ5H)7m~tHTA2o-r&wB-n6CYbxqbKTTG7*n&=x498&;iv-TJXC(ApSpQ+Ss1%lyX7Df7smz0I(tc=l6V6XD|@`ujR z<9Nh^u55~8B(kKBku$$YB!5*ympU1-ohz?wwePuFo*!2+V@~V+I?nR&T3Gz_TrB@P zRObr6%8mGfd)T}d>4*V{H$Aa)EBVuiNfsHGLGua*y6WFOK$0ao4h6x#LzpV-0{fkI zR>rJ0}UhaWzS6cU%{K-#r$kCVXu{x*@sy_x`wd7;K6S~7l%3S8FONTJG zdK7O>vB#DN=FLj(MiJV?%p=@T*|09F^ZG9Y{YM(_KFS0ZKds_o=24-puX|X4Y_C~2 zwo1CF(wsk?&$Q2C^H(+X_nd|Xe00jCog<~0KkAHDUET2s)UhiF$B0ug)42wb_J3}K z%HTwseq3BR<(JLkmod2Hk?=C7&}aCv5>;n}!K2?=Jm?u1clRX4z8VOkpjU=`7}#ay zuCdmTdfFf=fF!9ThVZ^PTUjmz?M~s`qMkUV5<`&#%KZjCFP8cIH<9;3e|6KpV}(cs zUdS~>8(cXS{^IghCBaB`7^$>gWs=2z0w{QR-zN_%|M+pNOqbJ0`*H<7(^l7UbaL(T zLegF8nwg0kQ>RlO9}Q5DtD3Y^H3S^z_t+b3vp}c+=-!kXADYB^a;!3CBD)6jWSl+6s zF2@@xcUv6dwRhhZ;P_Td6P!_7=VLyYK%rMv%0CEQCZpOyyn)%h& z>$E4F9*UdIH2jN&DY}0~U);aEy~6)lU^{+YiLV2k_^@x0!QiprZ-<5#IV!JjCO+Po zeC4Sn7&dHv=KwJA{PENbIPQGurb0#Y$-e(VFYt`%!c0O+B3$mIV7(*1;i#Np=yi6( z*_nT^-Ip6;baX68hLWRgPmWT~5!BJZi;G$7Y5{C2-kr;v0qYD5yttoPpZ>nvRizgE zK3YdNJX_1qynI1v`0>iVfu`q^&C5XY%lm6q&SODrJCj=-IWhHJaTB{(vu{TsB#zal ztK!KsW$`Rt@t#_?%Xuq4x4L9wS$df4x%yakk@Pu1wF#D%9LxjDpw;)p*yKddC!Oo# z`(mO$ON_uqmkqprucsnG(i;r;TTPsf&{5Zj#i*K*+ zz6*R2yGY*2G6(&=vo0XzFUWNgW&GXkiePd)!FO+#O|8vSW?(ssr1fm&O@V0qACnQ) zfGp1d$K>3>d)a9j@`1q!*n<1iE?YwuY}BShvT9%K9hxuRYxecK%d)eM^i#aCZyzl3 z&pp)Cdi;=XCu`qpSh?ToRgMABL>4}T(WfqV4R^I{l&xhNO#Rs*5!JvRkOT@*(0d!|o6YeWa%j z=&jc{Fa5S!Q~xuT(D%7U{$MnJmLqr$xpFXl*&|||ftMe-4&o2A&q`wD+IYPZYG`{| zHYY38Yii-sb9u_q(Jfxbu;1&PyJ{?~N}K-cTM^GbC0-!LzP5)f%`{-{xPOj){eCL( zk(Qys*TWG$Ei2!kYP!xo&!7;QeuK-%0=unKS_hj?8?LzxGh-V3A6LY|RWZBtV#o$F5(vcY+G4las;8dEAyid{~Or3`sSF4gSce<~$++dGl&XwKR@7HZbePfsSlROmh#fo4tz~I#&K5ajfqa)fs z>?N>0D}iQ4JV&M6D+tt`@=Dj!3O28(Ojf>w3 z-Gub-bLva$UCJ&f!63q=CjR?V=0;5%BSo;DWIWtTEA>j!th1lC{dlG2N*bfZF|60q z(OY0JJ%)A%*=;a^GAuwnCbhaR?QH_$hpLyRg2P@Jh>%o`E z?Rf-*zHXP_gxm~!rg8l6`m<3N_qsVS+{b^rs#X0GcIYS4Ti@MXZ9pnXZKu$w0&`8+ zzx6@y5x~Y&2Z zT<*7&%n0o##pBQvYpY4?$>e~d-&FB~_Gv#)$s-;=y{UMeLVqDk^L3WHcXkiBxa9@J zRd%11oYdMD6mD`mq!u#BJ7ss$M&_Hoi28$ zTL@@>3mp>V2na5{#ob!&^UvT*PZhueE+bVYzVf1E$%}~1fjOn7xGA8@aq@-tc zkk#EjY`HSnaLjfMXVc0_>})$aq4cRw^`ls{jtb|O{bu7-TV!`qW!7FsrmK*d?tGHRyN|b3t*nD=AzsPlp4v9kkBb9OJlR}R-)>W z?0Zhr*QISRQkBERsFFfJ*2rZ%_QyH+m5-i)$0#+}#pzeOTC z!7QUxc$Jp@Qcdwj;)2CAg}#qpF!HQdWe1yOemei9;1U^Jirzf+p*5{J;m;7<`s;t{ z%o?LzUuN{pul`4;fQ8_1E?1aPATV<7d#Z3L{4^~>G@?Q-&TpwQ;c_-%hFQS0v7s?T zTs2T!HO5tU?AQz!U%TX$Ki4bY(#^Z|R!R@}`p314BBKZ_4S~`heTJUe7-~1Q*VwVl zZE;8DiAG%X1R3VT2FmShHjRs-(&}IC?pC_3#9!&{{k1Q0`nT3u>GYQ8>7UK$G{vn? zm=C4z;m}^={B@3~jGn&M^K7T#n;33qR=g%_#)JD1(SJykvc_m7XWOw@r$!TG(VkIO zlfM}5xmtRMzU_^a!Wr|wHp$>7N`v3oLnKh51T#{imhB>fAC03-MXK`9J&+q484pN4 z3o}Q0GL>^9Wy~Vo&q?9+3F!Hmfns$;pglpnQSi*H{Fc6F?a&sDhf;MWHAj6;fjKyU zQ}a=eNFfnEJbDQ{hy`XhDr|8`us2{TvQmzZEl79ZkVt)+!4SD4d_JEnyz?jW)FGqq z$J}=>f5mPAW}4jQX>MfjJ*p`AO>GFIt8dixh%fjAo4ftddoDoMt(|WS2g~7!3CxVM zCQcsj6Q}AAW`~NW<$V1VYM#hJgOu&dERpn&NmbwXq8=>$NB4350-3$z>jEVad2wco zCOuxHAnhOGU-FsVA*l<0zv}f9=OiNgmRlm9*~#I6NNgX0bTBA$`>h4&U$Q(ty6fe- zZiH1$@=CVO`16coi@;%L zvtlsSHrGKd*pvdTUZ5!ULYTJe0&gw_c0?=AgUC_6;x-T?yBn0`f3ahEwWF;9{^+8g z#D`ATb>JZcM39(BLx*~)bKqVTF!2s$<)+juOWOD0`{K~V^mO{pdB(a%;EEiMDH``t z-BHxRnH#lCNZ-_}8+Sjtjm0^(w>Bn?@%V(w!jIu@`DcN1vxcX=A!i~^ISQn`UIBKU zJjKpzu}MZXw?3y``8oEkt$!a{Ze7PyqPp*`R>}v7>}en+x3PvS#58jZ29e=qHM?n+ zG#ev56e56s;{3!ni1$p)V_+N{i zs8iImX{}!o$-f6fvhS?E$kj4+)?hc=&Dy3s4;?hW1}Kz?_sAQuG*C zt774tB|Ha0l3blnu9)3oetB%i>Kw35de$(Chi7Du)9y?z=qHhn^h#VY`8Yz1Cxp1L zJx4I4XXV>s2OL|ieD2FbJl%<#{G!0EzlUe%)&A~Z)8ANCo*=M0KcyM47epD8 z)hFAGQ#rg?(*292%F9At6FJ=N{emFN3*EVwthNNM%h|C~Fp{p9iZT(t^L&vOKK|gl z`piRZ^JloTMhGqn%HzLl3`~YqeTO`7+Z#@Mt(yWZkN=tav;sS7p{YO zDdOD?*PW$H`+2=|>IL``dUPN5y(%{e4<=dz3%0I`sF?N=k7+_NQ6TrpMX} zFg__=+JL57#c9f&I0$XZH3?t&uCOWY6B84qDCgti))106hs-3fCVVBQ19}o5M=Lrl zU9sa*t2Ci}Ymb#kXQW(tJ zR2kY?-HUW_#cpkNm-hPkUCJrlUk{b<;6#~Hk{y>Iw=9v%&&b2*O6Pgu@q(mdfXTeJ z-ra4W-3wHd-Y2e1-JSE7e#@P8Gh=G>?#t=v7$v=z{nVPDlk6BF(oWv3VgHIhY8&oYVw`)j zQx_y_o-?CU7vFUMWvysz-!kd5i{|BU@*fwidh}=GzL&Mzm-!=fuX{nWfHv&KJWJ#5 zpGj3#(BzC1QSJcK(g?IVV^r0Lg6JMYX0xbor4gl3RcU6WW~r9gp9MP}H(Lqo#vP6Z zH*{%ZQnnw-uzv8vQIu?+6F+~_6z!(;hX9F5UqJmU*)uPe@C?xOqa|}=vDuFZT{Bu? zeI~?Xvm1~o`w5ZusY=Jm{CX8kWuASRvms^X>?uXMi(4QL^%#6xqkJ=$weAaT$b%qh zMVs6@Gw*T!GcnocSBI-4U}0+tzU+#>he`&H{oP`dDw+((t2mtJ?@{1OdrU~bu8g%W zWPv5Wh@-s^;9Cgy>u>r1A7)#sl+}7q@B>m3kpypE@#Ww+&XML$|6rfADSj1n7w%B? z)NNNddSsjROpaoI97d_apbRNtjxXKM#Arjo!L^lqR%7>3ip$cx7MAtZazUD0FQU6# zZ+4pzrP>IM`R^T#zsrQv;NLtHDG!H zdYyBRl3k$}xFiWCoUZF~YlP>B9=IOy%t^Lte66g7gA`AnB24DF3djtRhgVvSi-=hBqPX#_u85SX&6xTNsb$qh_PPK|khf&R!T6S(}v0#ee z%|S=$Q7FeHHFZ6$4|A|Ty~TRBps-(08Ztza_j8vM{vW}t-w>qU6Y?#+ch2Pd-`xgJ zAUF5}bR_8OGq>cyq{;psylZQ^Zw+T>L!_FW`lRqrVDw({yP{yY^aIAM8N*#udVeH` zqwRs{pu>G#wuVPB?hDDI`)30}K4;ty!-*=M2`a0ediZjuvA1xYE!TUw=gkQ{BY3@~ z!biyepWxdS9ZqVB1cRK@@L(<+h_!qxpbt#|GMFu_Z4m*fIdM)tdI-Ikp?lqi3g!)d z4cvxNrasI@kDEQM{i6eN!yvWh-NbgD4Ha}BqYV^i4xG9oL%844S+;Y?O{963N>M>B ztFCvTzDl4TV(+$%KXlg-e59T_YXx2HsQBbxCfxjMZtZ`0T!!>20XV-!iDN zv2F}BML6HhIK9oSQVch#D=Ev+^B-MJe3gSjRWV8ih#8MV85ROQtU}vMZ6xy#60Q1W z#M6uQW*K>-i#1^;&6&nwCN0S1XXMLYmi!&CnL7J(*ugffZoDG!d5KL2Uj<;3vrfpB zLjit@p#DOjVjRlUYiY=^%POZ}8Fo8#q=#F6{X_7?vCUHi-zzoUc`aNHmt-B%JLujq zq^`GIsO{3<9gU^E3-E(Y6-a0K!bRk1cXx(gl#5TBx|Q9>dHzDRg36u4PMSCy1d>MKm6z@36>FJ5~YG;|TW#M2TU&cFae& zCtEcNDN#NA!la{|T1>xxrIW9T9WkS?g0Qx>*G;>ZV`FbbzSJLsQuowvuMu7y(G*nZ z#SJdQI3g`R_q8V$D0Q)gpQKoincg*-uGB0Vx)P|l(3}G8%DEO^;|4@zSwT}T?TDF$ zjh1w0YYZm6ZCTTYed&A9pJ@qJJvJx%ZO5^Haz}4You+r~#RNn}jzm&*$|;roXYQR~ zISy_tmX_x(xq|-@^(5$dzia-?(8cx}V|6={(rc6MYl;GRg?Zt{Dgj_K$1av8M5UwX z5I$pEf@P_O9bp!YlpxpAje36R(SpD&8Ar9b@Q|6XrEp*4>|l2m=d`~n4p}mBx`A>{ zb-n@yRNeDr)D42Z==ZBd&fr@>{0rkrs~(VFwwouM5CxJfN3f4JZ{+Yal4gl7`96hN zCCz-F%8_blu0`nEYm;3vaw0G@8=eR~5^FdL?ti9=9PC%|24pxWx8}&~GQg02d#(;;tft{H^5FlotgzqkFs3I4;+aie>pyAIDe@Dcb+(Sl>AUxW`6v(2NL^$rABlGKDt-@!wYvno1Gw)O za|FMU8b0{Ul*&Vxi8xB=n!Z=xykJZ(9yP^2W=Rab8cV!k`Nzt5~7^I)cBN+3IBX>3g?IMqymq!`W{dq0vO;~By@16r9zT)`QHrubL z&a z{H>bwdI~7s>U8iUFp^Yu5PM?t>iC$tz%-;be1H06U)H}N+yV3--4l`*e4u~ra%j`RB3Np+%fO6>K#J=!RFpzWgox* zD+N|ITez(e-Wq)$uc{Na%}1H5+3i!8CYIGbYVQ`LX3wlqaxAhAZinZWkDcbQwc2d< zrKF1Omm07Q3F>-_2kKJ9_$Mtmm&#rsa8<_R7QGIa_Er+RSLMVfo)<}I1O)U+!3{DJ zRJsl{J#@33qi^)6jP{shEA8vXCa2^MfrY1%`)JY=Z+^F`vA>6xIlr$nyaInTJ3mb{ z9=6w(8z3cB$xO0slYjlVd$*}U+f*zoRoVlY3F zqw_yHPJ8m-UgnVQW4w8|_XZZiGz%^z%*h(pPhzU>bObqf;ktA9CMD$q=VZ02$1#%L z`X)BNm($HBU(<^t)t=R1>}xNVbJBdKB-MDdJ4JI`3< z-tL{W*VWb4wK;3MdnO$niB^`Dc*~#~?`-h!h%Rm$bN6hUcfZOZaHpq@9Jj-AS$o`PwQ_ODn$Yc5IDiVXB?2#<2cx-W)h@oRH^|D3(y zf30T)P%E?A6uQ#8d0qu##NW#w8lfXGgJM3n@`O@xJFb3HuE04L{F!ZaSeK=?Dv7W4 z^MJYMpUlscXWX!P`h)BH`@awG{6|+VlzOGh$XGY_^%o|KlX~>iAeQd_d3h|U9=(Wg z=RlAsJmzVPZCYKWWj2aYRc@}k`7QOW>AJE!tXK_@j*wz0U9(-5(0lHGLqsf}Br>-o zYPD7i#S8iT*@`RMY6!+PKFa#%!mYzs-&6SrzKbbBVN^@}6|)yQVt+1%FiPDHEluk~ z3zZHSi0K-yMW;(7+a9{*N)$9BEOze`R`vJC4W#r^r(5L3ZHaCf#4=y=&7ftH$#GUK zMU~XwN4rg$3b(JOL=kK>2cdwZiN70GpTTq0HHnpVYo3+N7q=VZWzUB`ZpLq37XV+t zY#LizE~tavu*@7oNs*z)ISS`rTaA~uhS<)QBD(B=%+fHQY_>gu?(FOwKw9R;xPiDT zkd8g}Hl(2X?5er!r#rzv@14n0ljt%$Gs8#5aRr#TJ{n zSj8Rs5=1)Q;fNOgrhbBIHqUK$1?gzgKnhOvDcYE_YHN#cDuD+JsLU-j)-^W0uXGa~ zmv1xJ^asxg;dIZ_cit0PLimwYT?=%@REUi*?NpxnNai&Lynyk`ZkfAiYN6ys*`S6xhYDOfrnj9~Hv2-&J=@ zKWIx`t@?0yZtz1D9xxd}uwgJBJ!)axkundAxxeeaC-=EH$x;~i8ouU8gg9cnmTsdz zpv;#cu>skYADv~Uu_9g)6Is=77Cz%6Y#^@|`ka)K9Ny$Gc%`iUAUZa!+V!W{Lqk(?wzqS; zslm+@2g`-)D^2WwjsBXTzIDiAXW&vWr&DP>YiB#_c_z?Ov|pP4iZ_o57N*4XDxPM~ zSKtv93M%|5r#`<_s{R})RrtI_RA_j)=XbjttDvKHtrlz=Vyqh{ymt_~H6(r6MU_o} z5MrM9}O?S@3vb(Xb*q)SsT1~YQ35;dSX<@YeM<38G!b%K zajsV-%;~ReI*!M-slN8WC&+#$BjTuhc5d^=^!YcC>DO6GgCsMzCqh6819qr=%tpJS|AF%SSPNBc;c^J7j>x&o z*m5ba@(nqx z#zqil7FSPrQlrTICi}IUi#*RvOPm22_dNcfJKdMDs+dT-N^vYiaZ{Sk)R0vgZYYzaNF1 zykjKQdohUwNoYN{b#;0}+GSb&Ge^zLR0v#g&>$UK%E8%JnBFymDub%YXNiqEk8|#6mI<+L%cWc8m@3!A*1ik7Bi>PZJJ<&d(pVRma{uQrkbF#F}U8b zE3gAUbEb$)ElOc7n&F4PkTo}Fo{ym(e6=Q8g(t!&q1|Rc!`Zcv9hvt*jt*5;n*k0(sZ^_?)}*@P&Fika#dl-0_kS&Q z@Bi9&l^FZ>ZCA3&8kHvl6A|=H$w2kGkOr3+gLS>Wd zbOfN;_MC`)FcGV~BX`ntUW`#j3=NK*c~7p7=GKn%#c?cY^)SOsY267u4-wqLyPsaF z{wv7t`BAW`p+oO#af4o=BldZt9@;@c)>`oo+9&?nVbw>VaPf{=xQYm1s-{B7nyDUn z-FZm6iU$==L)+<+on6*xHRLi%BBdXYtgMm_c#l#yH zFqB*dy>lAVi}t4441(y#H{TK^hhntuzglV#@2j|Je`yw!{qu@sbD8Db$ZNwa(B$2OhEW~r=s#NmK0V*|1f&^cJ}`HLyG#DdGP3IRYY;T9TUa8Kg_TZ z2h$>pM%Qh)6vbHLwkus6+9%}$>Cs#5_gmSQA9s8KrrBTH^u4-lIVYv0-ee&@Ar^8w zSU~~+f7@3pjGfq-OjyDQ80K1#qdvOUZN-_>ZVX-f37U5vgTcymls-NT9!_A*Vt?bm zldmHhb11mPWTyCkc9)}^;>p-S(Q=a%s*k2=i^lT|nO!YPFqc+&BielCEn8!;DmW;U z`b$&M9ka}|pT-u+H`Wcs#FfL6*h;ySaN#dUpgW!i2Ts{wH?t!Da-pIFe}0(Qgs8HC z_r}wqUNy%DmYTpux1t~4n4T$`XtzCm_6As2t%^KsW9*0A1{l)olt{^2&VNTyra1Y` z?;?%f9c-H_lTjXoAr8Z_?L$7f1SwIyJ1F+)j02g%2k{rfXfI6scMYvJnNeoK9kCZy9sN5)$hnL z>0R6s`_}u?h8w5*yzHf2Et(5&JNi8TWN}FuEA1)vc2dl`64U|Hjk9`GTsoCfN_`Yz zIwA$r(C7=08-t;w{s!!wThV@nVEem5@PnP^kn6M?c3WOfr*BH|>{xq(KFi;K#}9*C zB{1?_ax-81*7aI5R8?o-uX8nl9O>H!W)Q6VB?erL^Nk;uWqyaMd-ch_yQ(IegghJ; zKei^0$lJOiZRBi|u*+F=yQx;7Eu& zFYsW-{uuX;$+WoJI95DrO^G_}UQD3gLiA@uCKp&cmoF~Fo9!{@QiaoPFVsu`(p`53 zgv!uvE8gvWNRcyX#Gy=wIXz0A?-64!u2s#U3YmY<-7NCHWQ&awqn!bSohy~4*o&Du z5mtvFzOoTwq~an)R`|7?;mq9HXd3T-bjVc!M+531G1cSw#`r4cT1r8n7{<%QnT$Pg zM;!R#VC^u)v&wIp=YOwjO@-yCB(W|flomN!jEl1=^VSS-sST@Sy{J;+9A*$FhkPHI z(OMMf)92?i@1lWg##S?XGNQsSXA-JJA2%lV23YkA&%a08jl4a*+*T^V*6Zia5qX4p zVPmPsH&;7I&mmxvt^RA^mHLBj=5YT0q-pwiPXjGm7Q}<6m7!g`x%? zZ3EaG^K?pSPP#aQj=kzvPAe72F>qb5O6;^U3SO1nCp z^!z7$8gkkFp-n$Jl|iu$Lf5ZyEz{3`tEhthyOi?c(B;#g^(tFUBz=c%vru{Eli6-% z`>xmv@v7B7_&XP$&$$L^Ri4g}{^_}ptN!i^L&w(we7_;{&f|dJf4z$7 zCfvPa*f;5L#dB)qecq3B8b`@6&bqRC=yEIR)=j zKN;mb9;OpqXu@k?e;qJGW)R zvR2qU1CBO51_bX#b_zY5m0j3;^yIs1H=J`r;h~q~bA3CR)*1={1A$=qJY_V~Uk&*a=;}ugQ-f*|!FSu{_&*h?ztcYZcW}+R;~tN;o2c@B zeO9?S`f1AMM6yx1b#}665L+yCEu|12E64+MM0vhhSEQZd=Z`k`X*+L@qWwxh4%ghvDfN@}AiAT0A-w$& zRiBc*+@{{YPX)(0ChdL4Ti4HPw5qUt;+dK0_L94-8Z%^X5_;dQQt0}^cgbJ5j`v1y zdUuGTOwLQekEn=NvQI|>)v->d5`RW)@+v zy&K|PDB{G$+3LL1wa=)3YvHf%E8$|R8v|tGbd-V0LFeZ~pIQHx24Y5Ny#=?56AUl< zJWu_`(@GXOhuc0T`0*@jSgnb(N?ntyQ(0Vt!|eiy14xzJZ$oyAOvhK&y858?m_}GX zdc!fTPYSkf6lHyixpl^XuW-d$(!U3>3UL?@0BPZ`9PYMXA=~svV3`F7m$4Nw(i~1S zzP1+9d=qJGrbquPlI+u_zjOEZUR_JMxSGdaU5x&#ErW*kn(?|5*Wze~(fERw<-gMD z3GR`n0JAU9V|y=o$zdv5?s9E{N#d-PzE`0_ZBeJ&>(Hy-bNlN4UXq3Sa%P?t1m(w! z_kNPN)X>K^z^-fw2tvNu6#$8&3Of*Zvi0=His2~1Wo5a+TV$=c!gS}YEkaN*``EU; z^few>kckd%b=o(Y2Mb|m2;L6bRy2AYYmDY+7An50M(bIZB^FD1FR*Q~NW& z@fQg3@}u3Z3I{3XIcKnjfgS+UfBp@bEnD%4)(52)6qPAEGC0Z?txG|O6n&jzbZ1$h zXjEc+?0Bc~icy)SWV*2(`$+8yv;AiyTyR?{a&EUf#mx3DnYkmDYPy_KpZR?%SaAFX zYj*5;)KZC65Szwb-JicM*u7E*jKitfib=+o` zgi9>|mv$DU4(N*fUTk!|9dEFh4Sp+wF0!&V}0{&2OMjjvt$4`HJ z5eN^<^VZ6z74!VX(60s3pbAo@mt<`L-SuFJJ4bXHsUa?-)#7~ zybK<7iPK;giHgdXQQ|U3Fq?lyj3_K}2*&^DKGcV>piGK~9Lh(Qm?0J<66sLI@KcF; zFpYWga8OH6ygW5>-qJgWsr>sb9v=^;PlJ%vju@IWq%(p2`=UM@uIoQKE^khhI=sXJ z2_vw40T(!|KPEbS&DIsyx9Wvp5C4RhqcIC}_t9 z+KgqEe=)E0*?4n%!@Q>%*Yi@wl$;!nr~qG*j;^Ti^_61~^*3#&k?BT3 zW_a=LKrixo-^es@>95aZ=-IJ*Og8Tha$8osq4k=jDha3Y()RMcZ1q_9I|+)5+p`W76Jn z_C4tt^RXY7A*^`kw?9u!_uh{!nBp)+6Jv<-jw{4^(szkw;qi=#zPuOYwpLCvBxpX| zD^}RKY8u$;fcA7D15C4(M{;lK@+QT($ou1qKn}{D<_UYR=8BxddRF}g$!-rbp4Z$g z*EPlntrY~Aie#iX_gb+P$PXFLnduZs4;sdF)JC+YE;5U-Mp*5B&M=GcD%gAk&%nXp z!H>vs$Bp~neF$p)BJL_bhr0-Ru8@B%+ozVWIQ^mV;JdUbSF_(l+MvJ%kk?{dU_am& zOy~Fjy16(uI?#tMT$BTq4b?J-cLUirZ!>^glX-3E@yx7-OKnP|oHsVou$l zt*$*x)5iReerd9Zq)6EPRBRj4RoEP6NP$=Ozg+6zopx6F`=MO`Nks-TV#jvw!YnGN zjwP9Yl1_gfdGDxsO;J8WAvTU!O7@CTK>5`cO79uN-95WWIRfuD9({3WJy1y}%hwT{Nt}O0i zvK$ebE5&i+T4IrALyKk`N~L7W1T9jg)NmhHGBHu{qa1eQ$nxjaGw#}Q_N_4t1GEsD zZSk})$t0;&@O8@9bV)1}%tIFF|I_*c1rzP9x{i8TLop77V??|5C|b)2<}K-V)z4{z zwcrQjoV>D4(uQI{eXgSqK~mI!%ts1+qgOFI=)g93azv26j-W|R6i=dbDx3l4tV*M( z)>)&I`c&V*bLE)j=&`Pbokndy-3~!}r+4{j=+x{P+D;T`%PkoOHGZc@PrKLAF*PIip%e&vBI+AbAKF)ba-7Uk+K3Wg6mKU^slN_c4~ktyn%S-QT6cN}T5JlKnnV?Fo9hA7cDM$ZsIm|JXW(Tn`qSr`+6zB6rn9 z4K-D?-nVLTe2^-tCl!BT?jn9O^phC#N;tEh*@AGjiY@TAismE51~o=$_b7e@_Pi2e zuwV$=7MW7qIc?`uKTur%rG%nt#Gb}ZV;^0wJrlB$Y@66V?McsvHLm@&<0FRrL*>aM z{@-OK<_dD~t3Z10FLbqYfQa-;SbtUXe{}YK)`PY$W7wvy-o{W(kX0$;PCEOyxOrN;Lw9q#R5V zYDlczLjt-n$3djM7&(kIfwc$1;B@9r6#*G~F+|aBIbS~O_t@~`Mn`)q9XTDTIlLpg z$9WIEfn3Y{T!~U%I#b;;$5pxbfG270^e6}=3H%RyUiP;fgc)hr-OM~b#s4TnfO*r` zx7yAMnQ24`EOq8qNG~gH!ED-1KeQ?A3M|q3&@*_1)>+}54e{x^CF$2>Eu1?QfJU$Ev_2v5xN|%~Zw3Ts7T`Cg zOg0h6f&Lz@?NSugUOOhB*CnevUXY;IjGaQkN{~c3#!-e3axwlp#vlQ3GMbn?{U4pX zTjaWJDrVd5C^K784`*@~e5zI5cd@0R8-#v?0rQYb>PCMC zih8uR3N^{f%GO-?qIc7TBf31=EB1gJ7oEBxWvb!X+aj)+GX5%Kr8or|3pLh=lkT#; zPx(Y<(4g><0%m${B5MgFF_m(A*O=|if(#5qIwvoV#iR=x;{04$9A$bet4r`6}t%e^<%+S>@snwzcy8e`se+j|X$ zOJ_*w%&s)y@0A?FKD!+1gF1|FJheqILMhJF{ zgJqi>zTEOzG~TgRz!Jj$VCrxS*eNKZyppZlV4ph8r1*N6;|no6(D=kyww3(!<~+`R zOV85#gND@!j!ShgifI!}fB1NV6%Fdh0$pc(tlBWfIoYMv^P)i_o;l&ekw(Y33-)TO4BJMI7&+<#Rj*`(@YuC3 zV1FhTFHK0_-ueo+a__-FdIEOP5ulr-t)+4s}5yP~8{rI~<9*4(Gi)wZ~v^!*5^b&-d0)tMXe9#-* zU@W-i&GGz0ia)6y;V)gW-6~ULF+2Suqj$bM2;9bBK!62a6-pAn?~cJHYzKkI=5pDB zAK6jCH6*P_IlHKUzp+&HQv4>o7(Or7J|>CPJ3)z75W!qyBiVkXpo~f^0rQkLV%pGF z&5<4e4m%#XjWD}$o_VH#a{V>c3)uF_f9IO&jn|S4%|oKT>;)Sy6a<{r$EH?nW7o{u zmK`uVlOrKuit(8rZP<>7D#T+wCAW7KX1Ew9*kdb$3%)aw52HA02N@dUTIDM!_GWG4 z>+$l9Kz2i^RH#W0w?Q0x+p4v*6;nV?x?_+RoDfpSKxGp@enMGm;J-)mjqxMt^(p@R zo0fBz;)|T)Fmc5`ar8s%yaZ z*aiq{&fSIyy6zNBxj4ILBx~;BhC+(HZflu=N3?-QNm5-3Azi!~pScFz@hPiyS6BSG zve5ar)j#_PrsIt9c|Bk6xIcGhM*|4yx~Xm1Jb?Z0Q|X9om!xt`9RXGc&BOobZqA&e zhwH}o0qs47?e}UU+liPrswr>vDJ3;)=Xo7nn}kvQdI|V|`;dT%i`&B$*~oy@IctTLEkK z_~1Y41kqSIfoayIxmm?i$M;8PYKHyk*JmGBJLleX3|%%D1A!Wnnyq>fON^458_xTK z9=C36o<_`a5U$Ee9+5c0A;6Ew>fFvaAs6%{r*Gl=sriTDY(ku>4i-BOawM~>nva7V z%IDD^T>7K;S{awhUGG6yzav5z-cf~%vQDBv@FFf8^q zCNpeW`TkJd_-ov^W_Qyf%^D%m|E9h36Qbk)bO>hvC9}-kGr`;hD*)^6k9trr<|IlR#1G$4$G|d9REkrxi~WY{eQf>N>a%^RC2#{ac`y@LM)Wa z+$t$Ev)qTFax2$QuC=hl%xzX|t~0qOxem+ZvI#L`b6sxV-~0D3@ZLG+b$LD>WxoI_ znPF>NIn6|9>0JOk>Phzg6B~N}O_aW$eN{L|mD~~I$Mc}A?RtABXso76E;y}bt1w&d zE91kT`tTweN#@c$zhYFhqqEg5D`}G&wUAPBY!BgO-ai6iu9YX3x~C3{R1AlYTe{Zs zM1i@B-5ok%JyZ)Bq}>?)XOLJB-ILvC1%dqc?%b71&uPcYdd2PmpiFP42=5Gl6_J~z z(2mo$OH1aQt-%D(FIA5uTAwILLt!42s_gMr@B8yTFD*_0zOaEZ2K3rr?Ae=-k$BVR zuPt+L_he_hA3JSC2 zam!9cylw*9;vFVulgrDArM|r!^se4y0Q;Y+9qiJ0;kx%`)7{a=sG@pV1W&v}TnhX? zFam617)OSw+jjs$qfo@Yx3Ry!cVBo|`{INy(6@h=jqJ@A=vYDFA6!-JI(M`wYd?TrlCVWg07Vs#JL@!NeSp0uWIilZIdS9PlLJYjpz2#L zhgH-*6h2k774Kiu!M2s)T}GWu0z!&ib#OUpj<>Xko_ZQcP7;s-z3;p!m5;^&Et#3ZP-B^G(TM0lO3M4s;=be#sco(k*G0ZG3wcm|Lwb-w(XKWGf;#Um2k^g$hVZ6L^e$(XpPQ27Hz9%SUI1tI%!hw0@uqsKjhF_|74yAZI}Jvfh-?~ zt@cDjAqpd&3(gL!c1zy`o;$fOGo>WZ6M1UFiLD-`rdLxmRV6})%Hp$5mK$XvkrFjF z)Q1JnyXPFGUO0wP2h2p@Y>?qobEf2D%uh3NkNz!~*cF$xxN!fZTU^J=7kb7`TzNgf zd2}s3N4cxdhNSu8W|vZ70^z?_wdCfvaukE_3x;XVhc3@Y{|E2ilLyGiN-adu1=-U) zRr&FGj6Y*vkA9-}RNIjWA@) z*$ny4c_uIh8BT?WV)#O;^bWAD*M^iOwqjq`Ykqj_$7Q!tFGR`lsdL+rMwcMWU+c$! zxh4Gw@(k=NM6@QJNJ%~8bqtn|N|#K6TnFDA0wQVUS8N3Dyf7fJloayD4126D!w8qY#pZ!^p*c*JYR zEnpD;hUK~RSK6*mR_LvrZB^hBp8k^ZhU3nUn99W;sT)tZq{r^3<1*DxdYrJ*b3W~S z@Zm$h_Hyk9upS+2?b3$ozQX3G7UXk6CdtiK9{IL~#Wn<~_eok+IWQXjExx<&R*+|? zV&QLQ5F)kL+4vBfo~`#{zT1-}WIcjnrgfVPs|O`Nj+wuvdK+gF$Y@*({>r%L>#OcV zoF>JXY6;a-tdz7u5ek3A#a7}@EG@K03#&fVTKySw%FDe?WUH2nK&ZZ)A0 zRREY_uXFr+JDfiPR3RHCu9oVo6w=3dQv3Ctr?`dltYg;)x#A}w4xy|bXW;qb`H5i( zoRBSWuNpCj36&u&Uti98Vtd*h%tBYiICQD^4^%w?skrUaCDJy3HYv^ktR>XhkNcpm zXe_8TxeXoieq22ACt0G)O-FHB_2lPzi}l9_dP}sBx^^?>jw3NVQ;MsDDM%@&Wz}Sd>RU`f=&_Lga-Z0F^xN!=V`DPr$Zh2zkVyK%bqPWzOax zLvIE@#54_Idxvr*g82P^`$8xHp82{({*4=b*YB!d{heoO_*BJOinxInUfR@xwa02{*h z=#V=Ysf#wFFBy9|P!rf~$j>P0Zw!3APiGuOgE=y^evH+`&t;8j?%2ltnEhdgEMDjW z)$igKF%?xM3#VMni^de_dEQY~MNN2A3$VsGm74q{uN%UnVwuYVZmw*^Cw?k)Xbo~; zY{!fa@F3V?SK67?+~wHhMhcf-q~Y5h?Co}Dlb?@}-c(R-GDmo_$qEyx9xQ}PmX+ZO3X$KCgF;ApJST0_ZY$;^dwxt(O z@ry3d3z{I~+=0F%t~s z{`UsUe&jU(HucfB->H#hv;1^;Cr{FR?Nfh2ot<4TQSWa5)caCkntWKzzrsCq$K3hP z*rXX9o~IWy^;f&@*@zF4EDy^1)QwO4s*|$-b`I4o0^e%(v{4UzBojAieUTd#qw_XU zOO(H|AZYi=E3EnzbKEp|Xz|go{Lqf&k(wyHpv*;hhk7v3nah{c!{O~^J-^p~K;FWPf@ajJqXJ^i> zid#E|{Z|6bF(MQQ=ng?C&hz2WUAO8=MB(0kuHG9Z?nG7SGpY(tG4>O%^aC6Y-qW{) zRDfUGy+*66eNKZMZ@Jbz2Ogjf<$+M@ovl-*v)6gGx+_9i5!!gTd}& z#0%LrwDZ)hl+LNtmcBQ6hj;=>6j7d(kXF0fseUq6g5TFluQrUKp6d@BOLRZ85Gli@ z=rxV%R_3}m!!Xuww%#`mbAq%^FNpkQ%Vd43KO3pMb&v&2uh8Pms9(S-Z!EN9G$kxj zRN%jNjOXwMWa0;;Wjj3!T=`Y4FDCf@oSobG=7il>>wSVI;iYo%H!@|3XBRu3%Zf0SnsByJkzrCGsCsRM|}C=_I)gx`SkRt6GycX>t0zGVl0E!YE3 zouqF0W13H?q^imxMgP}V&MEF(ynKn#(0x9AO}=?TYj6i%4%?Ia^6@U#X2e&0ZTz~^ zKv1m$w`_9Za{0zc7UN)cUR2Uqtr3cJO4DUDGJ`^@Y4JxeB;&!%J1vEE(*=%1< zaZ?+4QpHQ{G(Ps1dZ3?-JnMB=M~{0r^^JQQd3VI2WVlT=Fbr>JN1Vs@ZYZf+6piuehmK4rHh-?mr}U9O9%EFPJ$ zNcOQsh1uLs2%(AC;shib%y0H|Pb9_<+P1euw&=iW9}>;jS7MwqrY%$&x|Bziq%GaD z>EqxTUUedYFUE=xZ)ez-Fs-bA!3JF!sMjNK>C9;RD`rKm^)8`aBaF9c*9w1k3_35U zsXyzQTRnyCc7Fq{XksqEp;HwG6&tw2Bl)GBK;PXJCRJb(0{7lDjgYpls{c~A%F%S< z*xA%%K8*`}p0Kb_<4?^89uPF*H?`$y8PeYpKtTn6q2wx52fJ<49`YQi`KoaDqaBq( zZn}%3iSH?VXZS|LJg%9D)rA)P(#ov;)WHK+g|HfY4|y}XDUS<=uCZ=I1*pdeuDQel&NZ6>WU zJv|Nm^#ycQcQ5JMz;Db@k zxBs^fE;q_vvmC1jF_c8oGKl&`<)_C0>!SahRcx=dtaPr<^EGQ(Z2c zp5fmA#y}1Qx4RrUi!9#LLN(+Evx6JXOk`(Ytg&PumP3pMX4D$fJvz2}Is6bu61CyW zYTey+S9Oc}qGW%63Fty~aEMx_;)UAh{P^AfC;|bj)Hl%`$M67^Bdh5ojuuox5uARb zBXdjcTwf4qUN+jJ;BPgQ`ZY+Uiquq#xHV=vf(Q&{R@ODqd>>)-al6WNMSggBJ--@q zVgh}c|Iuito0<9+@Y~;sJTkBha%T0Y*#LJ!wA~jzeM+rvN7pCNT@2-ic4gK@s=CZ) z7kqO&KN9GE0wo26L)8W5K4c3_Nbcs#Cw(g95o@UMkNE*&! zB}?%XUQaD@!E0+r;FO0^hG#<36(NF#xHVpN#=-i^hHXaf(32rg6%AL6ap`yRrSox0 z0_mH6Ico=#P92>JG4dC3T^)qfo0V{|ZcTwJSHn{95~4e+JNmm{jJ=!UrA`*G{6ghA zv9X3H7;ULa?THV#4oQ%>9fSP8(BzQ@=JMMuQ>>>zBFVWd*LLCm2NEj$Adm3UU%!6C z?V2BZ;Nkz<_Y3Q~a}4NEk|MjXlF&Yjp&h3nZhX7lduD_<>q&DFOc*>c8JS`3XW_K*Dv2kR#Ys@{)VJS1W$>EsNIoaq>^82R#r0M^S zsFg4($u$t*{dw0sH78f{ZS6e$S`k04&z4j@q`f@`2e@Jq6$mZT_IsqdF9CO-``dZk zxuF%LiTAe@q4-M2ozFp-g^T>jdHND!6dc_hIR83;2BK&7ga@r!8Hqa(e{}C1n{Qtr zmd;o2$};}9?_Oo=`Cy5^m(QMCW7G5Ip;_&bc@c}-}hp4AI2OW zA`NTY9D}^`t1&5PT%JKR^8siU2xjWA5dRxnDt38;ZraiOIM^_0|h7HTs684fLCh z^=|fFwKjb4DTVqnJNw=eu(}) zkCdb`fP13OTuFAX{KIYgfdKmqIby)UZc^{-~h-ka=A$j!cdHvL`SZF?ep zX>f85KWn>}mFI5E?hl51x%A?b2VVZrG~kY&U%Y1i^2o$*03n$q8%?}n=#N@D)`8Mr zGMqXg`z@r;=wIJK?UXCglk(@HmwO>H+q){e|Jz4j|9eIF$FFlW5&}j0x-M-j7@jc| zwvOkP?Fk0(j3L~~mwTuAru252B}+cD@jypZWccPt@rsX(|YP3rO&2!`;PnIJY=x2jW6$poC9h@LoH~Or_8Z zbMKCEHr&If~@i;Tsz- z(?~y=rC&7A69}pB_@@JcIhYMK-4vz=hA}IiocS~b0wVK}o2n`KpNRMpwq zBm)-Txywg}0*J9=xv%H9s*5n5YXi{E=Mpbb*%o9v;hNZcXp6xNO-B%>i8!wU$n6cP zs5Rt<6t6R#v1{13O#;i>XMtvo1UcfO&@ z5@OW@E^Aop7;a*H#@io|J~W2T2q&o0BNrea)M`2X8}oGQb2Rhfc7xh7|A~=C4kB=b zz8LWj9v%wQhJEgd5?%b`e2EcmDfE*7ew_AO@KI%N_VHOc1;>B+8<~$RhGfsz@&mT@ z;Z2fzVrWZ#_;Z%}w-FLG4Y~^2B-Ql&5@OW-sL3oJwk@yfMo1HPFvq3w( z6uXfbQE1}Nb!mG&3ZKn;?;R=mMfPI9_PFg_3r3W@l%o^E z&zvR%^n{Nkj={fcCT(PO%`R*;Ze|gR{#M^_=z)b4-}G~J0v{B4+uo9-q+?o@0WZ~Y zacTS*e{mMCrgUtA(_@)ydZlVsf7Ng(-{i;rXg~a=Tnkt)ct9C*2`L{HR+)LDI=)W&`9z0W*LTHMq=RTRGgycMLtEv5M7i+j;JPiv%x(!HVB_;QVi>wpt}PEU4fzI8RpcUl&vBSz%ax+p+1y{!THh~5KSnXgql z_+eCtiGp-j;YT1NYAlL=2ymQ618(wznE%g%6XL%r+A-nzzO6u6QDEHV&T6TRL>4D( z$WcblnVTr+>NdK#bFFwx%j#<08@s@Cz$p9OI*Mhwq+Z&nYZJRSbF<&x*C&;WT- z{B)`i+z{Kk&RtFbNdvJ}w9U}^rRe4Wl;2NGZ?vKLS(TFc02uV`5CLQs4vN25MXOlL z3cWzls}C%iTU-K_Tb(0b{&B^z{DGgoJJB?d_U&PypN+3~&ip``#EO4k+Wkz(v#|n$ z=83Cm5qyjH^-i%z2OfA^3fV5@sh+Hsu{ee^02WNJN_wF4MFoy#%z8po{tE zZl;VSr0U}x+SJJBk;empWzsn?jK*-ALjWo>?jvuEmHiEF&pUw?Lat>y2G)XZvUbI7 z`h(QiuHe0iyX(us3k0T+-ra3f@!Ye-KJ-6B3J%zc;Yf0Z+a<**pl(w$~HC?~SP_D2RyL7};*e zyd6vnq7jxk$RKALRZK!O{xero!bd~G6#F%xzybx;X4QE}d8?i-%r8uvnTaW!+U3Zf z;$3aC0vZR5DKB z-_bI1*I0XJKab{422uf05|dtGQSC+^9jD%FfNqxDtJj#R|0ahZXJ(8zNZCX?C7Be= z8;W-1C5DD0ar0YGG}?I1=IpS@Q~=7Eg++4brjTveMBsUtKvo+&Mv@akjVyZGEnMk- zsy)_tytDZf?9BY;)Dw}r5p1Ra9=jR9@vT`?Aqj9LT!G1d7+sQ4CO)kB?_JY*ki z3m2EQzOLEwj4cx1+>d(`r}V48liU+eOu$(OF4)B^Xg!DGB>F6EOaG1!CD*wOjK;P1 zX#_q`DzVRDa#SDvqm%I#0k844-IE2@2&Zsv5?0;wC+BD681jdTQKbIGODXWqc+O) z|Io<7M^Oo8hV#{Rlo8D%Sc$KTR8dr?6VK>>`x4R4Oye_}iQJU|&^6|+n#1eRAPtAM zt-RELU>#sl+Z$tz7i$VAW;2=+G}g#KpKb1I?GV0Zkb(%dl{@`CyA^W^z&=@a>QQCW zT3O<)V-5LCJU8oAICJta8+>sXNj9Oahw4NeXF!B{)bp;5JfZn~LP{rtJ>in;1i^dN z&Kz*ZWU6tS2aOQ@?NJpL_A38X=MN`W!@%(nI}s^}7XD4!2;REPLKQ_(pFYGL^u1;m ztlRAo?E7oJCKdCqbtJrX%F+xf7`hMbW^< z`9q#5A*6&q);51K7SE3$lCBi~rJl8NzF)@!zE^xBKCXRzDPM!$B_~MLhsmk{Rifpz zhUVOcAHR8e+}NalM~|gX1l{&5bccyJkHPAFFh?+$BXvc5=oZavP@5oUIxL^!su&JA z#gDe7A=e6w+Or5XOk#ADDCHQl=?p4lI-(=H7%kq!6`CMw-=9PUi_(?=ESCrT`Sdj= z+x2$)gk<$z-|MXz0>v)>?|ptzt1W7=oRsTYt`R7h>VCCZ-Boxo$K}f96y386AQOX* zjJkZ~UJKiz-|%ofYhHBDRN+4th2CC}ru@RrFUGZe<@-Sw^K}ep34pSUezZ4dma5eC zd002yU^yX5I*@bw+r-6cF7W4=cT?H@>}mM$=lyPGce1lNp!ONgZSNpuyPc|iZwYKV z+VzNX;tDaqLit3~w6rUfv1BB0Pb#u=QD|EWCP$X*OpH1z244o=_5SdCYnROXUWMZ7VHB?8m3%*yOR=d}V$wG_c)@g;q)3#^BhFU=Tc zJU&`tpO86Lw99d;nneaCSJwB5a@aligpVPW-j{7d{-o+)A4dK#M*v$&rS1s;S1wWw ztxX4X_dqMW!1$$huA%F-<}K6Y$IRQf1;dOm)7)@)1kqc(J_lMj@cTRu>Iky|BprzS zp&cD2R?yj%y+uq}+axyxmGGrq6ZTqJ$k&sthCRd>v=R@(dPZbM=mAl3McuHT#*WlN zR4vTUGJut6b+dfww^xX`?A1Zf_**?F{H81u@j)w*}tIsMj=Zuf0)fd?``rmI%G*lN7q%|vK- zCq&jqDji|XVMMNvA(k5_oyY%aVBq~}8G(N0t^qow*eCt)!(X*&3WZbdbOv| zuV%MxnZ4dYe46)TZ>D?qlrGE~SvGGyOBEtXb(A3CxW8NDnZS*^)H4^iCfy{O*dzv{ z3JjL7braMqvK<yq{g6d} zF}+{UArEKR8zxu8OS+WmNtaQd)zE(|KU-_e%$#^-{V}JUW@Et_Ba`ME*CPxY@^rY6 z7Fl(kdx8T?^e5x@gb_crY#}V9wa1pl@>&;OYv_Kz8e!kALqy!1cf@Gx&e#)sefFF7LO2xsL4N_zI3>2z zn@*ykzGUUz53Dg|+WmfYz`PR(kKqXy5%=+lb z(__tK$O>~IuW@lUTCsa_(0Tj8Z$U<2;2g@EII1nYNCf9y>x3f7)005^GTcQpxQv#4vTIc?TV6qd@0ph8ev)lx4+QNilzs@sSpd>=m zBVk2=8=R{9iF!4KGj_jMrBILO=dAZ|I9<(NCp{b(MSTfiLnrX91m)vT{z#q@@K3AZnQL+00iL20=`vOkWhKp#G=nm`=MI;>|= zWVHPy>tbOkWK`?fV$MIRgY^3cX?Y^Qn5FkoxHmz&sfrgr$2`=r98<)dGpxCaJ1nuf z&3-`G5P#G3OfI?Un9jRWlqO49x`&B9UD;ZSzTS}TR6n?5!Yo7SNO#4>^_!JZ_9Vm0 zl$XifM!L%;gF4}CD+Tg9BB(y7DTzHv62r^A@&yC`o?hkhJPZ!lwWg7;u4rG|d@}Ccmhu4fnU{S(* z*PT%AZS^&YXonDs*?OLF&zmfQxer45( z;2a%kS3?bzzy^J#ib!Q*Qu9neriI(Y3VQv;&|IICP2sXFPP<|be=+&`s)e6Tq7`oJ zKigJ^&YPx@9af!LxiIBb2nPJeGu*#S_cvp}wV~ae6_qM?I&fF6eXFr3S1h~S5mnX_ zd6urRyf#)#R-UB{2MS&qsc^sl&NHyKZsgMtvVstOX+vC3WFD6=RwjIJw|oZya3Mn# z_M$@&guj!gKuS|RVfxN?bt`1RMf)rk84wInfz|2F~U4Y|J0(CEhW|qIS z3W*ZkC6L<**}tZoh!sUcy;u);p_AK0S7btI{Kj$ih8Yi-+BY`|E@0x{uJ2cRSyaPE zOep}TrNIn$qIlvGU5nf&q!`PyyPYSuA1)rYL}m$ocybwqZG#rQ!)c3eo)$hfFD{jr zxtjfL`DNs};UF2oHZj@Dh$EdH&^wrrxF=HhXo>(&xQ)7hL}3^JC=o1M_oR5#D$zV5 zI6nwh&bOVIw4^U-5;@u&*H6`H-8QXZx;5K|=v#a}j|w>W03TN{fj!KRZo`l#l5u>t z^#BE#-^z4$z10fk#m>ef%6F5`)7Gz)pk$C5zR4Q}#0D>hE;bZV>SVM$@YE4no756( zDDl(UH6bz9yrn{VH(N3$*tU@UASQo%RKfGut+JV`fJnB#X4F! zjy!D4R2T?c&xYm_w6t@dblO!9`zA?cZy3Kp0J~?^1a%$d$Z~!-7g!_|)mX!xLx=Ij zS$)UH6+aa2*j4k8(ReO7J{ldu{O1eOKs=tBCndF3%x}dfU8v{M<3ZAR=^l3n3QsRZ zX+$X-!rjdn8Nuc;=H3FSvT3Za_vBg9IFQ$kd!2XYOE$2bAr+Us(RAF43#0v=kkB3B zJP*ft(J^;|2cXH<7j4O8W)s;DG!Y(|5lKtm@s>N`qk}vy#?5g%#0ySm$-UXELZ$cc zGO!}#54MmKXuYq)Q-f=q+a1@?%CgEIt%v@6NVAkX3zwRV@gW?E=5F7qrcs-&Z^a8e zdO=cl_;FPsm7oqjL;8LBy~V#G9iqqWv~2a#2&AY@iH>!UQtyIRY|m4(TB>$xF)R8zZHY-D6(Rzi}11iP06A{oZakT)P37BZm(6!wB| zHdUr2fIi4KDpeQ5OyrlcvqpmTwg#P`<{?i8f4fV|ootoGMuaHlGPl)|Z_P?SDV_Vb z6?d&eOL#saI5#ZE0T?CTwQtsch5{j=d)t}f*6Uy3dVK*2jxJgtaQ-{)gr)kOk{{(2 zkss^?zfr98ZWY2j9l!gVjoQb2sZ9bsO7qK!_+`IUAs}d&c_xx3nbOvA+(Hc!zvH)k z6>ZOT!-lg2HLhFpHe&)i|Cqjcq&Q;u5iEH=TNdrzq-aFs|ZB=KY6{$EOsCI~;zqHLHp`aoF2%+dGPp z`Qq1(y*o!6LnJdrM5+glu`HDtF_4viE@RL~oRR zvc=`{ProA?@Ak)(-uq{^QOwtZb33Qw+aX^7Lu~fzJy}JT`qnN;kRGvFGs6B>30P)s*E{p=qmUElZo0 zRJtbVG%NQEgLR17a6{8qigmqsD&$LC`}exKgkI?ebJ^<#oIyzdx;ezTgSP5dr0~s| zeX{ctMpgZ0@$0X+#16<5_I1=b%C#~mO6dVN`}JWCmDdt=6??1dB|J;2PEt<#Sy z7e2@;X_c5#F6gCvV~Jgi^-=wdw;&t(kv{WO>`JWgQdgrhEqn_vew=aY@XT^(SMQBe z`(O=w%(i)vqZVMIUti;w@mQ^hF$*!jw3vEyaPNrQ?d|JmGoD_Oh5|P}jzfY7p~`O2 z-L@^OEw?{d-kj1BfWj1eBf=f9?N#n3gbC;v6^j?rvhCk_TnAiW^UoRn$4;tR^{_e;_yi>QnCoR9v8NX{vJESUsdc|nxQ1gm~Waewacn>TS<(ektkvO%!IZFZMvUkVEzwm{4&Su zf;IzF)t`{-t;&L?DOOCa*OAIRffUelE_DN;)Up8xiNVPLFFy-XJlPrkSUBbkQi`8y zmkn6cC*Nv^-()#zER}1s2TG3lqHhNkLE$2u%x%2Ego|Ih@%Rlz(*u_;SBicQ{Jr@8 zo%7>ARlc@2BglURTHH=@5q)o%Tno6Ktd!-)X=dHdEyN$XFR2)xzIbhc#h_V}#Iu7- zgjzch&wZ*_ta+S^8htGvtJ792Kc;H1>b4CfZoZo}*DXc=oD#cYCgm&LefRd=nUsgr zs4E>1QM(V_7$D7S0dc$Yxh}8%2ehj@BO`};o{A|dj7O)d6$*8KJ?>>$^JLL zif;Kgbp6sT?Kt>nt)staJBZD&Qj5Th7(5JaiR@>dE%?qX93y{teKeCY;!?Hqi7w77 zYs19i<1h6G-mKnZow%I5@142__~}aze^QPAg{1T9omY!NFMprTuALpMgtFmAdNj)# z{#eP-bf2yESUO_OVIgySy~;VTE}7fZfzeFmiMLIPgD=e2FqY%?WP3ibrL)jD5Yl%&#AqcVe^v!Cilb(IdsS_~%_#rt_wbkH$U@V!g)^7ROicQvB80*|bK z#QK(h&3v)0@}TU}{1ceH9ogV^R(fE;675e$;mmW@gdh!D-58gvKh zgho-)EXbequEuO8YksDatj-uIc1XLL-KQ^e5QIP;tPFN-{KcdQD4b_1Bm)*g-$C3q zZ2)C+V#9fwMH=0V=Bs}Vxl4EL&v;fz@#I(Wjnz5^Gb zvxkd7XtxX=GYS#$fa~*DA-YY71uYk25(1U4N@(wto zkgXfp!49Y0?RiL!jPT+=u3DRWmC`HpX&es!wqhOb!Mig-{+Xvdyq4(*vi#&?CCc`q zs?Z|kP}$I7J1hEHuJk=C_cmD>ZZGM4B7~G^S+mpdmA9OP02!B|tm*Ai?M-oHJSoER zM%)%lLy@Dtd?X)vuKLFN7?lVqmvU8LR6cgwe__zHyeVKoPTcre13my4x#sk`=-0&q3ym&CrzA0Ffr1jNheownT{r+oOTYtya zZ>qh#{01P(efWiaxd3vxATj@zH36h6E^7K>rgJ3lU*Q7OE=XQ^s336e`+@~1msDl( z;9ovR^my4ZLw|y(Z0M?;<>*cGmC-H*adF9tkP13aYc%~^_T(Axg)!8j-~1HFk;%~o zDZt`D(fJGkrf>W>T1&7VbmBuHo6T&ny1B-={$PZ&HZHjXiFo1z07v92%t6PVK6MYz z-ZVZH-yAew5GO=qRa+}NMDMjE}oSt z@XOWF>n)Ia@3a{rcSoIqO-LuUKACo&+Y{wKXKj9SKZS)^>bxZ*#Prv9#aUt>aiiY$H(-YCWMIL_+0_wH8g6_)Gyo^t7nfeSD6nPTJ7Cs%5{Ne2FZ4INOW{IFCEPO^o#d?wkz zHmzkS;Dx=*FLhb>!~!SQ*S*%$)|!rCA_ca?yEEcP?JcveS%IBb&CE3&lmd7_vC{&P zL+jMjG$_uWyFFwZVL)d-az)Ra14QN-3l0otcKx|GW9vf4S=*4txK_uSRh^EQ@Rf>Hv0qM+3aby9r^J4?D^*9Q9gJ#PbB)fhi&7HZr_;q9=r9{>(zIs^%Lq zZc+lI!|c`waI8*r9EwzP`o(8ESms(xI&qC#g+yAi4L_x~j--us1F^5Rrc>)G>oU@o zUmS*zKESi*BtQIK<)CMJyZf`c&8*P4I4PVDFoKf^OUr+oq0)Oi@8a3qP})ohZ2ODF z6-&%RRf}9hG_CBYtee`Q;^F&2pBoDwTKERUHs%gCq8<+gIw4+pe0CTMH`=0(;5$WpVQXP^KD@$(VO2IZIXX5v--EkHw;TJVmXi$as^s=`Yr)&8O}oJwc5G;M&)(h=B`*0CQ#Si z5!bDUeJKX4aE_tTwFhAFszisHSKxzmZ5j90t>oEk0&I1DlM%$}%`LtSzH)dbXYgi# z@1V-lkeUx}2AP(Jk?Bea92}@hyFju9g?82cJo7AP-ay5FRmnT!qlHV_X6WMYb7^(0 z){bwKdo^ulA!+wv9e$g^FMO{;#t}--FoQpLHMupNQKOKK2^n5wZ0Q&vfe|W3)w@0> z%TMKck8GMZ^v}dU#AqEu^Pqnrhw9_LmRTOOV!BG0;k+I4&g}Kq(3Yg{*X?v?eA85P zHdhSy%#CfhSDJ1vHa+t%A?1fmwsdxQ@ulKt2X(ThXL@(!Pj$z+#=L4h7ZGuQcyqIM zb8>W(DVEMlZQG(om+`-XG_`w9YS<5%$i7v?mAUp+z@&^v7ccVU-k{YA-;=r{Y@<%W z&-`WwKcn3q3{tDUsO*UmSGc`Du5CEed-$<^p|=|)*TmY+8{_RQJJ4a(tY`3GCh6k8 zj3+%q3r|#Si}DXmeQOO1AOBR7XLIHUW%6IH+f8r`_BI8 zbcvsu#Z3$ABCLgM^()lVZMhYVIQN|^(audZSr=qe%i+Ob4RcKbNB(Q#{RUD3q!xTU zs``HLDezL0?wc3Q+W_q|GE-RMHydh=Jwm9MK%GTJ*$%9C@4`(!+VUi5K?HXeP_r3H zF^gP-WuCOqzZsw6P~?fIsJ8z3u)MNDubNZs{2rckrvvsZ_yQjQJFk~ZMJxlZstW$+ zr4ArrQ{dD`SkRM-`O?y+rhT6@d+8a&$w7mZ2NqEK{?%!^hwUe3m&Lr?Ut;QHkH}=n zfb1{YJ_M7`-HNsNkFc0lU@NLdd!1OKimr{7gUb~I=FicGpoVQZnIxhcPS(d)MBJ+W zf%i70G~tE0Nsaz?rs8-;T|v)}rnHam9k1d!MM|SdAr9gi-XQw{A`0W|jpZSivddQMC^OL6j2A2X-1WFceAE2DeZ0;hi zlB>zXq-f7FhGmF{pU=R=?T{1MVh)$@rKKvuo#PzO^++SqR5YHx%TPuaNy`!3zr^pH zRokek=GSn$r}pw$iIa(WB0OXQ$yl(f0L8>Q(*qj~Hv~ehLW+8GnE6=+-sf+rb}X zrCvmnPXCep^=atnxQNzLV)n-@{iU^kg7NM`)ZXDb5wp=3HY3yGrm->q@saer#U7^q zJsIO`V_)*b^zrR+u~6`_65hP$yhfM9%FHC6eBSst+=TwLb^Pc2Q_^LDtWy0@UhNtS zr=GRAg00?}gJ9nEsc6LJZEZI(G5$p(@grJdd>*HlO--(I4TWX9{alc|z8Xd;Qzac| zB%J;!q5bC+=D}lCQrXObR`u?w62G!8^S(Q+9#ahcTYC$}lc0-#MBOJ6ZF8-Qp!IN3ewg}V+RyXxwxC3dwn9Fk zg&WBujmOU&)p9(wA;wR;IE+TAvvh~fkE-odyt4eQ7F4zNg8yX>pJDh5Bax+%jND8; zCxufUE*U4~@#nkgB324Ed>}5zH6~5~V`tlCTjxKOko&XlSW%k*-}Cq$^eIEcP_Rak z`J8#31*M0gUP=rehx`d-9461(T;!OrZQrt;`zWBnANI?58I}?zqaFbkQBzqp$MqQ7 z6CcK2)dcs|Ks5kW7}dHM6JU4u8x-VG^p?R0yw?S%V(65C@=QsAL-8f&GO-E0GtBmW z1F>(4LFx)N=fEe4ThP1bc)|wTqqD!St6g8uFuwCmW(uYV!v=*T($|Cwr}jz@=9XkL z;>6i1gY-G@x7BrJF%7stESjO~vmpR(R=t;@S*abba%7>#kdNbekgo@+X9wB=qvM3Q ztAVzQg`kqonekMFZgqja>7K6t!?vHRx-`t|SAbh!u!dUI=lX7HKe zvlml00h65M83QSl_J>3^q^sJ4 zV^N;1>AB3_B6gd_!xs2!HJT*eE4!-5;P)SPt9C#CRkf+?DE;D|gtoSslQAU15;*JE z*gGh7gMz*I#9ka+t)19_C?xrG<`^k!{E*J0@c6-_g?S;PAKD3}?+1+T{(~@_GY`)% z{ddS<_Q69g z&nf-_uQtgYEpund9l<;Qyz}M8r9Y=N&Yjjnx;b($$Tq%y^iN1ZK8v?aK2uCc+sLub zBI(~1klG@-BsNR7u&6}lUx}OBn}(OukTcFI!^F|h)sYl!XN-k?V+xFz@$PzuQAeLa z0F)YPX%i&}wqO3=krYGRcKMUI%gcu{?2fmyDAP{Xqo>vETe}{U3)wF5e2b5fxyED! z0AH5jRF}SU2OCul3SyJ#8WIto8XtDF#?-kUHUgMNz$`bOT@=yONVTd$im|&qIwl&2 zpH!06{Fo4e4Ii|Lo$kasl^LFCf9L%nmAuVkN}RP4BHYay2W|p!pXvWN&NbE)yYYWv z%;vd|9s$LWWptjlDuZ#c_hnM8mfs>wBK7DX%QOigSp$2yBN~!}*kk5w z@B)vqIn$s?d=0z(M)Pr!Wku!dAJzpzooNwKqFUX(8V`--JTK{Gcfo&^uZ%eksK_AQ z?DBv!3nthiwat_<$rz`z4sr}{n;cc=)&=$JnsyKDk}Y1Q@Aqzd<&4NJ+(;X(FinTHUh?l=GOm$(ITZPJf1q&F?Q`Hi z=Y1>AeO4m?QF#`n2KZ~9x@VA!#J(o-~uXvU2(Plo?0Lw?PNO5@(%CUpg6 z22b;^OWRZ8hI(--nR-%;QsaKjy`Ahzwg&0;2g-KL_&NVbovGI%L^Sc|d&|*FmZRYG zab?CVQAy(S`JHQBA9AP)(#>S`#IWf&3Ivy$iq~D*;d_hHCAI2D!GDnvKu~t>`yz~C z^)N~<5WU1dM_u|{OM^y>C&;`$`(veWrM`-PnX(hH_oY2-Y=``KVtD@7^NQ5)4LipG zdAD~4q?~ibB^N-}6Hbo<6ju9h!cA2KjbmT25$m*W0g|gV zsP{>@KR|hieGBw9$d#Hx?H-7vsgQaB@S7uMzdog1D#-ZtbW|sQ^xTo?ea-o~H5yCR zxHa(}8CP?7g>5bFGPe>9NmEq(L#}@PM$~c7?f+Ax2w5_^Yr-3*G1l$q$EXuG=)WC4 zV=%HLl_Oc)>Stwo&FSxN@2}sEWgY$W@zam0_bV@uUr!jU7{9k^1-rajd(`3NrifC^ z(C9dE8x%paB{V7-5MBh5Rvp(NLvKm?n9WAhYl-uI=8LOP5ADsvFf`ZW3 zt@X9@*Qj49;PAg>UC9vk@Xo6qb~_70C{ty=4JhXgH{^!4x5GkCtd&34^Q^lkx@+4W zYv#a`rC|}5Y7h!E;3Ns>8p|(&9C2lp-e~Yag1(O74OV=1oD!12IE%WMJJ1f&%m^la z6`WL)`^nsxhQVOT&o4#Q|IUg`qSXp?=UD1bhTi{sG5@F3Q?}ncvRnGi@t#Tew!Zy? z&hiHZjCeI{X~`?0z1VUYEiBm}>fWa)AG!9?d#uIw2s`(vz@22o-|p{5|9mqa8{bU| zzJJa*Zrl6(iJ=P_6e2y0+xN6xtuU|e8GmA=eMqPsyeB8n_a_qZm!o86SDaBPXlp+G zp}`luij8rnF7L!F$A&Bz3L<6adFmz93msV+7*?VOvo+c#DeeX`h7p&$0O*WpT=BSo zPV(2HLY?5=dE|CX*O(yz4a0%+a1-GNW~MHU%3i?pBFRw1FhKI$@VrWD(+@W7W4t&A z5mJu~8&awNj`RW#0HJ02G|si#7QRrdt1oQUkuc}ZI@wY+2R8D1>)%;l(5VKYMH*Z# z(?5UjP`uOC_}v_}?;YXdhx5Z~F=VOS(chXP$OdCm-fih8Cg1lV{(O_8}rVkw`A;vl%pm4GhJy`oa@INZenYg}n05|!NwSSM)P_SV=c{xAhKi#M5 zy|07!Y%X%&F9qfM8DA8kW>m_>h%^NI3X3}kt4=+5{>v`H?cI>V8F?il`h@-2-|vY9t)2h|Z5u52V%JkkA(6niVG} z=bU7g`j>dx@15lp+vk60|3-;L#`E<;hkDo@jqDXhHAX$9r(vl~lvxrzQ;>eLsq#D0 z*y{Q0xC3ber4kh$gor7oiL03I>rZvT8J0!}7y=Rbc4qbm5NL*2xs`fVnBoG6Ir-Xg z>#7#ns^}eI#g5oDL zKKcgv(Zl0@nFRaw+r|G6)gjzX*C`(Xzx`HCE6wNI)q5OY47j0OEsc(i`B)~MU?Ty| zJdrUgI@$WO!(Fp4PCsz~Z_K1F011>5l$9T1Uke3hH9pm|k3Gm$r}U3ss$ur5w?~Ee z)q!W0rgrwyCga37#$ZVSHr$2TlZo9^#?`w2KzhxR%(DkXQ+g|qHgO9Jl8GF^ISe^^ zCmV_Honfg`^lW`X~cfNJQi|>j4mE>EA#-!-QRDy>?1bOEozE6ritbHR`}Dhu%;925j6Pr) zCKj4A4+eIqzorVqfMAdx8$;N;0FunwF1@-kfImsWR&}!C2|SkeBv>!~N+BIKR`}K9 z=0RC7Mb#{-NWpoOvQ2N1-aAjC3dqjUOQ?3KeEGPy?BL-xp2I&8$Dei$7nv z%z%**ee+~J1?Ipslp-X$N%N;XpaN6vwz$hIvnN|F+n-wXg=Lba9UqJdn2D#<9rhkAxW zujiqSDkOV%Uu<{}WKa}<>ZfakkDo&3j412_Ik}J>I@9r{v z46ryRI!;fSyVm9Rbdnnr@uJJ^_?x}tD?QKWjF`iTY6|7RaRD|TmC**NST=kp?s9Yf z;V2>m7zJMN@L1-=u(DUzm{?^F7vpFH%4q8F%97LGRCU`XGRBpel}4YjR>+L(Zwys5 zY*B%C!=SNB`8n(jONz?IHKuZ9tr2==Sl3k=l^KcV#Ii5e26#xYBUxvGG&5C<8i#9G ziMzy%s01c-55H~Y>Q`6Ru{S?z-kb%2>I)R9?KDK7CGB48==X-z?VH?pX>4q2B3_OY zLRgM}EQ-SFcfO5JYNbVPS+)5k>wd6h&`+zGD zw-%KWO>pMQ*hc0F{k=Rz?%=Yx28ke$^B<0Dt~9bQS62 zlP9yi>3Z#7iuBRv=PoF38K-b|=7vcP^?7JG zXL}DUU%c0MWPRKa`KDgeTtqHRw6SeoZ-9RL@cegK_>7w%)qGF;+m5_mzBVRORs|6z zr(0KJdb3-g1*$;Z>GI1yJ4-aTkPB0g-k{zxM--|?Mo#n`TwIzx!IbG`UGixChSCn? z8QWg#`8n19o33>E#rN-S0q0HK*1fN>sFz|8xAj(N#V+R(RmS$3SlNW~v-nehKERsU z_&f+DurLF$?ri_Yk@Waiia{DsM=?Sc4lGdXPGlK1-t5 zkMT+Em2@&n_C(==MCQ8yQ26F0t`%Bf(|IdDeeB?uTZ0IH)QVX$7M=E@e}W;WH`b(Q z+wsrqcwEupr$b#fW})!}%CUnrNJ-K&V^Tg!Tp%`Z91RD!tU@oPkMWYsS!O%%L@dXd zzA~!N%d3p_)67u0I`zf56MNVdA9eYVIEB;o|HIr|)ptWR|1i<>kma*HmYy8-jo_3l z;{8rb=K;Z6&;lVCq;5WD2*3cXLz3SOhDo%6wLGPsC)E(KdRD?#4p?hP11yisif4!P znLFJMLDfIVts(f-uXrsWp;-rJ9!&Mr0cYq7D`2NcdOX|U1Qfzd3v>o06~)y72sUv; z`WNS-KLi_5w&~QI$%hYw z0OXgs&btC6PFrZAKvJw`lxQ-RM+Rkiw zKJdq?Fw)Ibb!X=!2+Ghpj)>3gy+HU_iYc|FE330PZ(YdPKe zl~Y04??dfb-t69aXW1ydW`qd6qH+R~O9MPCW;o>>)Mr=Nn2rq=68~f)5BqOh658vdoeYHs`3cnI%!> zp0`Mk-~0Ur7mEpdx0cF;fZG!GEcN7v6nO7evCV0ec`s9=ogOdX%HEwf{8-K%5Px3% zG)Fhm@R?rNg39wxaOFo+-QM$QFeMJ$FRZ$|eUCkfnB!fV>KuQ*ZAoq~+EFTwzkaBI zicDuX6+E;#4vjW#k7QhI7((ks0I_Q%=qtZW@_hDL_jHB8Vo6@;UUe-4dN}&dvYsne zW`Q6fL6Uk;;wW)>{FBILD9oJSBiR$x#lihWGj+l5DczbiKl~{X!d$&RQ;`M1g&M@F zS5eAB%hRvTv#xh=_v#Me#pktXr&3cqoh9?9`s@dXPbtb=vDUJ9HKI!JQXr)#R&LjN z)-kSs8<<2px!BZ`>rygx8cQP{11p4H$hg+SMs5v_QYbM$KG50$V|Ss%@ARg}tsRSy zB(#;*K7dgw4zX6*E*>!8pG1M@fx_MS%~DbJFtBmHJFpX7P_Wlfd=eeTETl)IbK99j z`6^CG4;9KLcS~Li$f2p{k4?4LAJ4N?E;g7e#>>Qw;7@ds57pRpbWGX?M-Es5Z_5`d zty_+hD*6M)u_6abb!MY*y?jf;15}J=z4YCWuGSsC%yq-;IPnf(*Ra=VVoJ9za8A%%5RYc`ir~x9 zw1BH4F)K=uZtflGHsf@kcz+@uF7YtsAr(*b)YTRYnl{Q$V-RPM60b#Cq4 z98yEql!X16^LK7-FC{6Q7V}Sy^v9qy)>mPuOdA9TAAaolDTPqFqA54$=lEdN}l0oT;DE{yf0Uz?`+z;jg5Uf56Hnn- z)h@kU7IjZrQ=x9XF8Vt3b!DKlp80Y2B-i(?XMSz|3krW-@bdJMy;6{Y6f@SX_(tB% z)|)?!32H0!fd1}V%NHX8r7h6f4g)$W;t6!I-V5kglwq$rZ|?$Pzh~~tHT#hk)CEub zl(1(DizXALVqI!^fkvcKKQMQ`4-q5!JU{4bx70S0h(2rAusrEEVR-ay8<}%7Y~koT ze-CB$Q&uh*sGTuGqSdAP1x?jZ5N<>fFU&-IC54DZ9G;oLR!`2EOgdiaXk-3vd^>v0 zS#+pG*}(b$a5MM=jZhDu53Uxatj^DpbSG}l2wP6!xO(CwxsmpL(OKvdyIEV;x6|u} znSftP5lLI?jG2S}_htEzpQ%M|DB77Dx^YiAZfusDO=o%^o*PdSK$*c$9e&l>ZcjUu zMwv3vTQ8Oc_)-lnwgEvu6+J?>DObPOps>uxmzg1N z#%EW~>x&c;N9%vgAKlK?^!DSs~Q!)Kx4m7j07dAcD-vj~8MN6ikjP_MgE|Vx< z#@bylQp%Zy+6#)dPOD(M>jAq&XGaNf|1nKkiwf$3JJn|zfn<=-9LMOx#BZQ=zN3#% ztXd93R@&kyiq|IA49JzsK|tS|K#se@7ItCZ1Ry|{giVV z7e18$0{97G^f7he``LXv4;CrkkSP;yz6D=nZh~g0GMO6bzYWC!>|tVOM$w5s{VuI5 zN;Z&=Ddlaf@V&|H&m8?X$Y5PQURU;`87Y=fa@BGOJJ+tam8DV3xPH}jYt&e&TPNtj z_nw+YD(1T965zM0(Gkqocz4~yA<*I`PR_#mW+-ZO##|#$O0;fz{3SQsB-*G6a^?h>N#)|^e0)JLG^WR;tc)_xHYS^#`B_cuPhPS4ckiSOS^T*n9h zU;ar^P8l91{GTp~9I0$0#@$%7_n>;PcP)CDC80w{(!4b_>>#&>p0t?0{eALp#rf60 zkK}2kKYc&N^O1t^R~9>~zRiyLBIp$EZ{t336W8whI_E$BPtE67;jK!TBKqd$vADUx zS-}GKVw`lAxb6C*m)@jxuc#U9LT2H(tHhZ~yNuJ0($cWx2PgimZ1TbFHY4*(XsyK| zEs^Gsx66%wKil>JTA!eVV{`YL4xd)gV*Rh!^-h|lWEdL^VdB=yYXbKiXR0fGf2kE} z>V$umo&J>Z&k}Jt2&BB3s(Kn7@#Eg?QrE8)0HJbj#Y1gM&*)_FyOl5_uR;&e3AJZ3 zo$ZCTDSxNL0rdM?sWSDFKkC5R1*;ks8N#ix_^IW!FkvI;7ZC*x6i$FOc57EIKX9YE zA7tBh{ayc4_~kpw`uuI!hIK!pe98kR) zi0AIxm=WKy&eCimdBzd~l!RWj7jCBh*7IeK&#Md>o<}Nj_`A~o|4xlE1db=Nkx&qM zexeE@JhL}-Rqv)( zo6sYLQJBWAL(C4)>Tv?0@fdn{PvDM8H*>tNm+c`6q{4Z@0TP1mn^}C%!b>$>5<%@G zzbQnfvf+vE?64sNfn0myHI^6?617|8IJVYMiJo5?E{<1>3I(yv#)=vv{2#l zuvwm5)auMr_*(x<%Ub?#Pc;<*%BWa_+SUB>Hc#LhJL>FGflet*;P9M+iX;-;SI((F z1|cGBh|@&(+F8f=QbB7KRhhyqc8i1hql?7)R9`pK_@I<@UIi58Fkj}@84EDM=Ls1t}FcWO0GcIl)QU;>T4=5d`__5rWYjKee%s+aZ}8ul8Jqv`_;1yGXJF3MP+ z-A+y+@S(rS2(HiAdD5y%ePb(4i4DI95zP4F@70nF;mIDofz0Sq$U0$sW7OM8-Hqi^ zZ&6%p=eQtLJAu6SLEddMG%ui~T&LfzGL>La0I@5$nxepODV(`SC=))na9zu;@_62r zRfJt$fY#>`d7aSmx>*4hz;%!WFYXy8b7JVFfsh_{qTv7y!UY8Y0Pf`RG=49V63S3A zLuK1WFrd(ozdQZ}B^6~Di$xarcSq7^WCuELqzs#V*u-h89Eu&FyX_hAeEvESb-sD;|rxihG{>`aErGf-T41-o+aDuqza z%u*uFNaJ5tyUtGA)NwAIN;FVH-JD(+|8M1#t`6Qw8$mcjIY5A9h?{@+O;Z~n5{eQd0DJScM^_v}iR+U=^ zDk~c3E zounsAcQ^FtEVxqRafu6NczYtK^)veUAkcG}@#x>nZ>NnfwQ~e0J1^OR`!@#Z{=NPx zNzuERhv(SN07gM&UC)gEOQ-P($Cc5z3KqZMzenDRgC}oCb?f@?CTQ2I8}fr^p=DRw zg*%VLi1WF$v1#*?XHubXvuWORzEdde z=1ILkIxPP7B%*-1@}_$V7tiPBwmeo1Sv~^`toJZR!1fBE%w|fzAs^lS>b}WD>;H}% zLD~%9AHAN(>h_5qR42b)^ewyV_o_$AQZhZCmOShFOHJe_ zE(jZLp5eWAw$X72G6uud7qsAfN7YV z!}m-SP8c(hDtxf7fu>8I1fH`!hvU7%(ZGT$*FSYDn|~9zJ1{^a7+!;d(JzfQ3c4&C zT>5}JqN_Yn!CABCsN?8?;zy!STCB5rcNE;3jMxA5lw=) z#C-#%gspSaBnMJ8`yxG13ud6&hFyq%9)0RrI6x{(?2kaQc*tLKnWJ}F+FPddWI832 zTWMH`>0~)Uv}bgAPc{uh>^3?me@tBLL;A2x1CNf52Z`>xn51%GQ;itD|L~MPIj$)fZB}<|B4@@?_6Mhj}8l|G`&z;({JD& zwXekyX4f$mQCFCj4Dr+i^=U=irMXqUbo*t{@#dNF*h(tW&$P9Z+`6w@cK~*4F0`kt zn-;^~fv7ZdU)UqRBIKLgpFsN`a`NypN|0jMtcR#Jen<%m2w8HDh@7JAh~`BbR4BiW zk*?qQ``TM*x5-?rV7Cbb`A9>p_^0#Cp+#d;Gu3VW3p6|rD8f%Nd)N5sy&~@5fEM=L zN8xj>sN2j|YIPdG%y7!2)4(FQ(^n_DH8CJJH_)Q3Mq%K!mp`oP3DLXGe>N={jcMU< z0c8IHM>>+RId63>)9~Y-Sq7pQ3wgj?eS*x3>eJ+Vr$8-@it-TeJ83#&S^ zvDf&Y=ccH(glJh{=HSA+JI{B>HxZRtMFZn=rSh&Ba&&oTjJ4zWgkfKHkX@xnX9?+d zo1VEdFN>Y_kh%4E@|UA&o}9gdJw{Mu-^`fmgpq`fMl5>C8<&nuSXfYFi+e?aU zAC2LDyFNemb1L_=OePaEQlOm_bSvZ2@^W^G#?<4A)FTN-dZHO}ueqnO2>v&M6q%8c4p!ty)?}*c2&hl1; zXboYW)j5TvNb$?7#g_ilF9kIvnCr$)aY<$}xDkrM59x9bYwRm69$?Of6kf$iOP>&w z75Di`%AbT+?D7|C>syvcm>JwwrpcE0ct0`o=uJ5-8Izk; z{eH{;en{{`)jrt-^94$VPwv;K;~866Vw99r3HQTuvAU1VE`GXJ#=dwh9Hf8(oL-gp z6lQQSv2&E|?}40dzhmDvpSH7PrCyS>e`dALYOR~yj;{IHaC&}zM}NpH;KtnSczoBV zujcxnkLe@-pk+dSBz9%Lk(!QKXoyRFYV&B$nY2!0e$e<=-_=N5i3vZ%NrVwXLns&Z z)>pD^Kd=^gwFZyGN#SpWl|(E9pP*fxfYi&_%y>ATRVj9q)T9@I5tzLG)#gq}_Ja_b zc-T_e$?I02{~aOrZf`1Gn;`=gQ0%LolYDkje{#RxEYlX}y=71erG?%I4P$eMt&|NP z|H(9Hoyg+ljrns>F^u8X2^)&qDU_UDG`*)E^6e=5aZE^g?LUL!jU~iE?E2pSj(m() zQCZ>+e|Q5EvTPid6-E+|DSLd9*Ct?C{xNdce)v%5#+gO!p(A}OMO`0d8{ZrlZS7^p z={`!idnGR;gY|T{!JIovocAdFqmM(REsNnnVX){HI2G_^DD22_>cL}qo39mBvjZ+=)jv@;Jf%o zzaOHFzPp6s3UlrqD}8rT>rWA3T5IIIGgLo+2Kx?1`#Doke(UXOJ(+3+_4yU!zv0sp z)fx4jGdiWGU%9gL7ZfN81GsUoc?&g`Wd2@QTkFy`jIwxt?PtP&l)?B5hF*L}khw;=Oj8s0dY1uJiFA zUE81GGzElfNAhO2|5VEJDt}cg$!SlNkW9J6&+T-!zETIFk7=&oIHM#fUwh$?#8jS7 z5z)@ljJ?ZJ-LYgjWiJ?JNr(a$%J1Frl^p(_Om&D5M}MN*vB4iyP#T8%roUcZXY&Ty z6{M!d4M%XTC~$$v;Pg6;vTK>ezg}|$)l0{ce^CR3L5};MsE;ZlVd`i+_K{4Eu4U;h z?W0{Ci4XR5)1&T(sJxO;eQmsYkjjcojnf2_(VK2a!T?@&(m>Q|K9!BqyEzZDcV=cM z!_@>}a5T-o?D~6V&kXv@p^(r$;GU@QLI&4p?(ZqP7D*8;iIdv*oI_om0HQOMeetKu z3C?L4gNg>33Qx?6Qk7%|OLgq9^W{O~55I_ZXV8~R$Ko?1Qs|IWpMvETiwXRdxrRcz%NET%Jl#0xP>03c3Hgo-94&Pk*{~uZ#0}ha z_cabjX1c*KwTghFPK#s6rm+eMhu4TI-Es>mf*!~+Q_@zZ!Bos>W-Q`#!M3tm&*dfI za##Y#=$+Pw_qd#k_ca^E+Uf*9xnA1t8Z0!BW+jR8C3CDaQ}NfP{Q(PS7mGlU07T94 z=S}GG&)%CZRkOofm?jOCHOO~=`tj#Bm4i1>R)IoYeznNv-wu;F?Qn4of@SNz9wReY zWc1x{5qQ0~r!k-Fs4`(9IpBMTU3v{!)IPANb-wcWhKTlv8nx$M8ShD~-iFBg?F#Fp zW#DjYQS;qJk-<>uGY&P4`ybl=Z3z41;mil)LVj?L9e!kk4Tp4J>uJx!G+ijIy~m+W z8oQ$Sp0~J-JwF=CSp27EG#O&3H23~Z<$hFKzDbn2;CxAN&pD?wxt_fa4g`YtL9!s&^K^1+N!t1Z#MGuOD zQM#Vp)E@%_dXC?n?2NC+Q70CWA264S^X5UofA)qLn^C#?pDA6y-E(J32xUqJaP zTssL|`zKJc%z?S)KhJPWhbNH9>s!6T0TBLfL+@CI;Thx`>es?JaUw2Lf;h`}o^58* zHig~h@!AVih!-)Btr6F+BE4yAa{jjy7H`}*jL z$fIAQI(GP%#d-O}syy3mjlqXYlzQy55oSIf&5e*o40ImL+sz<U8jtnbSwXYt>8{FDnl9}B#v|Cvb|E?6Jy=X z+)sBy^GwYA`}uD2bCp)*QExw-Q=TX)lLK61%p9Owm5fR6zS)Ru^k6BaBw`nPdA4}e z4ASY(es=&K*nlGSO#F)?>4QBQHL1+~*2vIOqg6dcV;9Y^Dd*@`EmKj2aaWqU$m)$; zpnpynXV}%9nPU5%JYzU|?3iMmP}Sx={;Ta>9Vt#DU@L9jO0d^sQnB0YNZvt0XHlkW zo$GL^3DvwVGSbr9#4bhJ6qrwFz01^;Kn|{8i}6%kcv<27J<%N=4SKMH^$Tlyk+y5G z&+;q(j|M&yoFAFb&2Ix(Ny5L#=i5E11Q2YE_Nsn+DjA>(2Q8#=M)$k&pPv@IGvwt` zPcV8it63yRXV|5+B9krC!GY7*5NN1G*tG;l3GW+b=Eqcf*B3%cYi?lDf8!VxTEh&> zyIWm>z1HQW&pfqZ*T33fVg=x{imnR$gZ&0~RnUMq@ z3EJ(6?bb! zH?vOQX1Yw!?8G}C&d<_Js+XszkLs{4OM6ei@HQnJ9$N!)gYFg~{_o=bLV8RZuJPGg?Ml0u!z7)eh~v^%u33jm#$`kMxptDz|T3@Kad0gBA zcBUQ#&ML6<#!i$~)>OatjII6d3JNIt`L`M%h}F(=#p6o2NH~^U zSRS%IU)o{c3p}9ye&|v0p@Q5uB~E|@m%dhAMqlrb3~`SNBJcbL)ftw)+&d;b3^|Un zp8|5g;%sNS;d_n>ace*O63Vi9GJMNDdMEbQ;lcnYJL$?)cr2G4OC?Q@-;3&(f=e&e z*sz#VpMijyC*cUCM~?fDG@re!DL!#GXf%4NB5o%di%$-bOyMXoklT(dv&{J>V5X1T z;03}Jdm#VL!sPmG?0>ucv%)OR^rx(dob^&t%cF>0handO*KR9%c|_MbYu{P%Lt#6sEMSvt+!NL40HD2Ldp z8Cf_%X+9jA)nxJY^`7=X-DeLC4@HM9?MgC}1D$nxQ}CDL`+2bJuUw^;mXnQFn<@W0 zLia@7WEoV{xe{VDpV?bZ0h6Asc%Ee;A-+JKg9L1$ZKHK=vVy#$pIx4}-`RC5s8-j| z;~KyjyD|LQ)!f{I=t>;6&Ns)5Y@EJRwQSVrE7Dp5U;nICN2O$--`d@0_YRe}09%-+ zP(`sll-)$Iyr^1WDQ&_d!$|Z^GOiD_(CtV*7`9Q`g zz|Xrc-E{vRP$ZFhkcL?<)ahJoqt-+6seWtHEYb0WXjCvoS&8G>U>;vTiUkF#TJ6LJ zk3xtltz2~iA)9WXKHf~^ROcPVcpqX8b>srB=NjI}-yQ|3GH_T2&YK+ZXbz0=_ZUu<#~m)!cG)M1I8#ghmBfzFF#QK-csfjv`I+ zLQaCS#^Nw}3x6{-6jJ@}RI8{qS_*>%YZ*+$b*~!^kJ+MXGttbv+O|L3ccm{HnN5$r zHhFEWz?WQl-{X>`&c(a{c@dDKoT+WNg6vsbz*H^rPQWc_U%&0tGOWS>Kzd(^Bh7No zX0ZOONiy{9Z-3*2EU54!TLuk%Sa;kFQ-p1D9Z4w93Y)4WA%iQ-gZ#|A*_*h@2Bi&L z*G!ld39cvUEhZt>)kO;am0HRiAKpk6Ks{#X*FjKLlZVHboC-(jy?j7)DWd$so^w`Q zUlgNwENu8t6Gsep#sT!wchh+jYPuBW47p_)bWqk5BiK(}77p9%9nd$tLsAZhOaos$ z11z&{xKKiQ;{5Eoe^9u}dCU36v(PvZfV_E~RRVp7Y+kuXL_y|(wq=YFz%#84EW&kn z;!EGT`8!Jnl>@|wK*&o&m^iP(2^+reabGd?te$ynFat0=$mC-T(!3evXY~ZYY;PxG zw;}v2b~abKI@h3rVR)gUyCro%v`W;cDEGCJvdW>ZaQe{iJhVrORGQo`H{&}ck2mc~-n~%z{2kv`=<3P=4?{4@yeDIAl3jX^|pP?>|!Jy4{Tr4c%$M zW>yqU4%EusQLV85-tPhmvkDz4SIa5sD7luEJrH+!;(td1H~2gnpLM%3o#}G}z=}hF zXx>uevZ}{-5B7dPH8@QG`ZAz1FK2mI$4BSnYyS3@=5K|Lt(}uFlu;Ptcxw-w_j660 z-%P)d{+)j9x23S^N9{%W{o3@I4pIKAb*n-5YQ!CqXgv>daLe&0QPS_&<-;KLsnUm( z=&YADuI(vXxNpjOW^jh2@Su)6RL5%eHQckttQIQ7PtbgZvhm-c@Y?`FkG~^~%jzP( zJV-lfYy||<55ODcEDVVnW(W-IwAYHy7C+tyy9&kn9b2Yo(7v@KBjfnZSKR408nwK`OwwE(WXXq6H^Z+p%vR_W8r?jr@j^ncv0#y6&4o z=^anNBRju*0;8^_N#~Z&n|tS9bbJb*l`=IVoSJnwn46D*WX0V&D8x1LBE6l7!FW+< znS8lB>(rC_w?)GPZA||N)~rFtJCC+f=t)d=vhQ)o|yt6V56#ey9QW-tEEzE8TUf{0br*cCvR zwvO?16N55)q4ECXmr&|#K_i$%>Hn0i6?|W@ZRwW*o;lWE|TO z2PcUWjw9PS$H+cM#xXzN`}g|~&b;sY^?Y8};}I;Nmgy6bwQO#H`4U6|h@T#Q34F@b z4DyxeG&Ue14b`IFF9Aw6`Q)iSif1@7ErV#pe;Z`St!X{&N0{1=YiMdh&U*K49OC_G z*R5r4u7`#OEHa%z^DkH!-Te6J>&jXwr;bBx$)T0ly68T2IM`-P2j-Dn3rvfO5K4uw za=tBWgl9#2ZkX3>~8Kgn)T^sf)Eb-R;N=B0EY0O-cxWXy;CMXaOyKo2>G z`reTl&E=lB3snRoJoBR8eMO~>lKREII&DnJ1Af`@^*1{3Ij_uK%??lI*JF0)9R>o; z&W#wKJ1;Zb?3|Qfp6${u`gcub28oSxp^g0(^`^|p=%Jse8_+Z->}^Asy-Bkh$x4WA zQLjmoO)KR-kMG@aNRooAW%<%NuFB9X7K}5owt$IydKL==9YCuOTR+Z%LzV1f?}*Pn zt)0>_TW;a+RB9Es9e|{~_^5=YF}1YHvZ3nsZ*pj0weQoGviVtm2AFZ2F;SiPjhJZ**% zGq$WeF8i6Qz)M_i4>tCJpK0s=LwXoZi$~uq6Q0RzUeqf*J2b&BtcHKUJvdIfJ-GC1 zsq&_dP>MHIwXYyS+*G1Sye~JE_2d(z)U#70TET zVI!YBMj2~Ey)&Mf>#!Jjx+9Y|E(_Hk#+8lAJlHCd&W|$y=uxr({?=W`R&zG;3wV2E zXvf@AD*exLvCe@Oq$5j9hvTdltolGw7ltVVs}-h|lsV5pDh{O%JFI3S-)}*pfVhR) z$f*;rh;+6>_A zqZ8^B>4HJqe5!<&@voWm(q>3rr|IpW$jgH5>4s^ChYaePGS6^%m@>**qN1@8kv&!M z$BUlsu>%=4uOlsm&Hp_`<4$(bC7!hh;yX&%giiKS5FL*=DfV@8e~|VnQY+R$Mk& z*#-4};l_2AS*bW18O7}61u1GOMFw4TV*(g=0Z|u7M*J(O`cFGP ztiJVp=y4LWFl{^9%Ff?aB>ED3?dKP1!J+AW?X9EJCmvjI^dc8jp1K}P)TaCE^njWS zcpz*j%<)~?Ot2*c$b@`mO|m1qb%$1%%-~bK>W1NV4hx$n*Xom{uZrJGN4K)c4+%kA z*v%Whc#E_r*mrhBY_l83SWn9AzL zsB#3+Igx7=P8*kHk!8vSPiQW522q&uEA0o$ejTjf(c`0@<9%*aTaws#eL|JtoloXz z!r4!a7!u3G>?Zon>dNf1L63qqDsizSl|ds^A$Unl?GM+*U^zh@*XU`voZAc&s#jF) z4KQR>`6)Fpuz-m?g+z_d@FxPU4?rmld{Q^P!u^uDp8|~kh^686U`BywrBhdg_OG;3WaeNfLZ|ZdMWVKB(r$2sWWl_n%*kUo?1kTHKG8+64we!a zh=__=r}A*+v@_WfQ`b;0U}nPA6Ayq2!KI#TD6vLk3pCftXuiL{50RI_ynEtoeP053 zoMqGUnVM^#VDTPp*qvaHgPuC_Z;gZ1BDX>VKln(ZhBQYq#{N`~ z^yOtjV(jxGulF$uX}5r$;9Pp*c?GAP01qlNdB+(YCQWPh3}>KM@T!a>K#27d zctEg>qt1$T68ZFCUf}ROm4N~paC%6Q8Q5j^$^>plttYGt_wzw^NJjzm0zaAW9SrPr z=XVqz5Zw#cDx(N`g_b>QnFxj;yKVHwkmp>Sk_Z30!~*haZCOzKt*zQ+^|F3(v!k3# z7y$>P1jdjNn_l_qA4)#;2Kxm|-s#Vz(@6fiq+2B1E}FN%Xt!35ajb9EsS(kfO`u0v9u#lfGY(S}YSm(Fup+_SC3DZ3gfRUri--%9@-L zLqPBy`uykkwIRt7ADzahJduwE-jMaXwPAT+Zq2ojmMiIV^mE3f%>Q*Ji@Sd?xI>4@ z7BoK(T3%)NLXr^hcmJHI#(d2XW~HcNh*Yf#wCJ*Fdf%NZo@Ct=>X0_n5*}tOVK9{m zlYn!KO3N9;YkVRAMlQRTCQC~KqWF$cg~v!(ow1j6jhEo7jfMG&_tP(KAXJ`?+v(p% z3k`gC&#->fFc=4^d^Op{NrW}vYPW04+_a_krn?J%KUI0YLwUT~`Se|^o01)qBl)Qt z<(zwPCiSiBmGKkR=dejs*%d77knsH9Uzi9ny07scw>M)3!kzL7l|a4)k5hnbHLDu$ zzpKS>sQ3u9t1zq@Nnm)}KmG4g6%*yUgQPA6XdIa}IgF0kJMOL??!wOMBCk4kMra;@ z5gPdmQ(HxyfBv3vl9P$od!iAZT3qC!CX%`rHz?V)y}|DF`2IP_%#Ou4-@Nc;=IFwP zN?BLe#CH9TCF(X+zEFv*cDr^YCNXI{S$vpOI&7F1%@?htL%L3QIff-~lkg zHKfX@4jw0p*yIX|^Lr=@am2-@opNJC+Z~7G-evtOM@{2Z`X@Z4pR7~xw?$uPVuw(O z%vV+9RNal^N7g079X3y7F!k3!UKb3M3uG0wc(4VZCxvgS_Ckq)W{tL)7R{O|?1@`J z9zi}_t9=;5cwz*jjm3nw?(s{6-KPD;2O@LX&_lUgX>mw6$B&jm5#5DuQ4{_y6B9Et zUnX`qH`FYzXxvHI6_h(4XJ7$M4H%NvZ>cd*SIF;f4ox<7sfoL|bTKglh~0Oj0aGX$ z+dpQ%(Xl&teL_*9`056b^I>EGCj95jgj%kxBBe16U1Atgw9Z$u7I_;E*mepqhno#m z8{w#SukRkkO`3)E+cfTE04!sSuPTSQKWhN0z?-b!+LiMd&nw?c>3^S6a$?6LrxlG& zj9;A^kb4eWWBr2d5Ec%OcH2JMjRzogUguk9SE=$p@;*?H6$gPpMoFHu5`&e3! z@c&(Ut6@RN7bvI7_vaO5xJL%pVndzFu-y7IG0CvRdMmZyH{_&>`Eb4=J;XCzWu-!! z8;aa;Is+|(3E!QV3Y2&bTb)wZM48E**b-HvA{>mZU4Z_PvZqCXpYXWP{NM6&k;G_s z8Ad24*(t5IOc_VC4{21t~8NglIn*hfOSVAu6(Js5p;B&)-n1 zuyV-ef8?N6)Oo%1BGffi08GUqd7pI}_p#X5M2Sxqrx*U$AhMQ{nuH^XX zxVVV7c?WySRjvaQ+L!$=8^WUTB)y=Gwuu5TX~o1gVLLNLe7qm_GyIE_1p8Y=VveKO z?@w0G6dbelhwWKliP>U?cdS=@KM9u3InESFPp?HYUfhJFADRMk+t4P4&fdX%i53{-N8 zFW8~X4HTY^-LxnzM=veTi37je#Y}%gX5yQeit@RlR(5(K{INPq(fdy z@OzC54rv&d4(7FSoaz!O0q^ylET5zmA1?GzX#1jXDRgW1a`~mzYuubVVd^Gw24RyC zL?5qbSx?3kH7#t(haZ-9d4}r;NHyn=`|%m>~v$p-z>$g;5V%1NKUnL zFmt3wdz%HqOv3(#l&)i+vZ{9CV$=BgN!$+dRNKqmu|9Dt>H(z8J^@q2O;JwVw;9vm z43uu=Pw-JVb>!A*GHz9~{!p`#NsWHuXfvo5oFduO8~Uo%kAGxAA)0NSI2P@Z9)k}( zG!FDHM^i+4xm=6iA`zYuwo>+1%@pkfg>@7cwZ^j9C@#yg6W=9ULoHnmZHuwRzrb<1 zC+|1zlAuoaaNf=Ji3{8mDBDM>wq7UOVTW$_VIj~PRCDo|DXL-(FOF;O7UuTy>g2WF zP_Mt~^uiy;E{gw5o2=X~U*VDGcNq68igBt-o5=f^ zIF*JHp)U5b<41_j^i=Dg;~;0AzkE{oYvp-CTEJcgpi@W?X1^fwy}VM@h%@vkxB$_E z^k6|rQOvscCsOTCvAg-LAROtMsZO;@Ft*{ zxtmr}8bAh>)EFCTbWND|gO+az&nS)580(y8I)u;5eoX_@z@u^vMSF?4-{337j3OKZ zt~*b7N?FY%7BZL>TNd}V8s>zTo4Wgl5w^oG@Q%U;PQ2p$x4>#{)m4lYB|?)~58yH+ z>~t219le>nZW^oDbB7vg`r8}&d_j&p`k~$#5)4(ZemeZJW^sO`Y#LjJkxc3>oAOZ@ zj&;-bfL3jn=k>hPaHj-lGFXf$AjCI`%4hzx(Ti3)Q#LO(pRE7z;a;asnai!x$>;IHRW-x!TA2j^P`hBK=@3_-|+E4-M z(eH`TCj&SWK;(vWzO`P&-_bSM^+-b^vc!>EZEU8&j&NRQ--8TW;F_i6Hbyn=)gcUc>^r3N2^BjGEdu^x+YM9XNq`{ zNri2$9aX%s*6OC^n0vAXIUcbl7|NCx{b74wGeG(F4@rR^BE-O=t0noby*gvC6%HUwj$}fZzyX6 zFUxdZdEo1Bw1u0P1zWmchpe-0*To@;qZ0bG++M)5K8BwKqD+u}R|$4vB=c{J0D0Hv zQ$a)ffEFQ_3szX%SA54)nygP^SQ>gWW8Do??9_h=(3+gbrZ?A3LO$C5OS^RM#cgaOu+mwfM3WQ~;+l6qI4R-IUivM~Mr=ki7g|fO zMBmt$=#_>AhDQ4NF&-i!A%}-GTCf`9$jYI+$Y$oC7cKD$dkwDs>9T}CKGmNcb*A@r zXJj)k_xgNo5O|k&PJ3DR1=+H4)KC%hX>+&`*LB?fA{*RSX!zlAhAz&;tTT1S&~(*5 z7}exFqvMpB^3p^p)U0t8+M1Uf&<&jXq*z2*ecO9AZqcgnLteXNedlhwmvyGf_+;4U z5~cU%b$vc`5n6-hZJ6NXw@!ok!N)g)cGKEM39Ty2MRdgSmJjwOYyLk1!ugnP6l4`G z``+xP=T#^qVO8yA&5S|S*8k?WSJtXxt*e}lBBSj2{Vsa7>Gk`WQ}g($D*qezaJn&D z=h#`pv5e~#D+jT>hkI{KneaqcBQMy3{m1qpFiEmsu|lnhvJ~agZABC#aAV zkAZr~)h(*@1v3>`KIO%IF?Jsatmq7X269c~ZX;e`Te(p$S8Qvgge|WX*?mf#HaoQ; zoXWbm-ZbpB)r(8iV3{g#QTa}T%UNr`2*&#Fs$v`3`j5Zuzy1aRZHse+N`s}EYn+0` zMesbill+yhAu`oVRaFvJmD&1rqamJZFfX0*2~;b7&Gz&=4F~TVgL@w}6aJGeU@7`a z_ImuR^&i}!#zkVHLjHh;KeUo#eU$NaIV{_(orB~zKdN-HoV9o+^gZ zNrgY6;Puiw9EtX$DzCl(D%mL9d%p#+i+P6+osI}?ZXyxqoz7Ha(?Gn zkHLi(EZ?FPP!Mu;vD`v5p@7t3E93XVuWvW5o7ov%dliy3aVh%+L*U-W%c^(zAXwhO zAGB}{rr6-6ebPOiTWb=XA+i~ZsEM{q0ReLUF~65XJySl?KF*oDu~rmwFZ^`?ghpdc zWmx!P&(B#A?k52x>{)19rBc@FRrj%QZ}+sGjOzJEPS6&46BI3ST49uT@F59xT?MOh7B71btGcuX=b_2K zT#eMe$vf>CfyK}rf zh5c(>I_rW}Y-!hcvx#cUE$FMp_JS6XqAaV8&+JnhJ(S;YV`gKR;b}RML^^Y2h8Y zn>h%e=7D`+z?1QjNw#2(yCDOkIuIDjHUVn4bIEukyP5Gr-IOj6CmrD~c(Cu#Vxmv; zUe792mUBpe50hykpLW37AlVsH+QAp1{CIROKxM7K<%SAP!PQ+@VP}og|1PbZdjP;| zR7dA}Yv%ggKZbk>P`@npX23nn%`%#H%;omY)+r87&U!$++-J-JGH~K>(U(Yt{ii{W zdif`7;vPvL`ciReU9-w-Zp7U8@8`c5i-Ra_AHy_KSf*6|N?chTT%DeF)q5VjQkweX zjfn{{fQjbC?X0(^p4R4ovA3?fWws^%6D-tk6Sd%6ay&%@PM=(LpC^pqVtZ(|y?Gvfx>A)u$;6sH4~X@4LwANN69|PJ#p`%w000Mrpb%=@C38b!}H>cxopGmja#4 zg0qpd!wWqWMXljt=JoUvisHfdNGb~3)nNFt*rU4-)^RCr@Uqy;G?@6c`45;KtVT=#a)uI=yIyp6Rd?-qxU zlYCeUwItIQ4Mnp==kzG{8K`L5EKs6CexvNhb|nvk@;f){uS4KZ#)D30>2{HH2bBv` zW<3oXA&V=@#zy!88;-MzuO(-#6n(K!xSgm>!TOh|9GnXV*A~S{vkj% z?T@}Lw= zuW-$~46}|ipz_FsLF}|CChsD-BAxNlodOm3;KG1f$6_nRf=2sX48431pk zm&PxvtLcbjF*cUS7O?Zofhkc8Xv;7(gS;_ej3RSA~cu=Ja!W8ChFCxR@rF4#{(Nw07F=p{ch8+`%`px4b z&EW<1y9tcTAt$jmdkeZAK{Zvb--<>RJ5f&wX{)!H2l+Xu5onuM{zgpy{DZ)yQ{xaB zjv4B|rAcH8pH$bBA~z(i3BPf4IY9v+l{-xyQupU z01r!hNjjNyx|;|fg}9m-xaS#6l6(1Y-OrORWei~bw+&Rdh7EDsU4evSAP^`ITKuba zm;ncFCiW>)_N+N$$222R++cnt_JMC_FM%HU5n2jlVKkyOGfa|qaDZ4m#~p~CRTlU0 z^AsBxaU5i4;)!@V4cBt8Qt=DrkU&U@kTB$2vY7kv-MEY2gxa4)q3AEyulF#mK-E8# zSzJrSP?(&zJT2b*3KT{2ij6Ym#guXFcdxxJaD_GmRgVD>7ysBI8l_+Umj5(Dz$Q_% z%yGlAJVWqUv`LU;fwOYYjZ~Q6c&Jt&KSO$w7SH0y5~KS-@vRH#iYB;B^4UFw?N=C# zeJEN}c{|redM2`;-G2Odz~wUgXo?XnKv8l{%G>;XV{IMV%_4 zpEP5%iM=xnvqi%;re>Nuu0Axba&!P6?s}f2pWN|eX8a(p@IkZIOkWVb>6}>1c;-Vf zI?S1X>JYIvA-PMF-3$4w9oOLmx!lFsDnh4Qq4b#$F;ek=ml_m}_03!qN4gKw{VUOa zesp_rXBloDT2h<9F2p8nA3I&|)PRo$r^l01)qz8svDB;{^-BdL#wPXbb5=jFm76(r zp7M4HRXPNWlNtuDtXwglgHGMs;eFT=e)Y{tmconiuWGS#vS}DOxEwJufFA_dVzb5*gl>6YB!(Vw zAvpHL9;8#9HX}JEfRSL!kukZJen|xxk!sG%@OWwmiDeoNu30b$cIQPU1Lh(B$|0`^ z;bIo~H#L=L6C{~y6fJ6_GXPr|_G%y|jR?sWnii91T2vQ)FQS4!p`%~fi0 zrI{b%(f-3VxziBFJS|+b>6AHHCV_N7TBPI2lP(~-jQ~P*@1W6LdW91E%$U3?6XR)< z0vNAMwN3C%&n(MoOlIv1xV2JtWe<{m2sSJ_yI^jXQ)BE4y+(E!EPC*}9%=yptDGCs z=(WJrHSU|DR#XLlma`iP9|>MT#I4k_S8R+k6e@XX+R4-kHsWNsx8f;M(mu%j9~yxG zjpjL{pKqQzJa5WeU9#avLO`u|U8PV;bv1pNsw?;{mUcc!N`}yiW~3pGCKIXNyBeYO zwn9@0fVU^qo#@AazJ}JR1h5pSZo<6IYEx%w1$$%ps@G*HBr?9qk9VLpCo>G2;M$H8 zN)sh-3sljBkbi}7zvGltk>tqKPS$MgC&;RJ2DvB38G4$nrML$F%T59z~w0@uOi$7tP$793ez_?}J>N2uBWmon z?PSFVkuNWDxBkU4Kls8ulHpv~0E(2?8*d)r-P$Up+uKme+4wyoH9wa$HK96tKLfkV z`eVCKuHS}^HHb?oL8>66!H9>!Pb|;i!TC=Pbnd0n>Xavzl4l*qaIh&s|8E~rn55g+ z=~)0u>gkPuO3X(WZm&l{_4tYv4NN|nXBlN<^m_6UJLk&!VA4Dv^W8H=z$M?Mx>QWl zTMsdS85MJbz&<4qK!a%cfT*ed4CgC3Gog>GKqf6Ecbh(M$TdTqD!z*}q`$K+1MS50 z&{UA!(SXfBA5g|6EIGbB0M#(6+mLk;^V_XyfThhzCphF~zCj0ax(XbUF&mk;32JU< zONZKX%OLHKm0P1Qui}3$$lm+J$30*yV^}hgP^$96CiQQd$ZL@0bwo7)uzn7U zn?%6o{6rb~e(V^j`ox-E>v!e+c*TW5>^Pt#d-5ofk6i`xJl3*W%))#v)V^()l;l%q zB{kJitZZFaoB%}G4_3r5EZ*H>~^u#sJOK_PRO`_cJ3NR z=Kx-$Imhp|gOP9?To?)LpKm!2S9l&pvBz)r8^OJ-^Mc0*0L$FZRs5)<+D}KXs=+i@ zle_J6cfFr!{_zqU%^zn8F;9`sRj}+XXvzEJnBt<=#x8Ddvs@N3f0$>`TsMgePATpx zYFP1dZa(0T{of^ituexg%#!}VVtfy$qJA{n*;6DgsE3KFg>h(|+~3v)h$+d65JmTK zpRdH`|TO;T~Iwaz-}$orI=p~ zn>CX|`xOD_t&C>&c?HbprGF$G`|6`^?fQv=niZ<}f^r=zp4dl(wfB- ztQ{v)heVhRn|7nRay)oOrqJ!yB9~*!5`G1$skS^QG_13oep%)ECypK;EY_#+?S=wR z)x;aPQi-wUn?SJYAJPbgJb?f7?UMvSK<+Z)jA%c2zdH4%I5LPj zpE6sv-CFPxZC&6YpTfUFg&XnOV85A1yBH@%95Ncv2Htgs*lW|+Q`02;wi(h{9RKEx z*7GMK%{1pn3RB^UUHVJdyO7;}`|invesr3cY8-@@Aw_e zUBf9&411Ml0C!iQ39JN#`DknyiU%ReT`S5|!izS5R$~-V&o#Hv zqQyJ&I`be7!hYjUg2j4!mW!* z`5(><6c_vTe&3M@19m;EI>L2+M>Bu(#C84r!Vp;APr358>tlxYimiTMqtvN>ASwvB z6x=>jrhLQ9zsk|d&OCc5))tw1iW_cs-yj>paztpdUa{GMSQ6qyQVYZP zMXYn269-16ZS7UQ;0`}V4bK{um#*ztpwY4=Nf_1M=T=o{29p-0`~kBva}yQFc$r0} zZJxrbZF897j%B)hT$y0^s3|AZqLccVzyU;@?~|jqttXf-rQd;y;v{>TG+z23=GL1a zbsG$u;MB>APJ*L=1zy36H`*K*1X{dHZM+~2gi;{I09%cmH1DazFLI`No_8id(oPuC zPJ%{g_ch`o&bHEwfHkrzmm=Ib@p4}=U_g*%tf^Drsd=|GBlIdze_cO1ls0e zKnTxKP3(47a;6B8d`B3*+j#GivD^U^H^umL8kU-()KO7f?dc_5!qFIWDw`p#$l5;X z{n9AH!bc<2<|AE>m}{cwX&DCf@Vq=q2r7iTUezvRZ&BqPAUHAG9z*l8ga-UlDqrorgl^AW9Cn5pz8Yhxb zVn=jBISq3z%q;OE2qq04Tmo>n@GguUab zc9alJ5ZBU}kb&Mp0kr%$J0dspt=>voYSw?$7~xnHV+;mSGVS$&azm3FeIbkwGQRG} zWbBR}3av6YVUuoliL-RH(Z6dYIxr&suo%!rnq=Eq7Ah2k6~J*fDXBqB(G8UC+vf;wN7e^0pKUqYj_Xddfi= zq6t23SOfBCNe$S>8ccGO+$`dVF>B83BU%4WgGIv7)wVjJH|4OdiWm9OK8KaiKTi&` zE(=?|Jx3%DMl))dR#Df!FI<|$eqZGBvPa+;$!nOs|9>3>Ei!r>g_o^I$&lgcE0a;T zy+nu(TrI7og`QZ<$#sNq102F&{jC|~<27JmPlOZ=_gNR;x#05D=DlF2+Do||^%g0S z7tz{xp%3DL^E}~~7H>W}5`+X;UC*vbgDE~TTB$jRPs#n==B zAw=iANmYcTDeHt@1+%J4jxFpUe~|}*AqWDF?B-Ns7R*U}MKMd1=!SAmi2Y|Ir3IMX z-2!ly6~op|T}Y$FgbSXj`nszNW~ea@Fwro_`9S_;3XVRrbC4jL! zC(JOVOd2v+zH%euQBoq4rCBkguiO-CDImhKT1xf@ne^*((Vv2HIAQ))U z13Q);UGxhnIz!)~`Va}Cm+r2!bGO7vF?ZtNUb|?-h`Ms4jUm3(%Dp}+S?4e}**&Ng z2x1vrUH89aAZQR;n;*mZO6-A;!)-y^EJ1INQ3oqLRGv`Jx#4tw5{6$R<9lkn*k@`$ zi?fa!7yLPnk9NG;Nsjh&^P4%|jlb^D_B2jTmpRLAT84#oeUNw`di$Rb?X_9&*-Vy6gki$%bC(QM<>8K zqg7Jr@MPFu!(MXa@UwTY*Kh>gj)-o{Lx*|$c?bJ^2GCz`c;`ovPnrM1-C7Y4^Ht}q z)6H`w8}U}Km;VFZH`Oa~EhXOcEj{l(Z%0H_!r$SxA^HBavnZCRiJrS!beoLzPzfAV zmJl(`wGh$vni{d>7-8Jq+2pnU6&1qgrlbWkUm`giN^9 zUN?T8y|f1jIX#R$uW3FGGL3WQYL>Y%uS1T&)4xbwt?ZWk#D2N~r zA5P&E*eOB9EGYh73NX(k&PNP%Y+~y@^GphB9K4=W-G7dE0Ze~?MR*ESyF8ul54gi5 ztJd*64}(6LN>SKdbOcUpMW1?_SDQ{noFHyfPE=Yi>1@QN+F@>lYq`mSc)DH7m`M5n zn5Z7j=`oYqNHx-pU}1ijp752dRTb@f5??~PRutCk<#UBWyR>gbu~Lu2mLR0pmE{cT z>&q-H8#1?Qk52q6W@7Oswsd7gbX01zxY@}SI;x0+Z?{*8M7x?>sZJ!P3zlb^eX2$L z$_K$+CA8AfJ=dZ*&(zM#q@e;{6b4%gZJfq!f+aji{GFli*+kG_gxThEDinMkpiUgDA;~L z;l~x3(Vgtr^V{a)wiHYM$whwYx(_iDgy!SH?FJitIiS0T8dEIh@zP>rYnY`5ObQVD zT|cLoynGZdHuXH#3LIb}W?7N|r^Ba9sq|SEdLBIZR63I~_h8ONOm+Wd;7v^)Ap`Ri z&GIdnm_(aN88mgM#x(PGkHli+R<6xbstQ<}-lku9@s0++cAB;)dw1*9eQI3o?DToM zQ~p4aC=l&R82GqRbRVL@?Os0vu<_KS_|5Ra5$dPvyL{LPfj@tbPJ&u5Mk2}F)@0_? z9Ys?b&7vyeIp=`{XGzn<)>n%2VF;qk2=3Gyxis&*Jprl1JSQ(y30iDw@c}n3wf|i* z!4XkSc;ByGt$EI=yBCsFW+JBFIp#2A;STu-y_-1AnC@RURW1XKlxX|~gKkDX$wtF1) z3*q?H)Iq!VnH344Z%uLf@{+>rNS>JS$jPfmZ$EY{Huh2nyaegS@tSfw|GQ*1zRw%% zw^e6hdR!;;Q~su#0ApgWOT#Dsrr7FN4}XrAui1OvPH{1@4bK)gFEh+m)XR3V_s=%m zTQf8`Io5KCkGs)KVFk}3cFDdn5tpG>L=gxKMTtG3HE2YQ_6=QOj#kjgU+k~bpngdi;f5I z+}1dz4*+u{k*g)^>w?{UzB7}D5@s+;f+BTTUka%{A)%w#P~^IHB}C~u{$mTGd_6oe z=ZjRWc7Yn=q6VP4I&X%{>%knJcrfRHiBec1y1MK)7H zJ*up9@z3HP=i|_pEOg|{XxN;QUm)1u>rEqQ-rnJfK->FO&eAkcSgFUn;D40HHjWjv z+oXqz!Jzy~p?&J6NkF!(c;KgvzVWJxBt_M#irF`zZU+x<1Y|!QeUoLDl%Lz&Y>|TC zFmBFjblR0d{HmSAPD^=Ee**m~E~XFUQGVJDlqfY@GdE%X^naIV9M2x%E6BM?J~O7w zj`LJ4FNA>o)IC7tLH-9Ae91BiNOkbII+n#tZFzxRIi&R$@?R?;RzI_#-mluk5(-5e z$&P6VB7JlH9mnbBsC#6SV)vI2?kB+I1!DtU2coo4*$|gWwoMyckn`=oYCm!!5`$_g z`RJgDz_35^*p6T39xBC=Mt|Zp1&f}SA!#;i2^Sgj$?&a5$$LpzJg4SY zn}Q)l8f{b%QB;e20RsQtB1_F7QmNs<9Q(`yw%L#$=}CIlmUnGD-C^a+Dx(_*w9l4H zLG}$&y9VIK{ghz_n>?>l86ZT$=$;ooHDwmB4v6Y|ST7FU+^_`oS@voe>l*&cJ2dhC zH0!@&^6*o4SwO+DD`$D>cvkq?EUEY%ik=#Is^N(e=t#r#Yd!3C!|e~}w;2izeyD*A zI?|#SG|9P%`>6rkpb-X(359&zM3+o;MM-20a-oE1t1vmC5Qe0S;vu&*5PfLvzjcv) z5eSb9VR<@*+3qVRN2a*`BPOX#Zcw3?hi`U;%<}QmU#{+SkFVD^XnP}E^rBhTi@3>a zF&er{r;gV#h7-X$!9+*DeiUzT({F{UAYK}DYv|PYlNr5a*oI8qqud$aR3f(&Xpn0@ zt*q3;U&jju3e*4o^eedu(n-px@K9IjT ztT&Dbw-RZfJzD=(e`P6ne!uPZAWTQxG<(fq@SV+3%9jDiVGI$dK!ALRQaXG@^)E2c zA;KEFFj&ogse<-p)%~Gz*;uB*oSg;-@d`=sy~*ER^#9v+Tb0NhXF|`ILXqv^0J^> zRDxjN$^m&V=e|X%tKgi&r=U#Z=HpzYI>RHsC;P^Wqw~7=+x~_`Gjx-r* zhT#yI7=>rI%kuq3`LnwD!~`U-CQL=U0q4Ub?YmJD5ErzOx3mH!@*G}U8sE2WAJky1 z5x~R4U3F8b%^~CP?XwWQ2li~sT?ls7>)kU%hN zS4X_Oj%e*Th7EIX9c-4IN|4=q8^BzV*^RTG%Ua^^$6dNAh775*(o?^AldP1IbmGc- zrR@FnOIV(}n?B*KTdc-M+Ko4KipOqz1>o@nse>f@V?ktOwD#2Qah8F^yo9FW_|!OlY+=FLs00rG zzD0>gZ<`fdDbrxd9=@GbBnMey>8&?uOc-jtI@o(-gEJ!yp?;p%(tAWvz{KM7M_|tc@PzP9K{D>5+4HX{yW#! zku5Tz+x)@9)VBMF8LPpw5*xsJOO-SwP@Tri!RucTta`n`;OgZcgR-NhnyOcQ4u@2? z2R-HALTD;XE~^ajHsL5(__HLp)EcLmZob3usad@q0y;#V8t{}SEk7bt9vfJ69h~4X zO8YA!C2*FuL?i9&h^G5yz#IBYdTNiTIM<6IF~QF7<_0FHhOu3UZCm?&zfp*ED7Ul~Mn!l*>~B@AasQ?&{4@(?HK&EbzBQp1lF{_d1_S$|FI{BeAcUj78u12dfHar;t0KT|tT!(Z8q zDFK*Bq-1x*g&IBFN24w$ALQjl-7+cgpL(n1uxIj+>AHT&U_=nlE%yTV_kjgLLqBK) z-m({D4SnZHX%rIhm*c#?x76_5^3IKl+m_cHF8^>_yJ;XeG5z@_lj*aJ!fDP?W|MZ2 zipzYl?09@sH=ThdD5S&4>jauWGf4aB&Ep_dep%YI|JGsYIR zL|Y_wnd9DC<#%tupRCHsOQ*8ze%UDGp{-m>)ipgE?r%&xOYe%7-~KoBV^p-~O#7fR zf7&YQo~ zt>BJG0n6Z1-ZwgDm$&y0X!4%j(b2-Z!xa<1llWyE;+FRw(%)@uIgcoDj*wmmnFXTS z0@ru-fYqAbGr59~HrGr|%34f0%xP739acuagnDos>wbg|T5@BEm*>h4<{s)lE6V;W zH3eRZoD*FN`WwLfZ0QBROGYA!(mOjV;;W~!IhD2Oe`(phLM+u_y{@pfr(WvhKx1T* z*Ut5F%w_bpDy?QB%iB$vbZV_! z8C$AO9ttU_{3SZeLH{twsg_A`vy1ue2SaZwZghlfne{as)**|fMedUSyuIJYsgJ+u zxt13$v$4rvFtC{io_qECGdla2p2BE_CsVe{b2E+7 zzh>#aX!Y&EX8t->>LM=1`*+L>j5HY$PE}PpGT0*u+;jY=%HMvz9(v2fjP1X^yNa(o zSLpQ0H7?VIBvX?YQ}fP>R}CWMpLDG)K9KqJp3`Y%x;xY>{|#>}X(ii+pjMI(-ca@d zmhS%Wuk?K5?76%sZ*KThR7-xZK{%>wD<`n>Q@Rjo(D(MgqEgGH}z zNfe@9V7|y~1cqZ%>l?9GNDXm|XHV0g$*k9WuS??7e&KS51*a1yE3&$OC!mY%u9EF7 z_LTkD*U%G}ql!rJcXBZ*sz$o3HBZwyD6;`??wC{uM4LU{=hf1hh<&Vi_vYl4cUQSv zo;>J$y{0W~s~&5eW2wPs$<`OqrDwLZF;b+3RjM1jVfwN|T$9PQ^OR2xIx~V_xlQ(6 z4Yy9?SG0Xoq?MHoW--vpG#6C3or0zpbq5ZU!u@ZOX#b;Y90Ey`1&{nt-M}`s+QW@I zfh|AhxfBGLo9z7asVKr~eBn5F01yq&{KBQib!FD}4s1|3_MkD%f!(JvL8%SZY40UG zo35a#PP(Uex?0(2_bCd$GWBD`VgeAR`T8YL)HS(GDYoa+`UVeDRe^bOhsV{KSzBAJ zDr)kx%y)4Fv2(6n!QN9xhYY5~C2`zxb1%=0X&xUYE$v$xO_O}KP>Z|8@E$ka;m z<+2V1E%D{Ybo9Mya+^qu+DCE(@{=jtK{pf6T~HneDWb+-@RvJ0&(1AKk=J+P>5JzLHv+)F?;Tzj>s{xkTL{6O}x#2HB?tM-jmbQ{-Roca&vwL04@) zw_BQR6u&gj7B(L}JD9BgkAiRloZY`@y+ z%b_i~3eIP@EzUV6X_`giVB2bH_wykaZ2UHd9iPZvzQ@~Is>_eHJLiJrgb0w4FYs14 z@B3wW=VbB&BNn)rc4`a6u97_HxM^aKzzL0}$y#YQBo;VTxu^k^y z8uW725<;0QfR|7wxJ2%%F;iOrRtqNbvurC9MEN!j8RuL#A%#6%D_x;nMFCA%mD3=7 zV0kY|c)9L#;Uq}a7igT!*vxqwkH3j@OwORxZQGFtc3}RCv=iAQd%Eb!)9dFVG~rQM zW+u1uyOR?(QdHfhfPlp`%qUI4lm4^soWiMLS2zAR%06012GRLG4+9g}c_6$=Zx7<=JGscH{6X*d^o4PMkvdJXQUF@MN5FAAY(eo1*0qBeTxk8atyO zegNbx;M$Aq%98-NY`d3ZXmH>BW+qB+^59)VB2ty(M?x)pE)+Y zg&l~h2!!+Vou!v!jET)Yw${|aUm3D#EmCB@)z2QgWj=EZdSeIMe)}D2d=oo6%P5O@ z-|?Ikl2KJs=b^6nPLf5!8Z}uJKRK|s!v_a-nsmO}B#F8hU2d(ZG<*D|NO{4&v-c(3 z$n9ruhI@jj*QcD+y8+e@F0n-ZB6=HnJU@V%;!S^b;o#AS&|)`K<@c0ScL&!3B&3;y zgV98B< zxlt6i??e@UcHVra_vL`PFSswGI;~=`=x6uk-!B5YCj&CK>xOgW$o${PB`+v;tDUWv zU2|9`&gIviK-4%X3GGW5ie*@n;91U*RB696A!hT`h1D+qanHLGh0hsX^T)=SX2a$8 zM@z3pN~KVF7UfPg0i(4=$YUyuWI(?-7$Gv@lWn9kR`!EmY7AKoD~E~imPuaySkc3T zg1{x+iDTl9<4DZ5z|;GCdp1E_=YBDGr^gG^Q--4PQes}&;*w$v=9YO5N$BdNI31Cz z1Y=7SvEBBKe>;gVu zikjUNxDM%*p5MpKR|ORPUFa|B4i4FN#ib=>{C8vmSu17@I%MgVLm$1$ zjBJh|rKc&>*VT&O(xs@F4}p-5E_v(K19chpMILf-y+tfWcau0*PNiRQ852!q?^VAQ z6X;1LX@Bl~sTZfyYm%1iMJ*~!HnN-SnV=UHMEaC&$bDzYjQ8D{Hw0)UZgIlV}I$X#47CPkN0aM%QoZrl=2FS^8T+7 z4s4iVCBG!aFtgAVXCIzBv!?vEh={zUmYrKzBN>)!rKL7>Kf0@KK_%gj%^ z9wgF?JYKz?i2rFb^RIB?Y8uzTgN27e*|7!LiN}I6+cP;0TovgE$I^{?UP?=1P{E(t z5%}B97h?#}a94zw^;XWr$+RO|Zd_AIz42F_*rb4`GSy_LR5uY~Zo~-oj9!~toQPVR zLsdWzWx8IyAJ28eq@L)_AG|B$Q6DvE*&R2ERluRzr6T+Q`lpmYTd!2U!E616h>{>pEu0fc#0a~H#WvsV8{qlmqlm5{yR zIh%QZf0wZIvA%WDs?I&V_wJ9(^bo~TW*G4NNr7KkaJgSh(R$4W2mjqs@gJw`2Meyr z2A<;bluBHx5XPgX|7O(;C^6NT@sFvHcnNQB+nWlEuX;@Dm2>HtN^0(+swrOW@#xmp z8v_qQd@}GJfxr_pHl{c2#&+#VFGqde1dt+)BN)|RlFtsNeQ?nW7195rt3D_(x~bl2 z0e;yOS9VuNT%vT##r0l8wxdjdDAVsh@i)`O|BQ%MF@oAY^hryAo?Ho?II`mKc+^<{ z(9}fRyC_*Nlnj(XLjJ2 zih>;p{igVIoIz@_tEYPGJ4~~FJBLDx6qaHT(dr>t=25XGKUlnO&pL)sDui;Ea)8V0 zocK{?v#$T6lR;=v8z}0;)W}Z<6`$=NcyMSgel1@lQ(G~Wrv|0|emH|X?D%0gHufYR zXrK)plw5Nj@24e#|7vi*!kl{;JD=(Rre8uO^+oIL!}_LMwI)+GuGKcyMm`x30hjv9 z>WRFOLJD6_2F$&%I#_Tq!d(Z>7Qf(aRU58GBlCgl@YUsu1gtnHpm z(*~}q4ddtbrM&`O)4bTCs4}o`Rd2|Mc`+eXnYTJp+`Q+HH2fhT$#XL99*Pr{B_*VZ zmO@R-Vq+^Fy^K@TH2pDRTbY@1;O{o@Ke~5Rl=WF=%iYb^tF$|0?=E23H~{@8M|~KZ zDfL<2FFiy3BPOW+-S?XDvK^YGM0uPGN$L*pgq=UAZzK=2I_9s{%?n|$084bvec}YV zzzqare(g?QI&!3d<{u3CYBvpG#MTOvJNd6q-W|u3aAKkQNJf4Cl66lb;kmSIq%%oh zipdtrUHgqcF+d?I9Z%k{e6lg5>AA?=8YvgdV2aWL7y*Y4Oq+iC-1ZRgO13u;;3P$k|>>;(U{kE<~_evbq81ec%%Fhdf+lkyn;w5$_mR zabtYLa;YeO39Z~4T_S20T!(Q>iq2X#)&tZPC{S>~c!wi|06kS44F}y%y(yveJj;{VNqj8w1OB1rsoPT}^s7u-CLxsLw1!N$4(-ia@dYHcJsE zzAZZN!2|o+106p2>L8v$O5o@=T&bV5u3DYPVk(92Y%m(6usAvCzPp17;uGtrJge)) zOuS7JN?OnzZLuXgL^inq-af9sYxeA9wGvXcgVDZk07xot8VYVbYL5R}Qe<~l%=lny zwmj?I_tc#opVJbhmL8!b;ptvVFUrCm@t7=-KvN*LMycNdnJyYds42Em?i`H|M);^? zs$ZXjI~mj)=pEVJL?}!M1-o>zZE!nBD@1x=8tv4eePy9kNX>&ez=l$Z9I*1f4-Y_Y!6ksxE z2kKq7n8E@{vsqz_M~`~6f>f~m{smFw z4j{z23$Rj?PG15BakxUapA+?CsnJisMws#L*q&)@3lOSVK{Cp6TJwYgvqpkrNDj=@ z1)B*UWVFM@a}Z65;?ZfuM7`m_KwW6JNH-wz(M@X-gA&-NItWlh%cxwx9>biu1W28z zYUSqDR^Y}jJ&uLK4}(gsH5uowFC-tAn0;}3Y} z1EZVnyZXIOA%uH$V$&3uDjmvxE(dC!zt-~(jH*(HlE+6r)A{C3UgD%=cNp0Ux_>CPx*ag5mzprz5w&mzbpvSMYWU9;z78(S&1o_@fd@;6H zn#b3{g{ksucdSy3wYZwbVI5WyQQ#IYTX~zLd??nhF&BRQS+D(ofyi~80pGls?%`hY zt^Dyo3_+h|TQK5fk#O(sXGCQzo4ZM>rb1rqyX=HA1QhU6bUdbt5qG-;5&)YnfCL~$ zb~cg%|1JyTI13_7 zuHqF%EpP9*Ltv`WU=*NmBh<(WF__cc+il;WmME6ix^2_Tc>5z zy#J_3CyKZII3{SOpLhBJ%G-BQtXX-5WZ2X?EDMv@-752OU~{V-D$EQH%6H9_x>tkS zQ4^pJp0gpZoeyWUe#SH-@krhfnQ0rNAkuFiMw9MSX8iPdYpyF`ah{CWr74t5L+N!B z#SiKlMp~=N9LLHqHg?aE+i`+;TzE1hk-~2ppY4*qV)ahHeIi%mG4L_+cDNATp~0v~ zpwuhRj+6KLs@F%dZ9xUxIrHvp35|l{?w0WdTWiGk*vIEnhCZU&$6q=|f6UqzSw`*@ zgA9B~hCjS)6HRpO1X2QxBApt?-YA@WvY0qAwdd*UgD@^*U}$aGs%zz?_WIV7#`SeE z29+7p+uw6mc4qqOt?b?k=x7smrzX1qn;ycrSUZ^Vc9e7+iBMq5g%GGdK9jOiY!3L+ zjY;LB67LecJn*P6B@n)0rrh~=M%zX7up`lUjs}HkN%sb3ZrXJUGBhuTfm0G>6r8s{ zomNMz2hbQV9e=EY{fYvh9zQ!_K~QLk8~2M7#P!m_(r1M+4`JvGrEktd*fb33P0Ix6 z3ZbM&3q@oQxJ4yS*eM!01^h&PvKFw-?e>^A6RUYOwUgv zVU(fZXX*Nud-$O~G$LZ^||p}u15nuGN?tp8Gbd(DE&D(v+7uRfrllg>{odI z%N2$|MSb6(7Sb$zWQ*M;$7EGn8H|#kC#j3_f%w&Ph_fk>9#uCHa|9T z@X3c>pM6YkI=r>Gj&+8Wrk0U6kp{BcNQKZMVcD6L)SVlObTh|cm-RNIr+oVba~)x!55Jw@ z!=!<6-)1`7epz5F_cDWMF03}v{@{HKmv4Q}oTNKfZ<_do#fap7`rEe^YKmVS&w6@? z<4{i;gZcX<&jM}6cF~%XpNh3uS0M$r8(!C1G;ftv=pzOlr~>(}F~p!`39$RGys*_3W@F9-_t1DY&OXV2m?2Y~Onu*=aKa+y9?SjIra|@@0Sh8Yki9t78 zESmeaTRkTCdJEVjEPM&oYRcl<*DR-IZe&Q~xcH;ParN^jXRTCC(Ztw)SxKHLV?V~T z^Z3p3kXUGgfCWv1YJMsKZ|&ljB`3r*iTn)tbFN6vB_E;6?BIcuW=Rqv9f8ve3%X|| z|4uXnZ4TvT!8#U22RYVeqrES^+;AS!6c{<#vfX=od7mw1$JsLExAKX1h(C zKtvgkh(oWPs18Q&h#$~5*Y5*rcjT1{wOiISYwAZ5bEN;g95t9Qcte+9U@yf8j}8h} zF(psNyc#K}o{%^+P;1{b#*8#+21usnuT2kp16H`_27kJ~-x!XGy1DSR@5un%?>73Y zMbXz+Xj4W5b7S8U#oqUMV4q@qs-e5D$TicWWb_?9T@`NuUvVbu%;!JajIC_7TS$ga zj$|{9P0)7?{gAe9mIT0RO%b$e8x+`^KXn7rBCTlzJlEV-c_#$+&V)Muhzbu>T^B1m0yJwb3p*fg7)xMu&W`s&tDCj8A& zG}z_3iF>wkRyF$ccZ*xfnCL?T#l~q0<_9tNQJxzsI=z>Zdwre!nCRS>?=OB*v=`-s~$GUrE6$~?&Vpr51yT~y>$Bqw=Q$~ zWrhZQrRf-c|EkL=bcCjX$Rx3HN;e+Gk5J4QVdkf5Tat+mV!DNH{*NUlBeB2Df1d&e zblq3SVE)E8zlbXRVlQ#nR2#2eO9)@|+I!nV514;HOlGDiQT5GJ$mV7U(`S z4KF)F3*SDmtIJ(5X%f`)%}Nee)bmPmo6yhnowJtOcUcp__cIAhjs8;BrSRuS9P)|a z9mtjM4zJPF>7%cHqj(!nzz)h-C4AqKC!=Jud9*Q2*bz)(k&R)_qiR%}y-4k-1ZIW8 z3oUswORck`L~b+xTx*e`Ud&jCC>R0BEqYwo1oxkH0j0oYxIlZ3ODs&%XZtyEp)38I zGt2}gdTP~z1#g=N5vThJYea3Jyw@(1KR7;92+_AcCDg`0Ha)BV%c z`1~iN)wmGGMm(EpiW67?ek!Sb{ucRa9nsFE-Ck@QD|k6XX!M|OvvHfPjTvnP*KL}6 zKG3ymFzKtWkD*9rWIPCyeZQvcqXlu;Ay2(kxDpl)lHiq;&(`FXlw{3Dx)pAW78wu( zwPZ|6DerxyZ|5)lDDLShP}V^kyn z$_s!@!D}>z4|sz9sR?cb^8ImuPGZj>2qT_Z2)_j7YHATRsGB=24#_@IAe7<%xygap zuVH#>7*_`QLY-b{0}en_RFVH8t@YXd#ZU~70P`0oIkFuZT)SH+HyMv`V)@*T?y{G} zRKgEx&0_vA5EgDuyJlEna4)Cb8@-8dZWj4IK)z6ugR_z9B10IdMkImoCd;2xbUTWT zrW;f`NP=!|3m>W~n8LvOFUQ}N`>Hdj_OC|5)7RTkKH_Rl zzxQIzG(?@FU|8)Q!irp27EJV^@S_0dM%1DHXP;fJHNt&NOM17xqD6I@#qg)Sjq9EP z#cP(ykXzZpa&~H0hTjqJk`#5x2uZ8Jl%FKWn=r&}u~(iU6PPDA+!5Qy`|H6(Za|{~Y1-OcmlF&)XZlS!hE!cG0nMWp8}1Zu|JyPO%*4G*i~=IfCy4 zge8eNEF55k!7kAxieAgF&Jk zPcwrFj@#hRL~VLil(Px~%$y;&ocRHMx$aLs?-hp^%!ZMCo`)XW9z+x!JiQ}?9mwfj zDBH%YVagn_j1T6CJgCYA^=Ry0QkpNOKHX?!sTrel2=!os9HrHU2-LLJRmYX1`Ww=h zf9sK-uHE+S`m@7z39=!bqvii9%l8!bH^CzkKjE2@?Pgs3uc+AD_Ixk)$4Q$U&sl!? zal>A6-WKorT7$^LDg6wEm}Qt8biTjrU^F-PZU61xYyCX@ObaPrbpBb#4|&s`Ch5>Q z(cL)DZe7gae>ik5L=zY$ROwsEd0c4<;hQXdZEg`)X3T{0i)z!6Dy{u3WGgbwx+1Lj zIr{wd;y+tNQx@U(l8b;mA*WbnPf0j{{RBASUH(puBre=IAMxX78-hv7sWNm=tCbW| zGls27< zxkF)TtX?_t_C}A7p*e+j`5NTqtzL8`g&cx3tOBFJ>-`mPN56-}1CCk~{Vl2d(Ykd%O;p3pvT`#YE1wneElbEIuW@J8c&8D}P0^3HXr5o(-kLL$o z{aC9noTwMY`6@Pvy=`WYi|dyn=wqy3*;mrTjvD9Bf*-?G1Mb$i3-bM2&FS#s=c||Q zJ?f~6Hy75rHodu)S5CfmxSe$~XVkSviF2vKmTk~b!DW_Cl}V9p!De#?#t}36dt7Wg zWa6~0HhSUxpByxuq>{VzU1}iV|y0p4CQ;UbIL>l;%+CXpUjEtT?`PHSgX|j|9 z{}&W^AwH);5M9)>H1^DEp`7D|W$`c!Lr$;~5ztFw3uU1<7?r z=?)G8usH!*+ zEU*ANY*YLDdp*mkXz;y}X-4dYq$hab=WQnr1b2Bo8Cn|syvoTppsUEAA9P{;gX(8R z1-)}4qb44hFx0-UuW-I~GP&ks(j`_c873o8Y;vgQK!6aXOUZrS>l$OI?zCUk-CJ-` zZ6jMGv(V^=LC5&j&}S+U0SA{F=mMQGm|ro$m-v+hUbut?^mM=Qei4I(Nq9(}1^>sz zWA=e1^3SuyCEsq-lRcTMUXOCD+m=|mE4&nYgd@NIT3qr`Wc#4ANQ#Z?7V^I&$oKSD zmyGJaM`N!@u~}Kcq&Ch~A!b{rmaAU3D}>i;v&+z%#gnFzn}z_zN0-9}gnPf}%ei62 z3;S1p!B9zV(00v|g(Jw1wSwOL+Iuzo4#yhI!QJ?-Mw9wgA(B6pH;1-AN_Ue<8B+oB zPTdSk^8DS+*+zHE=u-T*ACn7)t^S8+?!4PR+Y5as4&$`WB%KB5y*S*hKwf?s9#Fg| zO+Bh-pk-KG?%|wd+5PnQcPnFgkv=Z&!`=307o4&zOJ}WTW?8Gd5(Z5g?VcSt{#G@j z=cHfYJzI#Jy*aI8g&b5MedoP;nt#aqaWeUXXVxghP6Xf@xDPB$4(cz2G`iCo5m+^6 z0OPx@cHEz7XfYLp3F>?!^Dw-8l}mVUI5zoD zZ@aN*-cGW%*ZMQe(qQ5ETbfpCsy=VKrJ`fIQk5dStBLMC^z>g|9u^J)8%WrtojX6$ zteqRN<7mvU8=h-6PoGcdci=@_q9TbrZzp6q#zB07x;S1E+`ev|S_}z*8V=be`Xu1X7ADkPMHQ7Rh-WwCCt5j=a#R0xVi9(}p2O z{CCL7>9ykrWhzDu=bZqcewq9|{ps+*j9*iOOI^fMCFYBG5-O^No{a7+b0GMCYO<61 zNRxvU+5Eq$rPBnW&Uff=i)!?;wSK(G5e;wE8IcpSb0flDk8ElT0d(mMd31hr+BfHS zliX!PV>`R5rde=*WitX2W-w zGI7V%U2lE&WWc|aCMSM=ir4G8R=0V9uhOXYaK2k<_DaIc$QW`RDZyDpHcqgT%Ex! z5SRcp-LI8D!N%Cy0q|z>kEn8q4E1fNX71qACK@J7 z;loJC3z{B;Y>zhkd-b0?k>zeD;%a;&O=6_EAiZkk?YxvoJ)rJ&$Pk;^W#5pu0DNUC ziwkXo5%W)|AJGtH%dWF0oxooqp)AEV{g)a)z8Af?=3v`ROwMu}$zSiEAJvmFZJM3NnDI8KaZDgo z%cvFLq>*k@irgwNpQ@`UdrjuZB|u{sdPY_)(o}S0v2{!m-18GeHh-7$sWtsempnX# z|7nH&K|g2_+B9lZZx$QcOp@XCK;$3kI?kXTTi%WX}i6xSl86im^&mYRfpbFMW71Mq>=vwQ8TfL#`r^Rl~jYhqgSn3*`zNYIyyr*&$F4|46z|G=Yz$9&-84I*fUpOAU$VEFERRTZ#LEv|Lg~!a9fDMhb3^ z@z)(UxVZLc(aL+hydbS%f2x}{;%`KFMB&HsK6dxx*po*LL-xEZSB^(u3N0;>VXr=1 z{%9la^)mTOhu3!(p8BQz!MlgzHgZWD8*Mf0%?ARm@zTGopKqny%8#3wP>TA!w3OUa zb`54?`ns|&0XwUGV^A5}T>KmSaP`mLw$XuKk~Aom<+X*SrEB!>kQoYUYn$9{IoWat zFd*I`@$B*=94PU1gfmv2U`dN6a&l*|}66u21$98gQmZ%7wrxhc-On+x*0nH9BZPwSN#2pWQ_gN~rNBuDaL@&5FH zu9mb(hDl1Xy61BlHxtA}WAw-o%oTA)zPR7+MD)iuYj^u|YbHecB(Omyaf_1@*r05V z71am6xODxA*Tb*s$DKxe`(ogjY&{!&Xe73#Iq5JrL&Zh(EX&qTS~5$hn(8&@cd0+{hGD0c9g~3qf1B?2pdtFi zV1omTOg*YYH?pR?llfC%UDRMSLZZAgcMbTzVgAHMJ_azV-Qpw-Td;nDjcXn#@^x|& zj>rYTHXN3$uE$5UxO0@Jc$#u~qEj$qXLZ24y2JnFK_OoTIaOl)a zzbmiIJk*caOVPc?!`+1Nvk4tg&31!NjikzPil&HaS;icvOSWuHXRNNQ7;?nsz8%<- zS7A#J0y8rhmO85irfd`z(C?Hx1nBij$}BG%rzIDY)b7LQJt+PfKb7>nPJiDDiuX!~VZyb*yR^)Gs2S6m8zN3^JQaOLG|(s6$5bphXcxfM zf6d<@M~2dFrrTepaAf;TS;Mb>Iw#y(j>^nqE?O-6i0_T#{t^!UVn(u= z>aB@&k<=LOvh3Z@z|~3;x;@{p(rrRcHQyk)Gdeenb1en6};cblAE>+jvXnuHD|rG+P4{MJ}N?v`~MsU zOi4-6~e9y~M1|<8YPYlWL{U1^Vv?!3gr)yJ)+ZI_qv4);8Qe$Pn4qraXeS zFLSfndO^%P>>+rv^KtvKKT>lYSz7V(bECw1mA5d#O^Hu2O=mg2bI=Z4C#9jeo~-`4 zT(%F%3gNcM%!j`oIoUJ;h6h?XlQ;k&*OM)e_}JE)yEqpemBPBVH2$9URX$NNWTMP zlOU<}GhoL9Ig$)a+gs^D5Z|)vG`a6o_kr$qKQ;al*cQwfM!WKT9gI!Q?)+o&BCNy9 zP7_(QMzOK7#WQ9fe;&08TalVZkzPY<`6a1>&V<3pX&SfcYWU8(CV!ZRcQLgV0H^w< zHIjk_Ur?ATki`xgUuLO$B(SyI@55jhv-(k+(+9`q6Q$NtHtTyWciY~Ap2h#JJn;0* zxpY0W>$P-h<=0~CpuG5%B`ezjvoz+%MNC=+hM$%#SPaeI?ZE4sD%c}>$^XLj#vYX# z1RgwcB$%*udK0n&X33PSjiK0M!ym?t(Q)Moam<|+d^1#&O~Qfw6UuX%+L*7H9n_TU zTwCSqM98)@t;x9ly>SdL^k-(SgQN)C z&)yE-HbBGk+AWkL^1j<`f(J5X;EnD7ty|2C)RI$liEomK5>G6jh@-+Rywivqi!#v& zZLM16a#M>Mv{n<;>HR_FzX+MzY%e=4(pXahHZ1bMd1j<*x_3TwQ7)6s*GxM|!l`3% zoUg~#0@}1b&Am|NP8DkPWQK_Ja2jSQ6%@Zs%ckHvaxT}kP&Lprd9rq==8$Y|A@p2{ z8U(njf-UXH1$oq<&O7&y1b87W(xW2`3d3*eC~Dt=zJnpkh%bL+fmeQd;QL8QMBfpL z+DdLD23LfNP(2~Qy1QYO2b--umCb(4H)fmR*D-fLDpIx}8J`T#1TqWfS#lm!ZBl(w zI{@8GL!sBx0v}|v56OF6R%xZDS(8@@32ha3Xs*c}N6HCZaUK?RF?g_0i^BMw4mE+K zQHOY|LkX?HXX7B%a(!fx{j=cm>vB+L4!GnBqm+JF2S8NC4J7q<*wa9xK1QKA($sDW zBL;QL9zN&3NcBbJ0P-DG!&5MB;x)_^j0vZSRJiir51pH_#x|4B4v#S~#a^JbapRV5{rGa&l4+ciQJB3f-y*b&bGK}60Yg#STsgXBsO{^QIgVc9xthcE*w}wV^6R5L9=J9& z+9_b!r zn>h#>b38&!6(cUeIGQ(jHVul=WP*Yq2;8+$>)Eapo_nU+OCV>YwqfThe7t z1%Wk=_NU&d=0V@wZ|#Q~nLdMV|nwzNxjfbbt^FaTl8#WrK5l^j0J$(LcZS6WY zkY}dcEWl^;snBwO+5-^p-kmhc{+E#BjxdHRw7Ix=r=g2>HTCE>Ctr`J(0_}utQRMLAcV<*P={L}X%~VN zLtUr(ZAe`rHA3pTz1E#)lXuB0axvRa%s$VrKQSnrou1Oavc-W*nw_8S5pK?miHrnY zO^0|E%i^$G!*kYn(0ki%f2DvlnfKMWf5UT}ADv%1rQK%IYx;Qk>)GqGgmcz;pm8J; z8zLjxNgwU2s;t7yNR#qlu-(8RJCID9UfBxmfguemuKwJq1K}ix&qEMpq4W%nqI?^$ z6_Dn1vlkkc#5SufgSNWac;&fGi$o2~Lk1)<07-yNYNIzQ05|n&w8Ym!%&`$V&`X7?mjI$$i}tM4 z0oo!m9P-H8jbDg-IQaRn@0%QS{c7`%b&e1P@*$RXOo{alVSc_j<+_ko)Fi(|AUI)J4;{e!B7VHO(!R%xOS= z&Tpj2Ed3GR`C%-uA=M!ews2id9G=!bNTiRULC6lIf!5pe_bGh4F+M=|0y6)2{N3wj zBOU`7-1iN+;NKX{*;63`#OF+ay@sycCl_?w;n3PQsWl}jsMk!!sWB&T@;xE0MCHOW zbsIA^8+DdhXwsCzbZEi4!ekET7|2m|bj|XlbD*)P??(ktF>+Ev_ymm8pHZ&#&;LkE z(@94%;MIiQFWhkwb^aD?+Z&;rt(;m!sNt<+*Wzqqyg|w3?UU?(sLk@BYf;PytQgI? zF}m#O>!drUJvX4}B=@^WgFQMN@M_hVHPrvrR!rOrp~^BVsBzE0k12sq^je; zZiAG9A>R3r9A21qC&#o}DH!IAtRy$Gz!+d7@D&g|~-4x|zwI;+j|7fe;Kp}Ig{5z3!7 zILEUbDBvlS^sd0=6%_O5a{+`oc_F6#Zy#}KltkW*Zn{SwK~pXJtBrIdtk#eRu!PMR z#ycJ0oNxX_z9&YlWc!3N=rA-eJx2WS+BR_VJcMV!K?Vws^s;`orwcjtD_5>mqX(Tu z{BJ;T#)dn2Nj}Six0{OPJUIh|3LXxYBrO$jPU%gg06pQDHzPHE;1g6=P_VZq#V?hk zaj{Hg{5x5_->$QQgHEZ@f_4=GU2p)>1(O7b4(x!5X z{k`T0#t>?0W{?jp{0P3zy#N}Y)S46r2l|`61Pq5#)NGG-lRL=hGq2^ z7+e+hb;}*r)Gm=Z@*so-F1PcC^{u;pduFuahP_%J20u;=_{go{Hi^F zL{1rTLoqZ7KEUC`mD%T$3$5HZ{4L~J;Tl#WyUt`<28}JVFj9!dIiPAi0mQ&A*~}k9>Gu zuCcKB-o{Pg7L+?vLrDI;regu5w(0Lp^fX9T`UxD-;uUier@Y>cVt%mgOj9aqGtPK9 zVf?eOz|fFoyDUC5w!rX4q38`y-<9Umu~^4Hnai;iJOhvRAC{YQWY3%-$iAHuVE~+~ z_FTPg6yaD7-#4W2=aO7~X08S?2(W9GLR)Wvw1IdXn5mJ_%1(W~vZ^tB7;I^-y!zKY zjjKt*|9g3i6ix3iSZsfkq}_p}TT=-1_^8H1RnZ_%hJ$Qd_^2O=HoFY-8|lAsD+T#q zF{%P4xW)EcY76OtrCNnc9&i30h-68n9y$5^p2%)3^KhW{)Spj@213j;`J# zYj=m`GJmtyiNj{3-5A&1=5aY_zxT_~se84t4zmuyxg8uV*UHA7>c4!=t*g6Wx^&~U zrt#J*8OR_@R437%+v^8ve5avU+&~Y@TXoATX3309OL1i9{Ml2~ZW7qt)w%LGj@t@I zb}XA1Se!myj!qEbHXLdCA6-DOPqdLgavaHeKC*D*02N`+H3<>~4$^E?Xm<#6Eg2Q6 zmHLAk{A!G5vpA#5u%&H0DemiCO6Auimu;8oLLZ>c5{ovCPJ3R55|36pxE+Avm8})R z=h2lTJ;C-XM4aLtzL@QT&#(wD{vVxd{V3Lhd%?;IRl7Ma8~T3~oqHft|NqDJC6Zf` z`>moxF1h74Bt?kjez#99iREq#V@1e4_fKw1?!*#vo%=21Iwp79+=b0`Wqf|;_rE{p z?7ef&>-BoR9uJ)5G{EMw$_lGC!*_e>TH*Is$lJDXPcOR*ru;oDqs(I&!ygV{p=&?W zLFTr~y)QF&f7p@|eVm5_e6+d(P2|PDJQ(3ut|g~;T0yS0-+g@{FeP`VmK>8WQbZgR zgg#tW%7MJY%D?nOQ`29>1~8ll9fpH{am%126clqI-}HGeg=(<%)X zi>K@jjVvOfY4X%e;L=^O+1!!qGZJN|&i5`|5lMpY_)Y1dh-LmOp{`H2sD0tmuJvC^4%kF8K*DOzN@z#W$ zM<@)d@70!+Cx2yvQ`drA7VAtwCScVF2C!Bi_O2>VU;Cw<)0PNKrOnoZ=Tw!MAi!h^ z3->3^%_2kmcs`Xv9N!2QHl$`;UF#*I*vI>HHTvCD)i(GHmG7_y^q9fEO`=WY`}#8~ zdU8Asr8v{gvc+$>1pfBX*BEi<&7SDDw6Uv8$doktq-vg)aXr^M5^L@$BdMV#(Tqnp ze51rP6W1xh$utc=f|vEc$w&CWGn`NTC#<$l0AbgnX<`qd%{|OlJpTUS`izllQ>rnh z@=N3ozcmG02fL=Z(X+QA7R~xM^V}TnS!v5Ll#iJgD4wZNR7|KaH=;2Ipo!ghk9bKj z>Jtc#4U~(;YYCE{i(IFsoPnqb19QPqxUMDPGw=sJjA$ZA*h^}zv<`Suj`ae4_TR^6 z;U@gjgpAMb;89dUC~*9w5%h#b#-;vnrw!foi|dOJV~RCR{QrTij?2T`naAz_eyb%f z?lv1wdTa&zHww6BDHuUthRdvd4gZC3{^?;}<&-U_c~#atMce|a7Y{GL7XX=kS*iM> z%=B*U^>p9(B=uyW%zGw@C49!MDiX$x62amXWhEJbOC(JyV3wcZo;>G34QMbG;5cHt?^5pGT-2^glZ2B*fI- zKx-sot~9!IcG1{b_PKiE95=qsP$+}eWvV#=6>~z7ei*?s zNd#(rvv$v+5lzxFy~Ts!5TzNJTTj#UKYi*(WkduIsOG$gam+IFelal0HKUWL$T*rI@^kRO$UNPFM&7juWm~)LzuPD;f#2aRCia@a>sxCb$A9wgMqdgseS0Yd zLF>}t0|n8sKTsVof9E)1-X%^_+kF?+c{(VvQ8+4}m?Sbk7|kq{`qo#EL--)nZ|C@E z=GB5n-VrvuFr$L9(KsnDmV zkkY^V>*!irovu;(ph2PQ_Gy4PGdYj!Ya%U0@lGr1(TrnZx!+pno;$|@JI@KJsSjc}RzpQe0))Z?BYUtbQysmR*9 zE{OuQ6?eW$>1;Z0nW>Xa)m8s+DxGi0iwBaM?5Z?>=G7Q6@_rXd`0^9Mn;iQOws2@+ zHDLf^^={`Mk&UQ#KO}A@tEy^_va9k*VD6?bjGiXtx1wdNtDGRd+^efXF6BajdyfXU zLoXznf^dlegI%No6P>~BE2K@hlF-LiUjq>1mL+`dRzO$bTpv(TyvgX;=M zTk7~8Q~CXV#Q_Pv;x}(OT+;LzKC*Clmlde}=+uaF$JrBrQTYhH@3pV4F~Aa#IgMy6n??eFTOuZ}ovR_xuV0-dm) z0;BrT2LGt=4|;w&b}YM^kWlb%9o3`$dzY)G=gV1L%6`K6CDiDfHpH&NCB%?)Yt~fxS=FgWGrxa8_urcf=z zVK)k^&?EMi!|c)41h8ulhrxUH@hBrGB-W^f`_Z zkjh3B@-_~4R%Nt1;e(ewGzJD8|i%Ptvde+>H+Oj#dyNrE{X+E&oxOXFC zKM_4rzY>s`l0BDhT&3N!b{e6PWVnZi)^yAqyL16l>e!rzfDbI|pN0@iKQ%*3lZ{x6N5abg~VEKHBS?YZ4pAZMK|0OzCo&`E5 zMq%ONNpw-NZQpcazfslgfnm-X!g`1&yUjI!4a%th{bRHZ*($wCydb<%S8^ye5jOTy zG*gdZm8(%Km`-Z}g~IBRm1X3_fqD83?7J)%POIw`Ynidb*c5#$Z#7VwU*HCBU}kPw z=)BR>rx*;rVzITz&SG&e#531wzbz{ z?Tw5Cp-HmFc0;Z>baZALrqa_6G^hO2bas9}vwhgR_Trr*LTx%QY(y8_T7MXruT%2+ zgP8!{SLZ`zgWja-Wxarb|6%*t=v47alWvYy)29Q1bX@!a9H_Vo058gM;%xN-jDXy=~IV&9|IaLw+ z_48Ig<|^hM9`mHgOuowSMa7k-hGNpaMMsU&v9}$s7R|emb-yF-)l$2PpJmU4cH+e; zj8z0?kTJ5t22++9R_bwD;ZfV_m$Y+*%QvH!2A$ut~q%$yMoGPX|&9=BgylrX!)s3-|=Ee zTiWdNhQ?i(On&vivh|#Da`R`;P^(75nWNJL^Z$%~q^{PwOQ-z_;O2TV;2pri^!O61 zU?#;L89CPw#aK<`h$>LUl4ZZk7&jD_ffDXuj&qndFg9!>m?I}wYdH`_bFF$R>u>=? z27CJhG_L>$M!9&!pDDs-v0Q$4x#**9XwUJAQk|1sRz1t<_o{R`fgOf>qf&-^(~n_- zJp>P2!27ky67>)*CQ%*h!Gj8-lt~P4F2}#l5_XD!%BlZL0LGxg@c!&j0u(fMym4LXaB$1+LO#CBic$2iuPZ>|-Dwo_|5c1h3}^?J2KgZSJj5 zNRN?ywdg?hUo&bEKtUp(0Mvn_TnLMJy4_ZzHpd0Px8Ojy6Z4(+2QIFS*P{dw;_;J$ z;Ti)F){)ZIlD-YOdAS;ptw`FT=Y`<(-f>luA)$!UfGUPZl8sODExj>D3G?%)dMp>E zj)?4%?VEqd*E`MRgR)pQLEbq$JZ z8;F-xYMqC+SsU>PJV@@xJso$OywLghIqWIbr&Q+si9-Goy_`M^n50#rWK)TOVXldkwg0-i207sbM~xywI$K10ssVjZ_kLU` zHKIb2)Xt;)Sl{A zf96*XRneaP>mHAFud?-+q;6QH^gZ~C>_bM`?Z*|TSW?T#WiP0o!lai(CX~?tTL!Bp z*R%Y=mTm-qU2)kF5j0qOc^;>s+U?amCnmrWo?@l;WmlhK6*)4x&2_>#F6t%zsc0O^bEs(Um!c$2 z1|c13PXQ?OeRyjxgjHHg2tH##ey*iSiHT+}s)4{W9%d3!7{@?6up z4d?Cb_;tD@+DK{7YQNhsb6l-x)=*nd&O5p0c^$fByoM=m463#J7ALUKVt~|aFL)J0 z^iB9Xe`W(cMb_&7h7wX@QH&BT7;G!$E^4KNYV7_<8GaWJIM1(9(|g!+7b+smPpo7tE+L;nlx3Y7t z1aEXApTR?r1nuu_z>aM7O_5tIl&`WmJcWVdbBn-r3I^)+v)oTB(_TRAN?~yCXuee! zq=3*QrOXCDr=Sz`a*1eqBQn|=53AUh(~^e=0kk(kkD{#$QSx5w>+Dd?#1{A1TWu8K zi#Q@gU?+89jw&!Wv}5NeVUTOr60ZFmJuocF4^KCqNr^w|;G$-ODRzS={ggZHXe49J zOmq*XYsw|xN5BffFTCNu+f;j}`65&M6<8Pw;YYfoV?{YZHrF-7tZ*3B;`qPpPtIk1_{)2Rb0Nextd|&*qB*R;k3VGqL89k-_S@r?L*GW5qYD< zu_$BQ8&Fu`NH|+eEMTMjkM6M#FEsreWeBD2BA80H|7I?=sl*&t?WA0#euprZVoElb z#Kwg*+Q-qg2B z%6l2`ca12T_;+MK@lE@Es&03SXdITa5}ia-TUlnM(mRD4E1jztQbej(T2uHC2IER$ zUM7<>X4IG}k}y9=4e3(4PXY@(3oPp?c_+~qRyAYFE;GS4JmT5Sgw^^ zRi%pKVPSXRiFExK`2mo+?sIfXyh)-AIV6fKSJ-eUHqX&TFpb`SXdql$Vp;2Z>s~frU}%iTdxV z<=Q!^E|19@JrIU%s}`*|qOnUafFsL_f(BH+z7QJsrpX6aYo&jl^UR59Biiq3_oeQK z*}!sD!ea1BK6fV~gn$_W8BCMNna-F4M@dklfwV>f@mD>B(^EiWX{RByzc4I#g>+{rPsvRJT{u`8!-a1vU!4S|_Wy`922)Kvo#2sVs1!ps?RWMxD^NvooiEfL zQ!mRvex>TL5u-77Hp}XZVC`gEYlZj1o|I~*dN=iY@?k#Ti)cntY@yTx-z1NFeU+K3 zUz#f){>fA|S{&R+DT!JS{IWF>RZ37Bm>aFjKgT>(;jfgpPI$477v}PJVk@KxAXyOf zQxRJ54yzfg<(bxN5lM>MSmXsWb!HbW4XuG}Epy0X-QBAfJpjq01U2q*N#vsbO1>3@ zW1Dwk_G$SRFJ*p!W#JERB9{M5idsb|Z6@tUiSofvtlM^h)=6Pxdm>M+Rz-E!$%lU$ zChI#GmzGj6JG|M!51!2>w&+z5?@mVVCboRF5&$WBihauMMqUx^7g3wU%2SYie!w6& z36q@^h-8DO5j8Zb7Qru)m!MA*dgdw@JX+?dju@6OFGpvbj}JyeQ`-XSe#UxonzZ#F z-DPbLHYoA(Sf3~}6ml8FL<(oI1RywEuE6?2y|H%p+|sA=1qTl+IW!#HDFDtT$e5dt z2R>UbST<=O7gv?d&$ky=d7fwqq4-6kx8lG)r#_$f9@N?7TqD-97N}evY|~} zjz>3-uc6j{%h=WP3}6{LB^D_Jx>E%Y=(HP10{y}a1FEEUyi%)y_Yv>-{wiJ;+h+Jz zSiLVWU-K^BUA>{gqZABvQ7$Nixw~ohZk<^dMoe}v0lc}CxKN31jYX#Z0v3u^65B-E zBq-pE?Q6TneNum6=@u98CytBu@OX^`O>WZn_(=mIP6A7D%C69@phBOwH&6psP~Fus zSPM`vc}Un0$q8TXvYtalg6OLO>R`VX!{HkQSGX5(pTl$Cj|dSm_EKJG%;8Nu4ntkD zTi9G?OVcCg4R5T!~M9aw1{3u}3`E+5^xbm3+ z0<6T-1>oiiM7~WCqa3pB9KpT#IhA-=HT~lmgf%QcrZ2zjy?9gO0lY3s)jsLa(6%qc zqT7#AKikFklNRjlfK|z-HSXFB2@_y{RV2whw%6IiA}^vsU~1cF{%mS)wRt*y!?uy* zrRP5t{rLz+*){>{Z=So^4+VKm@(qJZq%tL&A9IWGRH`bKFr-^~iMrE5&m%ARfwuLX zq?l~C8s5aGAubgt-oY{`=ip1W1t%%oF<2O$0^B^WDK7@-x>Qo{ZWuSVOd|BPQYxy~ zYSLlFzdYx#FCt(O6WZVRdwp1!x3mO9iYVE!Sh0KLL%9SHgnZV0u&LrCOx}pO`+Z`C z!qafUETTU71}lh$dvEk)HwwsaSTeDZB1qjM8MYSmfuKk<)t~g(@u_&DQMig;6AofBDGQ)Cs7`{5QpE7P zc%pU#(j7^?SJqvEK|il*c#fB#gUucyplEYRD53A#(tmWGHSgXu$|x@<()h+B zxS=9<@L#pmcG~aZ5E|hnAa(t?`lki38gWo59HUNavw1J*MF|h52tBp zu!!z%9dWSPF7&P2!og3*Up8SH(Dltn_+bTO{Kg4ie zay8yu;B1?g58zUd?~YhAU2h4jj_=EZFVKqARpe$Kn@JLKqu!J#1f4kf z6mg%^B-5}-(kjX~-_CN|FmZ$5z_L7ddT{wr=#^YHf4t4Z+81SZ)#{eh5|=*|nRw}P z3IHN&i5taVev^0_py01Z%hB4r+OH~pUx*=Csd0egnH3)8FcEmJaQ|6gzLEKillHZ_ z?RIvYT%fV~VQ&j;y)eWljIikJNdJ6B&{nr{Y0EAv^BNAJ;{`p*?lD$efdD^}+59im zvD;L|0p`0E#XFj)^p0jnl2SFqsMdZlw4aU1 z@wIfdQbM)e#e%)PJ!Jdvm#v2>w18jWz1=aYK4NN_8{|Uq=^W_7qZnW@$SWQ#H$rE6 zQ`k4Nf`M$o`0n!KmI<$-$(5-M3^{W(m0Hx(C<86uQOVhl@>Xu`xGXF%eVi2P5y2H# zZZUQULdB9zs)h4?;-m7yRFCurwCN)_X)@FV zV#f`8YEd7WT-RxBo!!v>KMEt}CFt*y;GE=AAQ8b&c~}?z(y#Q_zej4adu}=BGETdM zc-?S!51ET9_rD>O*a0p2$=?XIm0g#ol$0nfdV~~q5?wF)A%bxlWQ2y(cSmRz0FTA) zgaOLa_IxkW?o+JBiUF_@$TPPUqyU9hzg7|9jxtFHu%*#ijTHwd`lCf%0=hG-&79B} z4}3^}a(i2ufgcI=zCf(DK4m}v{6QJbc8=<8nA4oDx1P|EhPuw_rE|n1w4A48*S}Bf zeRi}naulLdH~oih5}5x4LW_o@3`TH0+>zz4WY#W?`?FA8rALI&7a zkNyl)D%vvZNkvXZg;amYZiO-j7d+zmSBi44@4`+WTDI2}WSso7wmHT+s>iKqbC@d| zkJc4@*DduB9oOCWvMjFTLr^roF+rXj+vt;3t?j|LmHPFGqC*Yeb7fYi+oe(oC-4vb z7L}G838j@02T~=PA=Lu)cD}|<4Y_B~?rg1lc#t|w`zm#e5WIVbJku+X99Oy(D%#5z zxX%P2ddL5xt3Q^xPXG`yyY|KtvP6nfj%HqVyE^4=QaHg&v`-S|;wRn68=U=HPV4%4 z)mPema%0~^pr3&jK=coN+@kjxg4i96oZc!G*WrCv^NhRhhFvaduL9+A6 zUDNJ`qJY;{_db7HB^7m8$#hKSN|mPIbKIL8;C{!!=C~DFvY6H30Wx*$JKzQ0l&CG> zxb{0yM95qzfCQ{ZN=eVg71u^&(5e~PL8`H=EV zhR`_wM>LwIeNpY3`Q~qlx{~|?B(^A_D7xtQ*-)|#X*k;ued2J>jqj6H*P%u7!({tx zVyzNI-lpYR-^=YMXWn;zW_cBWn3N4O{0-CbbfQn<-vFR#gSr1&)}Tu_(glAimJQ$0e-$DL!5KN0km{N zHWFOs)7YG*`$2E|S@-4HmYY|8mWABsVlX{;+i_Dx_Nz~IQA`jfbr*jlv&49E7cBjZ zXtm&))Y)C@{K7ArLD72ZW$nN5+_%i~ZO#2M+_@j-tS9A#&+N5%6&WiB;`H;)*^D@O z$F9`R$ShbZ=NQZx+^wHbp4!w;?jXqE+{hcfU{)Op*w_Fg{8ARCCI^IwJ_tCS>6{l; zZe6J0_%TMq<-d1t#(@)eX+DJ>4OVdyC!Cy;PFGJ?tYcvh+mZjH>Ef_z#3Y&Zv>n1} zA9Pox>y!eLcFSU;CqC^PDSHcR_?GxS4SC%Gp*rOw+Zn4rzAx0zF^;S|N&T{2aHnkw zWbg9X(}|gqoDSqNV#mTo<1veZ{TDpbUV*Ke-o^oXQJn@~cjmkcktN991VdDx6UQ`` zn~1?Hdok`0wpdTqqpnbAN~zFp5rsDL(mM~Jokit2eDWRjsGZ_nSgcbsySz9zk69`z zqh@#KBD9H)lFEVr{T9a3rfw8=e%IC|Ojz42S!3R3(qG!mVJN;L*{{eHkE%^ujqlZy zWiKw`*LqT9Jtx_peaC1rZ!xpEUHd`dvFE62uv7-|%g)oX5%4Ejd+_MPx@?8IMk68i zq7sAwIlO0<_L#i?p?-exCGgYTm8BWGhhOe5ag%k)w#4njF54XMYWaw_RiBsi0TL{H z81&QhsfhcoH4BTUb=KG2D^^lf-hhbh!ZnhayV#&iW?i9K#dPmMfwwC!r`TU~q?R-d zu-j(_6Lv+d>+rP8GK0WepB_FctT7mo-qHz~IJ?lB~FU|e7Hx-!o3;gmOtq$-sbkZ6{f zUZ0cP0$K9Xw+uH24{nVd78I7}V!}{$cdA+lH$X|!YlE(@WDaVXP>cFPZ=!rt07H~q znHWO+JpWg@4an_G=ed~w5OKp85YfxH{Y<;wy68d~NIBY#^<-`zB=0_q!Ax_bZugwH zQ$N-0*fBK7+fnN}8ym-U!zgmy*?{1^NBvGABXmT!FIfF~w#pKFuE`{+X}TuRhX-IE zEj)ao2GH7v%F?JP(i2K!qIb>FaZ_whi)KwO!RLzY;*G=lF($a@5F1yIRX~W>n#|aV z*H;yRjMQ&uCe?mnp=)c+A%YIlR*L-0gNGA6%JJptUh1{T-yg&5rpQzuW3}d{tgzJBViig0mv~??R)hG`XcU;<$CgMW|yeh zI#@hgOj5PeR_G~!8QVRY{}EXA>1M%k`r$ygmS9TX#RDKJW^d6rDNcz^0BI8%re%L3 zXXhN-F_m3qM&(Y12TyKCPV9;0kI7>>pN~ktQeHmOA)r2VkSmW+$^X$YwzKSL^W058 z@g+NTJS;1t`4tT9^c377;}eL&TEl&zK9QJxCL8#DBBZNX*{F3257I1sy`(y&G~y8F z1kc)j^0KSISt7od@GY>7Dn(Uqs&W63RuPv361UG*$g3neXNwn_h$IlrW%C)YgF-OLGznQ%Esf;Fbo_%CrwZn2sO{d(qYnuvWkpXP; zkzQiP?OF4N;}}sE`|Sg#orYi)s9SJVV;oK8^XqX>=l$on?Ea-!*#TcX>60qPyKpe= zId>4qvteaxg}gLrS<4lxWGUrsiWdJ&8Z;PxuNGovd3Q}c6V9j2-wLs}@i~*OWw3j?vfc=k;BxcD%ya_9{=iw{2?n zf3LUTm0SOnQ8qHttz6decw_#Tff`=&)UB*f@iT)|C8aTqPJC|*@Jd}9_*iVcKJ#0j z47uP2zyfSr>D`PKFhNg&`X5>$XrE8s-of9lLWbOVDDtd`4=ykCRL{+EUKb-C3`QS0 zgT6`W`7;u)XacsLynh0IY)}yM033JJ4^Gt}NH)Dxpl(ko(8OKz*`S;GPPWb>Ifhln zin|ASGSBZ`&9E~mv7fGWZhtj z3=vB)2@#f`y2bzJKtX4tZ~&C1^B-L>3UNey)hXn9O{Z&rS>wA2Ags$fdO0XB;vn07)=>PF|@MqXlx>gv)2qhEx&gUD($cg;qjJQq#H z8MWU`CI!uW`;OUk9~DQJia7^Y83&nW_(mBuUvmYwHjaIt@H+QdwT^a(mV5hCVJ9#8 z=Ej;T|H@ltx`GJPJm!O*JfW3D&U!x_gZGaC6Zjanqdi?}f$yarI;O{fl22^>+OrKN zc84^MOD!-EJN(Zh`ZT|{0n2Zt)T?IePwkXy(8!_1b{C^hp1bpFt{3(ae_>6rzJoso z8q{6g`8qdl2JGi#aHU5jhlrK`I0A`86%=W87d}6bPw@}ksOT=xV8=Qav>sTvMntCaAjCw zJ=qMG?_A|@II?d;cx47o|-8<-J^O`Z*n*_KbtBdOABc8;pAz;+j=+5ckN zT4eru@1F-RWE%7{|M;;p&=4Zl&O}Jb_Vyg&-s9Dl^$mIB{+Z^h)htH$svOc*V4^DI z!Vu~2x9~A!E5$C;R}r`G8Zaf4?1wA$*Efr(zbZA@ID-T$+3|_JWfn^GOLR|6)9__+ z7ZW-v8D@WbxDZGx^&6YH>6a$o?`)>snjA2d_JCPaA4iw^V^lt`4P2wM;ca3tswO5x zLhZBD(YfX*cYMrASTh{n>oC^Te>cOV*2$2PTO(ia@8BP#^x<$5Q)xh?^#UoHW}@!W zA(rDEA_j6jQXO+32ShSG_g6m>;#b>EHt}b_5x5z4m>S8*K^Lfv9{zjGy-ObUqMgi_ z?X++Db}^7V#1TcHW8uO10&NbL$bU$b71xgeTYv~pg0E})%9zAR3VN|~8!pDTQP36> zwh^z&mR>*y62%6LIpwnhys4{@b=0EIFs(+pdVc!Pkr9w)j@fH7dGDIcbi7$q`}>lR z$f9Jgp8B~Z|rPV_#xn+@YSIkrHnE@+uHi&8}NgHy)4DyXRw#>;i=A0hgm>WvVuvt zLBGym8IXsD?D*PkFP=^`v~K`JEK5hl9W=LlCCoo^bv=9HF+HBO_e{2`sbVxV zC0mT{FtI}p$#6pgAYQTO*QM46GBs_*AD47J7QV51!*Tu_^H7B<{mfgigGm4Py`w6P zwlxxqgjx>h)~lVN6?ZB9Jw|lKXF?}0=s3QY4ELr=GBxd6uB-Im1cpMTmgR4!h9+tQSfqAAMtslmwVeMa^n;ELl}&9HeTbV9VqL{Ee0t@YCV8uC;MU`Ii>QNG*{dRgzVxLE zZSJ$x4wm`*u(p%7`u3AX%R*11BJl9upA%Zjh^9NCrnYb=meY15%tmdyv;y7P+AUMlCO)L?mrduy>nE8b(;HQ95@ z1z!@gvnGCgy}HLz|B>;*gG(zUru3-!cnXS}#y1Ij<7nHP;K%j#L!Sxt*8?ewGh~4Pk-}@oeT2A`wSCF+&E4Kt<^1Z^L zL1|rnF5%a~9RD&YFr?bNj9nT^tiki|KtS-^mFyU0PUVYtTyS@rG)bAYrn;XEK<`G} ztSxCV?<;4u)3Yy!{}@~!ee_|5M^S;cTqMfb&J5K%Fn&CwoYY%~qXJhUVql(RGZ;3J(-Le{PHE+Q#aa3?{wSB_jx`b|ybr6gcapQsEJ z(3C9ExH$|uCgRrej+O=vtEaRpgZ`~_?rj4TG&Te?&r|)_^NDR5Mw$PEhpO&Yi&@qu z&U>gw54~whKT$V=mn`JIU1++M!QJV=nRnc|3&bFqxYsTusiuUH2srFUUCJ}ObV>aB zfZ1eG%;;-585Pa^af@gdMP12c9skto*?XlLng0ldTS59l3g~lGb1V)GVK0AIHXls% z9n6X^0#-(k5@>Uins{^ZTtdpvb&yJIZ<7&+nT@-iw{J08o!z?qTRNih6q@}ssQMM| zXzU$?Y$gf-tth2s0VGJY$nCn^ew>b*=aL9TJ9-c1!yKN`lF!wn&JDng5(Wgqr-u!y zz-5n?1S#S(Y@RPMcr!UI($+F3yyHarys;j|7cpXnFvrDyu-l%yuSsvwFx@Uh)0spV zy{dJv@hsq(K)_12z}3(k*X&@c)0S6>E%p1NC(%hqkC*iF|DzK{1e5PW(lqrf#t~{n zB<8KM@YAnm%aDS;tUE27ULSuASAd1g{^VrtW!88;wq0+Ew?J`8j1z7ulRv2qtC8e z=5#WP;N3M4w}(j**aMF%U#-;eFE?a+oe?r`AR7!3jttCl*9(aEGvbXl`6>g>)R~G; zY5kARr+jJ70N^5<{Qi$_B`zpbKaP)Db&`O^(>OPn89$X!Z_oE=-EGAjeh`42A6?v@ zesi>S#Y`e!rZn}Xh=1q1i4^lQB)n#M1=Xb;jjSu{{PSvpW=XW4*Ay7*5nw@|L?NWd zj~tzcZ7?B4hx^qKdwkjWiUH0I-@%6dK(tP6pBMb2|NGM!0*Yj$X_V9MQHv^)g7wMx zy7KlELPug~EC2!)DfyT-x`@yw_#~oc0S}-n#ej9ggbWx)SgFB1bFz79cC*wG@n(Cw zO_1D~G~yAklK25$MpD^jUXc+v>|!aT>9$QDbqG@Hh$1=J4M^sCpo?m_+^Kc#8~GwN zNST8JO0G#I`ta{$2P@3kEG_^RvM(i7TBW{!W3g>cslDdC|;NWB9egprezB?ndg<-<` z{NvV1YRFkI-1>P6I!I-p&l22-@{s6{IryI^i=CQX~Xp+}L30YNLM`p0F<&{vCP$h*a63B3@+QEdKrAUJ3@>+QjJc6p+w*<+dW+hTNfZ4EQLjf z+|kAJZ4Qp?!nfZfFJ6@Atd$l@0=q%)_W`&@!aptOXr(O~S@C4(YTA-18PcyVf(j{?Wh7{1BVEQ8E>p0Ks~pmHdkuLM6hno&2P3}Z>2oV zN+ds?;R)jKPlXmJ&G4Lz>@((`Bn&?7%kz8mGUp1@76Y)y6v5&|MLSZEAGA2&5)g_? zT+V$I=gy2##q5sR_BTar=+dX^t?Uz(P?3(4BDSNs_8hXK)8c&ZTt(Xx&Y8{uwTf(_ zA0I-RM~qFcOj+*Dv|)T3zrUJUm8_><+2hGFqgnIFe47?@>Ja&_?aRg26IIp=<(o}L zzxvGIf0?rLPZSC-u9Q?!Gcn76w9NbIAH-2yPCRqFffMn&#+hQ>qX~V1rAU``wad0p z-UnUWrD6!5V8$*wwfMjhg@c2&bd#1TC3(hNUjW_IGik3Qyw(x7(lB+jzl)TaK+sc| zPTovK2waRuT%kt0gwz-iU*WL21Rpl)cVW@KcHSAlLhn|!vm`W?5=GOgFlpzWs!wvp zffIVaZ9kL?2nnwADD4MGpo`i^aiss~sCOanXttydR+bsCCr)^R0 zv}J4HoPDAheSx+FcMn6`6m7=qD~gZEAu;BO{bqg6ethN1W`@= zTK5n)#<5QAcfOICqN0=flPEsjWDnrr&^jTdsb%O_F9 zBxK*ky>{|miB};t_c@>Xwh%r-u(m-24KP1h5Q$%M?U=J>Hd6L>n40@rz?2w=Y({fZeUgw!OQM) zL;iZheXf69ro4Wy9iV?Nx%hV&ydU;|(<*4BT%DXDiO=xF_29h>E!|AGO75G~mq_+o ze?8B;VV^PYzv1-lm6b;&Qrx%hDYtmk3GW8G6+EN8$u}o=dYodkz5f=d5GJ+MyiGRBw{Ql&n|%pZ&s@p291& z*@N(rZ*4X;B{{!kaC5fv!|HYp_0CJ+spVg|6Qk*Nb|85{L8ZL$B2B~CG{887=rmMgAD3Seyc-fc+Wk&NmUmN}UA6b13A3`~B#_P!z6BUj6F z?$_*o;`n>^QZ>4e!OW?Si++MYlLH!yg4S#4c z>GLXb^DDkV{e7u{9IN8Ijl)6@A0!XCQoO_ixD_L$soK3Q?^T#rynMRITXqk>^XN_f zJ|599$ID_gZxfwCtR9 ztB}$#vyJpn=rC@N#B1tgNX}?(_6j^cGbpXeX~7u_Ob-0^Nzl3km+5WUh*8o6cU>q? z1SXuJ*`OV4m?nhmGC6a0q;h*nbc&`^vaE|_FX=G7=)vvny-`N9Z*%s!`&G+KpZ`af z{$|M}Lfmt?F1x2n5S7#}3_Mc%wFMC#6ny|G68xE(_9KON^EwsL5q*?S5)QM#!E}kD zSI3C+2Fg`35(dt<+s6f1jPOZ&E(tpw3GJ%D4VrOs=sugI^74m*`vu#>odrxd5?cV# zhl|C<@8p?u!oY@2kG#ce)Ay&6Yrj0Yy&i90v0nwx1)p$JcUDqZx3xvJZh5wgk%MB( zHmw?WSJ26R4nS(~dLUHe`>^w_i`2qxFxvB!H+wE3^{QsdN%i7!qS?Tj0n91-;NpJI z1fgBpCeNE*DPP)B;97wk+Xpm+#V)-EBKofPMIXV#yblO(tDDGIIb~D~6+5pnljqvO zYOg-&mg#dDnB-zTMo}`)0ML{tE?+%;_0;E1vD=q7e;Q9-_%L_~!~&CgL3j)wdo$rO z*()h`(lbz~LQrH*4vK8({)EXASDj74V=Hs6-NrMO8 zK50vWFzAmr;);rkTi+o4Cp+r{LZcBskl=_r7b9BNzMrFL+=U)MR_zvbf{>)OG_-Fz zh1oR=XR>T<%me_?I;m$x*YDykwPiQ~%Wr2aAY@ImX&!_AH{&?Q$NBDMTZ5bSMp1o1jPeYF%)X z%yoUwY-zq z{O29Um63GYGuZ)GZeK$@`93WRy5->=sUtJ>e-xdCTT}nv#)lwCE7Gli2ue2$5cx?8 zqd{6h5pXmzLOKKqX(dIv!;S75Avr?nZNO+Ya#G*tJb%EhYrC%VIcMj6zwg)UTyeHy zd+u_57F!>#V5yP>>@oeS?eDtv-VXm2Sgl-$&Mt*0-tql@u;(t~kbyIvJNe?OIR{_d z-3PC_$Sp7zdpdS4_|@wb_i>#fsv0v5##dYmlemaRw9ue?SX!(9CE1`(X<2OR>gU|0 zt5vP1L?5QC94#7j#Odm>7)%{9jWsvT7Qq9{x&9}cIIY2jfoTekvCK*CJ?~xl2{*sg z=gD7APi^zuNLUqWG4m?rWc3yPD!BlBBC$dT($@mB-U& zSt9uJCSCTQ+)B|~Zb&U@~5NRh~|!r7dm$BI0h}g3c@0qWqu1Jra~kZ?4}5BxcKXI-|>rB0c2-#@O3@xicSDYZ&t$beFkzePBTFa$ROph zY?RFf+t@+P*}?||^o{$bVnk?^A7j$3ySPqcn-r$f9?wUu7YO)#aAr4;2_`4{ z0F1?bKmpqHxm{d^m8kO1hd!43VGDsJ5v*L^)$2}2yzJqA1kX0WXMATAhm{%y?#o%& z1RvS>=}uu4t2?3_U;h&v?5dj>$fZNQ=$by|VlgDVYjZ}A*4`sB=;>JG169Y_GFcPpmN(>5gF^F9pBW+OgQV1&F9W7-?Cc_aJu4KxV_o*gXpeH zh$^X(rd55}-q8|wcHWc36eJGhxbasZYryAAcRihL*_$T8A|ak@%7T5tT$4UT`0BnG z-Ht3bky!Z_SbU2G%=-7H_Wc9^qt)ARXC^GIjVMoIj5`O)z8Ib9c z#7B2aqZCU^cBRz_htR{EtlJu8h3>fjp7?Wq_I|3%c_OZLB3dTb*s=~^8V$F~XCj94 zkS)C0<$lyWDS}XweLg?eBxlekS_tJ@&w5+aR<%$yiKq!H8#;J+QNcFOo@kXY zIDfqie$uB{L1mnv?ch9E%xY+yAY_tTtdnisn4n$O@V0!URg3-xU&vzyRe0v7Zw@B6jxxTjz# zN)>>{uch#SZup5_i~V-LoRWMYcl3D!VaC?2?F6|P1jnTie`8zIOy@jTQ!H?{7FW8@ zE{fYL!L7ba#)~Sk?oZz_U40|&;`7gvuhV>Wf!AA|Ovns;%vDd1VZwqXOEclb3AGPB zEI{#1yUDN~$UvyA)o2G!7Nm_9x7Z_J3pD>qh?JDJeMG?$Gl+eHd2fndwB@T|b?&ec1x@?yMOrf3dBV9fEzEMw4$?RQXZ!GmZ62kV!nujmV>EUDBY|nDR(YCh;wa?=J>$l zVdbr7ymT@7nBhTQaZ<;LnPsYZf-8dYZ_~Tw` zI0XgBsfks&L0M;Ql$OHuhW+tuGKR!Lb9JO>z7uZO_zT(#O`BkF&4q%WRqSGW3IF>FO`kxF0%>%qz4^88_w>%rFE z%p1IPSi!{QU~6$+Tp|n^v=;aEgbW+D+IUzF_EDz9mU5~i$(%Z2NK(>9tqI=LnRV|0 z>E**uAvGIMPEb(Aj`q%vS9=oC7AGS|l)hTs5?}^-!DG@!a@dyeJKp?B!h9m#GbD(?b3WdY)btBT>vUWm zfc&g;-jeF>9@jKh|NGS(L{}6Ju_ft2{`QX@eom))vh=|v0HV^(I`zbP=RXi{Lep#`!s;gXGUW=n zN$UJhQ;?q%M^P}rx|TyaLuGqAz0`;^d|vW#ih8NY3%u?&)5~%7gD+AwL)$ zFZvlL5AXRS!MJdG&f{)$EfT+7@3L6zx^sTh_1xkcvtABh|aH(wI^=a*#YYB@jodfK-;s zaSD}+vwsl$M!RP*hwl4go%35s953%AeKq7vB2IqXs^ z&G2@-m(<`?e9E1PdbGkQCwKEpKY88^Y-014zUPE{TMsYi{b$>4L@nIrzrb+MJW0SF zz4q1Py`|OBNuAe-oNIAs$h={{&rbJRI_L2O-}YXB{pq7z_^I)^Nye55U1J?f~*F(r|x@k6udo0gB-b0j0~(f2zl123{H@>kQuWN+vieB?b@4z_0-= zn366{xZEw0kpoWd@8GWid0Inkg-QmusE#1ksw@0hQvMpXlWUMyl&XrjHV98i)ot&X zb4y=-$)68&3R*M@{J6aMvnwS8rMIKdpk+8onkY`8upaMJutrW%LJ69TIzqa6Xeb`o z^e287WWxz~r^d(MGPrxENB(A;qdqU!dz=z%kJnIRZ02)YvUg08XCvERqj6(1Qe4Ls zFbXvM3$eLfczNnKE5b4X5gYpYl(4kUOuB(oIPC%X2BaSQ3~G(iq!0Ir0}qhzYyib6Y=ETJ zbobK*6nFhWOI+(s&$p|^&%=TgHK650eMOG|(v&z(ir39e3T{ek3=rE$5Mzc?v?Bf+ zazs-=i-IHk08~D{XTSb<)QiqDMe3pW?PSj$wr=|XY);}oTX|9iHgL?!@Z!Z%EyA^P z{_no)2Z`RbYmC0WxFiL~Fr9avM5yKoBhU}GTBnv)3u9$)U{r4?O(D~mlq+v$2=UZp6m0(li3pX_%;g9>!_^R$4 z(8zBR6Ob6juW`Ba5HflseBbXJVKa9vJs)B`Aog^>CLNo{m?dje$jk6avY#|xeV#8d z;GbQb3d2?&Z{qv8J72V9_hDh9_r8j&lOrL|$-P{+l~!qJSn5;xHXjMSg1n>=Qy8bX z)QxCT0G?GJ{XQl&y83DGd-Vxx$Zlwjq)1AHCB5WM!!lPt{(F!;Z^PqGbSo}bs?^o< z`Pe!4@1nN-YKbtvhxL6oz2y9O?owUiS@qMGASF5yQPAKVb)up#ZgbxWXvyIB+T5l8 ziKjSDFtG6rddSs63yEycl#iQnXBieLCKA6%3r3n>w|Hst#dC)>_h3sTT_=D(O-ulJ z6GuT)f}=f_!b9)RVon*~rr=l8*fkpa``IPa)=h1O@NDS9#U4WE!lv}+d}kt5Y}3a0 zKTv4)O>GOY&!_XX*T<4gwRy6j?z%fFrUn}1;{Kq3dBIwk<}(5rIjx;`V=Ke066~;6 zt=Yp{`{76YmpTkA?imM@$#AfdsKHGV@%+ps&Q1~gvPoP!6N;x_uIIhi>?RaSE>F^W zanJ4%tPouq8>B2novpAL&X<-V?GR;+6E+u&2<;c&(&Qy!FeppO+nET|mT`iOh{(fN zwwHZ=F<~wP7rYvCQ=3*h^0Itq3)k}5uI_cVaGVs?5%>)T$UZXX@kfsNzTGHFw(MhC zm)brTDg8s~Cz7(d_*dS5AD(V%610n6r2_)owbi)S1ixN8PQYN@760Kw-;TG1i=5(% zjj@qJ&C12Cg^V=brWv1Q>&5m`^?9F54klfoP4aGTnoaZoNb!r3Xoerc-F}2peeezy zFZ?L}j8%aGOjpP>?#j(Ng;=MoaBghMGj>bJ)q#YiOT_Xye%0s?+NxoACfiUq%so!8 zGTv}f7&B0%!KInG^Jjh6SQirg^BQyL>|L@S+(f8+AQDG(c4~cqX1^aoghyAHDL+wZzNbPQX zLM1C}Z|w_y5c!m?XHAg8E!J zhgsIVG1ZmbJ?2!bZt0Z^`}c3!)nm$0`%|;h*~}4!R!@|ut$2Qc)$!vSh3|gFk@*Ub zGlr))riMOS>hP1Q>mH_|^R$auAt%1YI}I+lWnZTfsO|7_{n>YXvUMp4wAa%MPtP(G zKLHEc6mjqpIKeI|{yf=cg-deObS_AhN}f+6j(2YKlqaI=J!IkX>|@-k8{RFWAQz%T zsSAY`;56`aR;eeo>Tv+iU9j|zagQ(db@B&V)LMawFZ3phJ`5d0~Q4bkaXVjA}6|5u2zeBqDK?| zn>jFAwVFZgd#kyfUnIl!pqA+DeTMdpIZY$xt}lyc;OmBVAo|Cwe(B_crS<_iELjc5 zKo@=@grQxPsV1|`8s-HH(k$OK{8UwvTsC}rJijRW+K3XNUPkoblAWfNr5>*Jr61r) zmdta?Z#y*JzSZeWw8J3H5p=$a`1)53R3b5$oOgLHdD^&{W@461?1W zT*BKrDMLh?pf6d{1*?7Hk~`nJS4aj=$#!lU$@--y=oFF?q;@H*{WExS-i}e460A+A zTs!+tc%rBG@%+{7e1EXA?A+Ykypc;MFQnmp*CIFTjFWZ^Jc-qr`3UwAt9D5fP&}7e zw#20n;&mlgNUQ{01vFVJ@E{g+v&ig+z0y}%Xpw#wGY%zrlO9S^mqXw$iYI5A7Ef+I z%M}Epn;(^xk$|rlfl$D*ZSki6-&&^$QX%9<y?N@ax#DTipD!TsZB@CSR2zuhOq8`e_mIj zf`x-jfpajp%3K>8Hwm`pESoru ziN1+&6(J&`h`0*uxuJ??AK*pu(#u>LgS{7*t^e-GNg<^b-v@fTdw=?n(XgcFI4`~o zaqFqZWDb9&Zy9x-8Imm1I0X4;9$28fHL@8+WDk(`t%F8RJ(! z!~a3us&0@NU>-W^UF0Hhopp1xB2)vv{PM-ZmwKQvV&z->nd>J_NIrTcLAKV{H<0`bn&%!-w0De6 zdLvr*{X;nS>?M2fZ#ixT*)C47adC(%b%&t!bh{wB@-zlABkhl%tcC-AQRd~ovaMjD z`oKyqa%?{oy+{e?xofrLYPc;Y*GS$|{Jt)j{|2dO*KZfgEi`wk$P~JN*>s*f>v}RF~YbQ`Kj{!?Z`j&1QqXwh;h6L*79CHKhF8} z+k>)cLpPBo>C}(^FILqaC>DGo_8d=f#n^`yOMr5qllH^#iDI{E3TZrm2>pEu42RAr zegN$~Hky*TgP_0r-t)EYD;o>JxQ%0eTF%D$B#Gb~yjYKFxb2-O=@6bP9wKzDTI_#> zk~Fa^Wvn~pc1BZ1)@G6)r`Ho_72f|q+Nw@Zp1wJop2I5_-u`0H6o+<9P|bG#oKJb> zjZd;wRE>jw%+zI%E~m>Z*K_u*xB?U6Kbq5*uDawg&5Ax~Lba;!)4{J4R9Nqb zl>FHyRcmdTy|QgJE2V-rW?m!~R4u^XU0{|SJL>FcUFrFurT?bQ$5s(M`#jh#c38eG zQH^Inj5|mRXc^_-v#@k_#$E@9+;_>8fZ0CDRS<#K-rqGdBDVJR25xphN&A{wi}w_v z@K&FrqO7Ra-}%MdR6ufcKkx9&EEOXd7xEtJ1n{4_=(blL#MwpN2;*^ALbb6sob__8 z<88`Ei2PWvW-+nxlbvNp$Bd{GkY|6sQuFint`g`h5GnM}Rv{t!T{2uf2WV~)FNxJ? z<%idZLuS~V9!1{@>&#FV6s2#OpJLlFm@JBINs*Xbks+PB2+vjj^On>2|dacpj z{Ncd#s5srLafVK9CPVwWqd|Sn^zupHigwE;5gqR|peU%UBkd3qpIfwaU6ANNby`_l zW`2Q5<1_7z%zxUF#%PcAV=ERK-5=50n%-~@j=d5fA}^(bCwXYERMD!pufVfGYy^t# ztPh^MDs;fkBODm~d%yy2UO|gyz)uLmvwOAGhacQNz?D_Fl*}fjx80=2ASRa&npNFX z=0bd^V^aXTIqJNpj+FTy)Yi2&N z5^fjhXgYgE6oleK(4tZ3PwJ4SMuKh8c|dJ!jrsYZclpxNXoGY!73+X|DYdRAgY3{B zNK;7GE1)y0BKbZ~5br*4_!(Fnj_Mf8{2~Ijt69-+&H2#a!n}}I>|JKDb2flFKU2&t z?w4aee%A1OvVqY9WQaE|%`orB*0ZvUW-#OwK!Ci|SJ=EL=V$%>baUaF`zhYK->)pGo`A z&MXYh!NK{;{lF+VxQ{uHx9hq?_lFNv|0(sShm76YPbiLI?G4;{R6kz+T3 z{L-MUE?HpmVb@$WyeF`HXqYzfbJI?fgo_-rgzPt(OYxCiGao`aHxIp@X(e0msd4dR z9a+P(wEsYX^v+_HeG6(M#X3P5X{S}TuObI7e--PQX4I$X(CVD)>uJ7#)i}$D`7T%P z1PcXE2GsWLt72@+(G$^GMJq!1rf5tYQh)AX5%RwbrvzVWV#+6FvkB8w{h1muIBre^ zx-W7%@hd@pWo|_&nf1sDQ2gxGezhVMUSkxTHP$>_(yHz(IrgkWZ7REQp(!dMOnoNL0e_JQ@AOGq8HM-3DtR z+9|j*>LizocBkBFT*%8Thq-LzyuW#vM{UD*DXiO}q{+S-=}W8$QZL=5_4N)cQG;Gu zd!E#PjyU`^rAek3%fH10{M6RIhww&gYN}?rc(fa_ysJ+52!q3 z3bs_Zx(NGo2-#Y{5MNA(hov>Z-@B3Day86u#QEQrE zz(twBqK^81$VIMF_nB;=`mBt|yFSCoy;ZA5U0N^tyITv@;jT9i3^G^mj+G!dWeF1) zE*`yxN#5zX=|%nO%NIBEJoKGxFpge!WRKWAn5GSZ1R#LHf}V&RMz%wWR)J&f0!Tbp z63PHRQfG7iOT53UvoB?k%*P-l2j^PB=u;lL?S)SRon5z)uJnDX9F{@i03wmlzO-sb z^n=U=xjL7;Z_TR`+q+UfTTF28U%1`%87h5FxV>MJiT-w4JPnpo`Slj~`46UkH=1+v zhGT99R0RvNUQ58hO%lJ$G0jGupRzFG3T}G+<9QSkgYOLbXMW^}Pgm>b%n3`|mt6{X z&fkAt+UUNV%XYowfxtIZM)i(lxN_1l=kYNmjIhkTH~vxnyl6vl4sOb(V^oGCE1&ri zx6QZyA83&p*{Mu?fZy#2AyI9loh!$N(DYz(Lk49PJJQ!?f>c!I*RBOM@aqe*xut)d zZ#YwRCLcs&SjBvYYB{a%9KdH%4)sD>LhSASuxJt`(EBWBNyH?=WB7_3(f_T#QvuP> z?9-FpvphP2O-XhwwH>2t;@R;o1Qu)W{y}6Nj*93P!DSjfAGZ7QAE*&}{>6bOtr^CDU5(dLw@#J(x{!A>N$As*ibc#RdIbX7;i?*!TsTUTR(iUzZ$+QbgTw z!2%6u4}u=}|8Q=Nu6~y%JzKSYGtr9r-AOw0)TdJE%byzlNd$xm7O0PUI9uy8BnEwZ z3paG^#VNf#*r<#qaIcc1HA$m&iiIVAdm3G|KlnWLM#A@jzFWr&YK>e4*8@4V3;(G1 zWq~sCioT*1dPj}r{H20=HqXV|P3~tjWW?Hz8P5huVd(D?yU?n8gWw0gYa()e9~)U# zRPkTNy#2izoPP^u=w9o8GP|JF)t?umMSg})?Cr~`p}rBnAHG4%I5z7U*{!aIcTzP? zOE1fgvzk5rfR18fdS0fL`ko|O{sqbNsL@c6^}YOI)jyE#)`>)!Rpu)%f@^0nhMsNL zoZdA=Hn(JZOyq0JF+1MESvDg8T6KON{>qJEWMO4aGxlwwz|Lyh3jOpzboM{T}-0yIz&ans?BRAum z$1jFkY`Qcb_635a`enqNzoeA=KhbA2iYsK!Y|VU#YtXjU^D*1QTGI$|k;~#u96*Ub z2pK>Eb}p!R=E-I&UbK!6Sigt}r2spy4h`)n{0#HZkZ2B-$WOEPKBl2JBKKS^m@qF` zc$%oi6R1SOr7h^D1;Un%(@{*fM`AK6aUat=Sd#ZE|BB{}A5Jg2FOL4+mu`DaCb9my z5vQQQ=dq5v&MQ20Q2B?N82btmEIrqtQ&_v<B7jQGqr}B@&mK^r>%&yHrrwVF>F^+NiyT zqo|<^Ai20OiIE>ZU-C@)K)MR{85*SIauM|>Z8=%LT=yRS59E{IM<#7%v|FL;)^WMJ zal`=0<_hKGUiNwht_kqc@b4ZZiAs_m_fDRSTF;Z`%kz*3RoL^^L2kO`I0)8|jFU_H zgO3Nr0p`BBmo`5k^kYs=qCZku0Tjijus?7M`q8h;b|qx?YUGHe)^1U0(7>XLfNyM`c(q;Rou%n>-U;HjgtcRju#~v zcUX){3$BbYuT`dipHueP>xk77adHY$-f*t~u}XXU(WTcK{=2C?paA;}wqCp{0d0Cb zX@3i%`dJ>SKEJ{BYdc$=Bl$2+AC<7yQIRc#9uCftO}NRq~yKyN>;U-;~i2dsyx zt$DcgJAqGt>*gpREE!4aroefBq0rgSZ}*p_@5;6GWn|Ox&MD**)7&yRRt>av^hwEq z>yy+XkDS7|MCjeiuLbJdbbA>z&74f9z%yfelCEUJi%*EK$S>+eJn^? zv*slMOp{AY$N2ywKyGpIk702$AaKS4S9afTa?|q z!>r2s%H+-w@mMYhmzQ@aXx%A~M7nw1G4$E)(E4$A&)~GwOo~)|j`3{G1SFZxR{vV8 z)P4JUQPR48cgCS2(H~nsj4k8&wyyIdsQr3nWyx1%Sz&^0?}dbSl!8iM-7v0>v{N-Q zEH0oSw?$A{i$XAOt;TzPu~u1uLH8~3e)09@sdn4N6RV1U7IYeP0XViE(k8Bpb*BGDURw74zHVUbvTa)SCbr5FLwOkUdtOZCr?{5lcHy6-by#oiHBa=PB_HMK_gm zw5&Ph(OInHBBOzTmB0qgIa9Jmx+H^w^s#=r4yFox&E?Z ze<0Z=++f`loeE1o9OEB9iRZ*k;_3Mk3sdNTT=D_eL5Ips*Zh)RQ+ao=h0q!|IR`2K zh8KrCA7>7o^LBU?IjJvjhv1e<4fVJ)v_FhZagjJTPhpia46Qz#Jkr{MZO1!inX(E_ z#agG1E7EBr6>y}yoJZQc>>Y>PbE~MX)5%PMQ0v=w=(P9bm41c6acp~jB;A{7^*h?# zTUbFpHxRao6~HbmXnHZ(?6<$w-`^=(tJ%vliQ@awi-x?kPx)WMSGNf>jWkb=F2B;9_;+1hbxVg&z3!JVP3ws3 zHH-8Q_UpChI_uac;T){v=n1j^gx=_ zW3q#rdy_eBP7x_;Bw-VzEw+!BsLBo4rH#bpRB3zOXfM!hPOL02lEBw0b>gU1NBG}V zj2$~|d}iiNs4(|n-EL7Mt7v>7SKJ{(-geft6aCNdpDQ2N2&W^3d#0*z4RDhFbeoQ@ zG22VtmU|N=PZkkM0%ic=HYM_?xqi6yyz!Fy9pz;pTmiISv_@}rc(4e2J#zv@q_#9r zN2c0^_?+4b;N zi@ilS>o19SOJ4fVI6}8>X$rI(RV8b)kFe=)EU?K_QSQKAURB8+>64S1o_=}od7=30 z0nKx?VemVn-$kj(xwD2-dPYaj{9Y4v*>C!+T@J}%0=VsZbc2FuI{W~$sg+a-a)1g zc}VVV-QkrZWAOji5`5ckn|(Ow*FbZ`C1rlkF-y)oEyGlG<58 zQhSP=M-qAeffC;Auro#BAMMOZ{!_}50k!bwQ3U%x4gPS~J2@=7)b~JJ$oA%R_7Ez4 z(iYHo+Bq~U+sVZvx~Q7J>l$1_B_=&IR^1(?Z_j!=O-_JXvLRza$prg# zxpIBtK8(W>pF5MWkee1q-MAQ9Tm~C>z?ia4 zkU~4=>4#M#&XQCd+9qY-?0~(6qa_8#-B0{le_J@pwPuK3K0`yvP6a!rL&4Dh;=H7+uY{jnHd? z$uIb9i2B=lLWjEoF04{nA}xkWc1%m-s=ElZ;X|NPkz)5-;8gr_du&^xO4)GE}hCCVJ)~6{YK^-&H*SJA{*yWzCH&53Ky;{@;~m*oO7U$yH*OKCaRTo5)rwtilx7b& z2J$4jTBi_!Rvh%SyMBs?abk~VtD*2Qfm#{e%ga$K`8|FFyzbYf9+A{!TBdSetoN(s z0J@ra5i+BB*4X6iUZ&|Yxio^)Ync&jl)LL65N=i6I_6hC>dENJXeYWIEI9LH2L7+~ z*X)B1cuV@5JPb$wcmA(Sy_sh7yqyygqR@5SZ~PwrtN)!+I)c%-&W?I)UpZNrHCbt7 zTB(LgXHTCKw(!%RsdzCWnzJEyTVLXAL_f`OX=X=nEZC`^waTd0__i(OV0`(YOuB-R zsc9iUmc^I#c)8Ptf7((5{L?ug_aNQ>tde@T>Hr&OF=rw0eq91`-*ST7Lo?meov$cv zx6vYzm26~G_tykvKz2e*?{>t+9aeG@`=_&Gz{5n?J zE+UJ$mY{Ak{nWRXmH5-gj&em8%G3w*>wN}(crlD~j*2d>{gSYdW-#IJ=?ZnH{nkwH z`RT1Kgw0b$Gp6{Q67pA7l#s7ZPrBzg#t5EW*o~WaXMZ>4M7!t8ymT^n``^UsDzcM+W4;f?If3~TNiHi*fHB3J{W4CaGO0y zuYC973jg%Y{$BNgV3RWgkEC2j=ZyP@{m5VcYhrm9_zfG93RGV7uWl1(FvxA1WXS){|9d2Pqqlv}b>-=tk2?+V1CS$T+IGe0O-d&`?$}>m{(W?3O`?cgBT*nZ zVi+9xf?ep{Tf_9Ldcy)udOcKG`HTf@2KLP)jZdxlSX)i>1(VKFL&rjz;HZkNDbJ*R zv8j&t+>wi6K#f&pBLdRuUJ9VVe|%SAaj|61bt>L&v}GYA6vMwlc%nP`-pg8UelOcT zTX2tt?^e?+*;?8Cah`IqbPBuTLpQde;DE^NN#B_t5^`_XvikoEsmUQsDy%TSwUC}q zc6}jtPm=ENB(%==E6cjmj1{^nRv_OO~68-*1%*E(E3?C4En#vvXw1I+yufBDu`P^I+GMOZ{VH|o~|hNN(u@ck%fWB3DA z7Wt7f^FEVGjdUinG$s}2SDG0O<{n@4gcDvo9vMv^hA(|5J`m{kd4PdoP48GLACdGn zFSd*dElDM%Il38eX{o*r61i^fRE3eEF+pr0oYpQpR3-3s)Q4&WgwEMkfFRg6Rrbo# zVi6XBMt*k6)+VTgRTJOt`7E3Fnay6LlcjAJ{7AZEfVqTd=Mj+vYL zeUK9NpA65QGjw6<-bO=L8|qzSOTC<&Wk%kywWYRfwrANMs&@ZT?8%q5a-*}A`BQat z=H4!#BDxt*!uKINsiv&@Rm4#UT8DlWxtS`TF+hW{t0I^WnS%ay7K{-^Tt5wxzz5n8 zYxRLI1~jARf*hbBXy|jKDGKq$>QBh?-^V%0s2+93I#@ZzlS$~g%-fj!x_ImIH?F}) zOeQu$LPi_$3dM4x_(3;Sp|I{vxXXxzzgfYa!#HkKy4cO^M^;1b!KwL%d0-(fgfgV( zMacUkDp)WY@O9^t-Arf5GA!P?GIoZ3LPKJc{|-FV{g{>Yp72V$VoBHWQQ(+se<$O- zTQG_@`AXZTp0()0wfjF1f?|*B(!+-6+Vdai9{66-_9|nIsQnb2hw{n-MV?))8~90h zfIJp$_c=hxQmq{6>!%Psq1Vwh=_clGU(2N61R9M4; zR}L+*`x+PEt&jxxvY2iiN=z`vx#3P}z9|Brs4MjjBGqo@@4?E&d}76ZG@~{xiFh>^ z-^=3II2|C0%59b zJAQtidotVU?DqXyYipGp=z%lT%>>Dz?P9Vh`fOxJtlARXMiwDZNsIzCGYGY7?)P^_ zlphf%>n&RBsiem0nfqgYBfrm`(Pe?Be0dMxP=-`+kXO zpMQ!_r7QfiO0={R;hw+Lz-h)!^kpqa;ZG%b#aWc(-GQm)y?@y)0%-9r?FMK0((@80mkMp{SoGH3^~nqweR+-24PcjhsKw(Yt5ayLFlbJepB#O4{29Z#KEE^HBeodQ zzpzvXGsoJtpt0y&K8;x*o9T+NZJ7yrRk3roF>Oxr57OHgt=i;bxYLvwFmryPk>FIL zArn@ydtr0auX%k3)}BxO>aPK3b?RMjMvLbxk8Ob_pn|pH$%H8O!!;8GW%?uMb^jl{?~$*xsb{? z3|%aTKT0Uu{m8CS$@4kLIIxmv-0LUtDZ9^>2Va~NTkSh${AymW z|D7E@QS%k*K~oCOxOFARkZds=6_vv-^IGn(z6Hbo4QF%*AZP# zV=P$uxYMM&u%BlugA=`&>GS8&xZk;_Vs|Z;)GO{3Oz#~&oRP7>#QlBPJWa!#v9M7* zHXD`nS-RSFPm<@(^^ZS?o$R@YV}E^gmkxMc8i?M?zM+xI}Sul+bkWU~2Vq+mUoJzrV9N zf;uvSW<@#WBl-M7tzQ<@b#hMdX@!;P`c7koX~k@sd0v472q95Z#`Og^9a%^ppVY&y zOunCzQ65p5ziGVTYgc`Iy!RrKkvw95Lg=sF0zGi_X2hi;?Eb)<-wizh3H%DH{sp!v z(I91vuCkZ*JsH@6+rHbu2gKMT#wKIhQ5$Q-MpQ<&$VPOgGFIkxBO<80k937mroJWboIg?d;NR{Y{n4sZkt@|#*i<{br=OB-MF3+Hm><= zfPO}ce)sq1NSzEJCEm#_rSZ0&hV{4Y8XYG4Vm28?H+?rlM0t7J!BYW+H=ZUQGmAQv zI&F;=aW1B2Nls+gn*E~hm#;46ujJwQ{OBOnpMNc@WEXrBa;qeMu$qQH##*n_bk5#B z9uE1&tsjhOjC~VpsP?C#;MrvbFo0zxmmeM?<)R#?$RUzy=&9;!zkL15 z&mYew-t{ALg_A9VMhNe1GAF($&v^3TwbRq?HHV}jkI9r6@M7BLVp?%k(PDei#fnjT zestk44zh240nEyG)%iC8b#VTdl|D?>I$)b@KVIJbzrC_x1wU zPb5RVwTEn8j39rWm(;`zP5l0V$Aw;fhA)}d?~3Y(9;BeclcTj;AZ1Ap3EOH{2IQTW z_mQ3c!%v!XOZnr&+BR7imrk;b^~A<}H>ZM5rf)hZ?hPu_X_y?hQA{Rkuwq*#82i4$ zC{h9vH57)12PqVWw!A0gGo8rnqxT9)`RbR40E8_?Uide4kav`7Z%6Fbvympwh+)=Y zP8x&v;(2l2VT)b*5%LrI5ER?3pM1PD(fsRSc{z3bG&y-d>1t*sMt*xD7(_};RCMCc z&z_7JQYag`z_Ct%aTKh(6Fh!N)wlUif&+uu{Z>{ADM{Ms&*GAh%H*CCWfLzq3mt|8 zORzJZ;qnKX#^c_h5Y{CZ^$C!Zn+Z+@c|(d)4!Emn>F!?oOrOrfOI%U`oTr#Wlaob_ zIG_3lt!~;{Em>y>8y>>(rRM%+1Imo0+}HoMDZ7_iw&NYbDfxk$_mbb1zL$%J{eWjY zu3S!=nese(WS%yiP0rJVn_}Ylx{{zcjx!F-#@U|Ugwr21l~H_cbEt_g?w!0ZY`qxl&HULQmk*?f zdpDMKJX%S^A{s*CQvzhRWAOzi5V+ZH3H}I_+ZGIHI(WylN7%89>CW1tXFdO#RGnUI z6RxZ&uBK=fi+6a4VxoyOskXGN8ep~+c`uANA2J3s?$JE9)axxmNY!lx@60LJr9cAAI+jX?CNAV-wV`~ zO9W8M2)`i|=8z}rp;@%pUKMEq%6o2fEckJtKhf|j$#t*|Vl=LqUIDz2)i~*Y6@YUk z7+We;PgWD;H~T2Y4)>$ebC!nL=GfAUJ6D*k+j$-+yd7q7^-FLifq^a%;j@!Kkua4Z zkv>p(91#bUPelIh_Hclfa!clD;Yd)XoZNPe$O*A4A`Hqd44eceqA<#)?r?A?2Xr&e z)!mQi54DsfbCTOk-hJH=Z(w+c&pP@|0?}ri;V3b(K7-Wj3CZ z{{Cv)Eg#ArhnTV^&I!6S^+Q3WqkX_^=`zj4iCb`L5xA1-urywW*-5Hl6$Q{N2Iat; zcNf`hc*20Rag2Vauyw+1l9Ru}vMl%s|{8Mid{L|Q1@2Re!+M5~CFC0@LoRLbZ ztLt%JVSsf80?Mb2-^I=a-v0fss{Qvy=Xqtz)7kzT#2>#aCoFUYdY(wFdeXm=n4km& zSWnrk%N&P1&6BqsqL%SnT}P1+v9FAI3_m*1Ex~S)ZlhFm+ET3Lyg4{H)_S>T2VK43 zo0VtR9mB^v&%ky?%--19#<;$4R20kM*xzO{pewuOaVL&A&M$F@rqWfDD>H$G!Y#xX z0%7_Ll)0i7B3iZaC}~)=0U%I5phifgB(M_;K*W9EG^@9ILk(lMv}SN-IC^vnAx5H9 z`W8C-XEiC1?x0^mTdSV1K6x_iYLM8&*e>tENoGo#bapy-!vsTSKkm)JN65njZ#sFH z%WDX+C0iy_T+k----`5gr{3||S&ZM=xZs~G+PVYX@MeD}4q_XmJ1N+6eQLC}qR$fq zBn}+{x%yF_vrv-)2u=N;NnaOWy)p+uQCaIUu97;%CrPq0JYIE|u#3~ONxgI(=zciNpB2?gDG%#F9?9d2h4q`k7aspHeRP3HO$WX0+#Gs^PX##gk-a-wMLIn!>jg+< zaldO;d(7eWw^`NdmzF!tJ;liPoVueV>pHFyvVYU9M5|NvwkqPHpd3LAHVKd4xcU-V zxE_;`3FKvF?OCaCIID|f<$S%*)tp^kw{<#y7uJ~8u!x(Pbt2?LM3egt?cCVy>;e7x zAf~7x>{6WS>>qMHtu+(Si&qKQngn5a%-tcDNuEOxli-4Q!ZWEg?3+g@5Z z%@G~HpQ4ZsFQZ9SS{uG^)H^5rmG}iGi2`}GUUw#A$S|yT#K7;;hbl~@EbOz&jOwcD z(0-7tdAZkV*=jyubZO z-$fAHETx7}HHR?FJpl*gI`QSbDlN9iWPrPVeQ)@c_PV+g*XQ0RLpGDu}A|5Z%N+(T~%p{?8Vi z@|INvMx0&X1g8ANE(j?TNw!chH{_|IB5O!QB(u$1_ln%x1y)NnTarnK8df;|g+Xch z?;j`-A$o%%e-`(z z#{xKbeDB>&`6^Tz->YCN{UD;(x5vi?83f##p;Pxq^VQDwM*MnH5F1T#w+9zZFyNVk zuJATR-^vOVM2YZJ<9JjDxqCJBhCt9xP^Ai#3Vy9p(@~Q)@F6ij2@-3=o34coQ6h0~ z6W<+@Oar}4M*GXq{e=wLvJhq$Alp@6N0ap9wq`f#evAgU+?C(FAQbB@$bHtpF{U+% zf}iAU*xuiSGSEb56zZ-bC@NI4M+33w%^fHD22Z7bc z=Fh^wpZ_D4=;vSdtox7lXS^$W7f+0M@64_8Mc=`!?m_yOeQ;f!z2jb?uWlzJ$3Lq# znJ^+-vq}|+Js&9`%cr2WX(`4QPHJ6;X5%ZRA!Nh!N|g}7vfTq{#uU%FCJMRx zG~ND=kbmc~P;V#9G_+b<+>h)XS?ks=G#A_%;>H=z$}pQ_iZV9N>{enM!)3Vxo*c@Z z5gI;=PkjiCni$8#-7hs0f;XHMeZ&I`o~0if9?lvsOlgo4NgE8?Q_bm6cs91^bG3&b z2;R^eoUL8(6O>xCA7yzCHE;L`>bIv8=w*I?Y{z4y^_t;Fhzf1Ui!a& zpP$vwT<5r}GH)ENrR`fH>ihrLe&+Zj{K2oA*T1Ogs2l!w4kO(#l9QeK$>}*=o*gn_ z{N$vmwvs2sHA^9^Fs_i(rBXW&q{BvjyGw@PE}9fw9mhfPRSq~4^*XPo^|`bnW_?T* zJ-O9(&0ZNdwMnG#`2E;q3t2oct_roF6Z5Z%%xUoMY?JDGD)Bi0L#1h2dvFz?c_CUR z*|E1Lt%}b!UbyZ?u|-ePYEqu5ulV;@{tqznF1m9?DduDpyLeB|PLt$=v2qXF^!1Wl z7e7T8O6spuy#-Bx{K5NhCz;Bc0*n8C^l>Fu{Yp>QZy4=0*fln*?`dr~5}lc!>5~+* zzbUzqzs<574H~7`oQe9hx2VBp`z_#BU3vWF%dscFk5{#Vy3h@oVijy@lj#rU3x7y! zxFEm{Ll=<4&*yc9;yHNS_(=JmnfgyZZ1X`c`gyM* zd&Y!RjF%inSalR-Dv`eaq$17AHPyWK3{I}6JINcJ4H0zEOm}h5RyY0|{vPowsN%!Q zhW<~DGDMj=jrOJun$2yi%9FPua3N-gZ8ozft)p&#*9;#Yc?I_JTBHf05x{)klI0)E z7k_H;xfOm@SaO)6FY!b3eq}z@ry2e1+?n3m+~{Q)wasjPw%-=XPOV$V%uqa zRa>l*W`+tlL+z^;}<;v(-%x34c`aWp>?FWa4t!>?L1e!-!Gjl&tPS$IZh%!I+#MX6w6B z=&d9lZ=FMzxK@QH;Wun{o<;Na5;M;&OgCqO!fj>qf?bv&W0qqRQa%EEj-KBvRO%%Q zS0}wjHOmOA!lY|zrdj-H{hMvR-qjRqlWPcXiH>WEn^;a`cc2#=mF;j;-maU-S}f1Q ztnbUo;X&qhWXs#yg=xzr*38Rgx*l_8dnG;EZ~;{TUvSF&T)qRZ)Yaln&$a1=%UQ%o z`;)t2$#`t!0b9%+>xGpMU#mJk5I(byHJ*qnP!RL>Hs|>N_z$0_)Gln_BPvQIa$o)M z{v6_CYz!Px%+$l6KgO{Q*M9X{-=FgK|flVuxmvK_DQ`{BOPsOebs z=&{=yg*eEVAYcAhUM2(=?lplOvtxG+zCfJ$U)UD(xP2$o=PA^CBpoa+wk>Q`_vZJU zGnR+{Yp`uf<2B*un%(&`7Z_u;u&ChX4X({=ROtYAIP;74+%esj1&M!Xe;K*V?{uRz zQxr0}wUK^DKE{tv|0&`3wqJa>s4wp}u3LWt5jw} z$-2aHMLi??jVWx+@y*=4=KNT;S~Ak=`z5DlX42cF_`jBDb1}k*WTDD2?A7n1X0bWJ zCl0$+$$n*Q#dk!9QJrjY8J{L|D5X_pGneOirmIXe8=@^}e8Pt2Sae>FagJ2d?(BbW zXrDl1uAP(lXYH?2$16@I(=u|-JbxYr*Lm+uFVlR!qZ=>xh$kg5Q)RivJ%jJ}fnqsE zC}kx^_{92RlqWoSv-KS^hiQG{`wviwOTW3OsOtIE%+x$4>q}DaIKo+pU;m9yEVPh`5zJ&W=-G+ zb6e&f!nGzEKO7&sAPFtpCR0TRidPKjPfO|ZUZwc1W|zVY>Nu8V(;YgYzx+W?t}-Boim=gSTfz7v2X|OL8%-GI+VjnT5RNm`zXU2vTla{C4f+xxwVB{gHa&aFKd{s{XZ)vxL>m6eCTUyi1b zhZeYhy~Q&rEgP~l13Y2oyl3iXL${%)g42yl9&(S`c`qc{BA-rRWZEio3VSL(O2W~_ zACo`wpUuiR{51Z>%I;h55h^gVcl@g3AR+=i{VDusEiYzpE$2WzI7&a5F4$q8(!uyi z)U5Wwa7dk#UAOUSM!wQnhR3$8XVFIbpB9Cub6aF3TS7QX&PbT_pjX>_@A~!AFNe2KdO9vU6kJc4wW2)}MAL^{@)NL=@;@IA!;UaC463FK{oufEjP4TNLL7r5l z^xE4sXr;|^Wrm-ELy&>3cfR!7v;S`6tK>c`UT89DjqQ2RkF?5oJK+D)bthk>FPp7J zRuo@2bitj!dt5VT1cjD=e417B;Bdw`RnOm$!5w=u+WP^(go!>0kBI;iX%(fnF*FPYuS?Oe)!tyI))0j}i0AWOw;N z&+iDKYnlMXs;vds#k*pHWf4%5~-nY zxE8l{wJ@fXJUhrSZ?F!ECj=U*X1wv+0Y<@}H3|N7!SJBx(^H#Qte69YZX+u%VSdEx z2T9G#wD4S<9ZOV19UGnf9qZqn8?6kboFb7qu2h#o<85{H*S#PKzLlNFcG0@Fv1OlP zjhhU$I#;;gMnKi7YV(aPjC9sggm%Ze>-8I0^_opNUJzc5SA5EpV?VWh;`EH`=#_Om z-mm%asy&W)O(Dg}hWOTVlG?VvE*U7huZsHj^K8LE<5lmniODu^abcLh{}fnwt_$Jv z!ic>o&hx`sVR2vkF#$sXgyn1}yQXpg+s#dJ)>wSvvwt8aq2-jB=vWtI>O z1V=rgk>vX=EXZXx$VNCu*jh{z%4i2YL$TMdZ{XowPc_5%JSc|gFU+I~3w6Q1rJ`ry z$NvDNs6^l8-;XEwUAlu94Reu#Ar{#KI?<8RIG&I)rE?c53qIO%gcwcGVQ zWc#`J;Eqd8ngzcd44k%i)g-C6F7U}$Ch!VRW4)Zzwc7(NRGSX!>!Tuq23cYWVJSP= zMB4|L+EL3E44s9l>+VqtU#Jp!Vn1w)M0u={2!j}sJ>%_<;0*87`Z-j%g&TYrojSQM z%n-$hEAA~cam*EG;E z+YG|=?DrUuNu#E9NwMXfiVvF2zIQzMAK+b11l`5{a)9LSI6AZ7!rH0VNIB&S*=%@k zf9)p49%4lw;sW7>Qw3`UQ%XyxiE9m%{IIcpk8hHD(Fu4#HVGXDBAF@g%zCC4EB=YO zKKeJ$45n9WNN+jROLB`*-B*ihy}owv@V;_p=tRRSWxs0-nGd9^zv5TZF6Ye5jh5?*Pay%euc|1K0^&#%z>kM-NCkFSa#1SMyGH-feZQm!*Dv~10m2;(4R&g z$yI{r7D`O19~fI5_aMuTg=j{Tk(rfRg?RS$ah({DC|N68|q^ z(L_e<&&2u6q}Q#aOZA?vxC;0%ZlURH1*HU6mFfA<0!R)egfRe@O)I02$vITPAI;x& z*5EiHYBvXwmQr@%4k)vG+!;< zea^QN2}uZ$OBG|^gC|37ksOQ2bx;Sx>MDTrX7C)ybg%o!cZC6fnDS;5=70jLNSf!f zn`eBSl?N2q5m-6+T;dSI5Y z($LxQbUrSMgGcjilKc>%)K096tW*SI*e&s_M7yDJtu*F8%XwMLMck4nv#g7J0jJE& z@!bptX;)?QGH*vm|2h0ZW#0u>1aF_#*Kf{o6H~7=6I=i5tI`sY@USwMx+lCP`}V@R zfd;m^lGtCYdRddB*oj>kW6gRX4*?$t`SrsA(D}Fm8fQ4!bvK@x8a4-=*KgQ9o_jiu z+euPeT)Pn5Ow((^+axWbU_Vd6eycR=I>@l@2U2%g*2VqIw7B5~e5ju8O0Kl!Zm-no z`l4*qT=?62KAp@+I(aM6VHPRcUXb}p261wWleeF}Q{$!I*@i}#H!BQk8m};R!U&O_ z$Bd>!88^_QsE`0G3f5)o@9O7{b@c^=!B*sM<3xn0-DMH+;XxM*THCMoc!=`tQM%1lX~+UAC1PEPIw z+XN>jqHcjNy-w85J8q~KYzn+*{8_WI);Xq_y@xp}HMudc-9AK4=2TT4fcbPA_4OkG z)8%sj?c_j@5>xwJp{RIiV;4WmaZ8_UhPeiRww68|3A^2v!UP-dUIb#P{gOy_Rz0BW zMLw`Cc?i<2=S@MGyL%UC6nQ-SW+e~Ee2aJhIbdH0Ump+(`S|0pbF?R?1S=YRwhltY z#3>2+_G2GCsBqbbpz)fGQg9y#ka%^Mp%--MIYh|VWN8`sGo!lgkU6dXC%qu5h)xcO z06C*>d|*Dq(9S&{bL;~Uv@bx{h#4TOLoK_fvKcyAL|y~Q+Z{t$h}6|4dHF$#(zns* zQ+Lbg0Wu&E#K>8b1S1XunR<0H0FJO=hn7&y54S+cQjt+heXSZ}-_(q*rfp zLkN(-Mx{Om-UO+`-)gj8>-GRwGEkD?>4q-_c7NDZmyx_RU>brv#KLgvvKPG~{s)d6 zY$$8*7&Y%oXST6iMOw0U2(!Bl(t)m6cM?fmJ5F!6A5g4x2#vW9j5*1t*DdXN0roPGrV+@%nqT7Fx+{G^ z##uD!8N7W(h|+SE@4T?aF!TK2xfRj8R&3A_oFbZ@p zGl6tS=o7Wn%Ckr%Q4EI*F!cNj&M0V42G%Q_fCc1+AdVk1drM~>hwrx$R>Ic_0$62G zxx?wnX~XSnWuDRjA}CBT5||jNopnINejEb3&V7?tjWK=K549{17xHD^0lD?_QR7*> zmh<7E1|hFjSE#VpD^R>BYuk7=c}-U&wVpf#5P*&ya3vjP^G#tDO#{gQ4DRa5q-M_l zH7sNYS6%qi+VQD?!_PI@ooFI^{VEOGN8>;P2q9aTzFFvy;m*w9F?5E8xY8(w6~q8; ze5ocrqt2}ZaLl4SiX+wAl075kGz2C_Hvk_j80k~yu5t-Yk>_UNq`oYj;p)0@RWu>nMRo)w18>#uMbcik%~zCDyz!N5AT>OWL39){XXx&Zm3z}quj^KqlfwZc9xzg!K{Q%5Py|f9AcZ77EvIlwsfh=@lP|b8 zn`0Gb0An@(H%CN?Eg{mY`=`duzk4~|G3fGlOSWP0VA?nEdfRQoWKEZe!tT~WXXsJ! zFqp^VMc1?TO)GURZ0UpYY3-!q0r&p_1eX4K{n(vz4Fs%GmcA)vbEeqUVM!^zZ?ixK zC4er~U2|z8oeh8Vu5lXP(~VsLhP^_;y+h!OU#SLM-5IiRVig|ayFVK9{jL`8NXut_ zOtxoOyeB-S#&qS0`+Al(u5cr_MzWA-ZQbI58lq@S4M2Fx^y~B!0vuF4PUQD+dO|cQ zRMtKa4J-`}O#&P};p=jcYA45sv=;q(S4(6Iu#Ef4^jq%t1I6bU_DDV)I8r|E5mKcm z4*2?Wm()9>S5?12oVZ21LW018W@|&kNVz@D$*FX)F==tq5O{%2y zr+Wp~4+g=!)0qT-d0M95S>@l}a3-1rnK5u%%DyM24$CShJDQJ9BiC!7%9qM~hWy)- z$iAU2Kw(`P=_({RV8jscjbXmcy&$9q-W49&B*dFES8Dspq~|6Fl|5NCyvLHR*M8kN zdK1kT(QtpD)wdVOEG~M~)H`2j7_!L2_6_v*jR%itgCa8FRg1uH;+Magl}aB-p-ffDclbq{Nik6u<9ZajnFAq#gb36 z#fhG`*W}NcpufHoQI2i*0~J!%^bl z;h$aC8)l8qj3F+{f#stesEFPH*}ZI!_8d;TTQ9k10on)Y-R*2i28OJAoSZ6JKebA* zfz3qmj#VJ0K;gAo6V-=b_nswkn$iep^=pSXizksNP%7Y=iF!$^X4=%d{FF+|8}`tB=Nb(E|W*7y}6o9A_Y%<@R6x zi`Ua;uLX7+H!-JM=R6|qtyMP?>Ski_b8o`em-nBW)|Sx5%#(|(}yYJqOoYaS-IdHod3U}5ffKN*LI5GfL?_2TVqgdnh>^)XHXk|`llpW9I)>)fDQ&PXd5ta{wI}G&wZ{tK<)(HF zztvS=X~X#)mzU3vHPw0B;s-Uq$o)XJ_$_>V@>Fs2&L;MU_Q8o;d-7S4_A`- zdCz;J*Rl&Bxt34g%QZ?4s?NUN6139qJ80rbeEhqUd=~M9l-mal!LDp)j^z%DjdKFa zvJBncw$vuM`F$dQYMJV#XW6cz#&{j~iQ8>Ki43m2PE}JZ5*R5f}eg%6~ z=$~%Rb_&WgU;lQkf93QUU}$kodoG;f%f^TH(Ky2R|E;p*AMa_g9L_FjAhJ0?Lz zj{WX=(64xZs-B*O82id@&NS_^5ANbQRo{2bV!fRY>kO3LU7oQwr!-qR(=*CnTJ!|} zC@Op>{zc-GbHQQVxz1e9#cOklLBXdR=iKf=zY_j2Fll4bgns;Nk@~1#e8X`5#VX!t z3FcnhK3sR_66A{WnlQO4{4;-`kozL;BS(=XzxZ|@*brNQm565Ks9 zGMi0>lJ0?aI=r>Tm-Tnm0YujvcfbD!sNK1$y5WhB@G>WF_eiW?q}@uNDXLhesWI70 z^0AwcR!8_3o7f-t-mm0$T5F6V=WL424(PmaIh4Ha3}y><==dDWG_&s$%7r_P@{8p1{qx&ZnYCGl@KWExL>7zIfa$|l~Hz%7KS)oSuGcObgDJ8Mn z;yNlCqYKePyFNdIm;kD>4Zo`Jw}uygb3ZPC4=1~3W%PeKk$IW{yIbUc9CDQjMpo?U z9|_VpNHktaFIxFn{S_#9KBM`U&@Ca7vs=6u)NRgwaab5MB6qJ{e9kAPYa(qX7TqO7 zAf6JmCffyrg&*1(F$c0$?;aV;?4Gvj>o;^9B>Tutc0Y&}-_j7j)|5X#KCv~Giy1hU z7BD|*b>_YPST8Nh!InPKqjy!v<`9)qI$ok5Rhw-*ml&}gol^WWc`a6VHe#Yzt0Jr- z`lr>VWXi+RJe}`4nQLBWvCRWKQV@II>l%Ny$egsGyo?Sqq7AAI~jzM1!V0@?}RCZUP!Bv5g>&vUHxN2JFy{s+)L zUh~~WIW#Y$mT7AF>~E$oLhK)WYy>KdIeSuxD?FMweaPG!m%a$+lK_#D@AbqDi}g^r)#*w|HCNzY1gFMTvYO0>LOSzgP*!rpVU*6)&gjk zZ^#8-e&3NM$_+?uRJFzGy|2Png~=W0yU=eS2o0!r2ZIa!uQ>bSWtj%;mvZRTy{CAiEi|LK?^yTEP&CoQ=!;C%F60_dUK3*MNFP(iU^a<~l%$;-; zXk~LKyO^2bPF7Af%+wrr7T_a{MB~%Ugr@rZ(j_aa9c?1-M@ubTQqy$pOj2Z7ZoY@Y zbg{1*>ncnrIQ3Kg2oCO%Py1w5&dVjnP7{rJk0AOju_33~o9h-GB2!cLZB zggwcp!uF_Rnr4YBzT_gRTaMMaRdvN8{IMS-CZ7!y;A$DS|I;ho$+LKBZnORQ_@3Cb z*u2t<-@Wlmm@>;g+9Sb2Y0ch z%AikdJHLbdEA1!FC##mrq$qGF!@Jie=a}PX5bd_=CxR~G&1Jx|##{G?KIKE=Zs<@# zWfrHPmfrBwU(yw=q;;OP#Qis3%#Ca`g;O%6a3IxXcuPW&Ovn9488Rg^r_OY;%vTl8 zdSdK+rN+IH62!@Qxk39`%DQ)1MX~?&I*_lqe}kq&aiT)O0UTFTn(l4$TE1Y>Xfq(g|Yic4{ za>cRkG;gQeVsr7XBEC1u5jU&{1(Kc-UZtc*DKy2gMTB2!3E|zGWdb$# zij-o+S(>OqpfCn$?#@-(esGe*vE)l0gR-~u#v^6M1zSU2e+Qh@Cj2V(KJ++#Pnza9 zG39^pu6nHc`!5~G@~60@uUM2VASmj6)LHE#hCvLRpQQ;3XP@{~>B-~OV<3@jp| z{qs1$k%+2uL9mBqydQI&8qO%VtAoR$&wO4gAZKMNUiO>p94#t8a@8(x%l{?s?Hsea z^6#-#S84!m&?ZTa_Rk0qnHWl_TQRPe;5f2Q`{0`IlhBZ4RP%h;^f^Zr2!ckx7WLoJ zSu|@C_|N;{7WGn}BJ$)qpRpIf!TO1sRiW?qtn@K<_fMEAOa_L!^c8>cTx6;%@er53woITr~e%d~JIr~qA2}zXLWZeNGMzXqV5?^Oo+PsY-UY8LG zX8X0Cqp6MUQO1BExt%x7a^6jM`z*tX8Oh)oBWT+)61wn~farqQuNaXT;;w+@)dfYd;1Yk1+g6ad0 zrlY>$SJ)(e!BvQ@*%RDJ02`8cEl8l*wa4gi#|=$)Z2^ju(NYAFB;rTy3Wu@yu;W8C z)P#|OaKQc|Q2H2ohV8`b%BT)0DfD0AZ{;B@flbW1gLRZ41fLW~vGltilLTau--z=d zTH|c-c=z9{zni1p^HRoxN0V-wC<-rtUAvOoXr(fXTj&tANGXw2kagUr9K{eU{vnPW z%5dFOd}P7^xW60Mj!p8*vStD70A6y#nB9`&3X+kQ37QVF{I9;ZtTl-t$`rF*UQh zCF*b!7*Yhy2yrM%l{J5j5r~F}%^L4iILTFwr9LS<={O;byGGfS%qd8RZ%EQ2-+5gl zW{ar6j*9LIIAXh89bqiH_b~W$h4Eg(10N2sos=&JG4e%>3z5R(b2!!l2@taI;?uvdy6 z12iq69QMo)d&#hU0qbAnrK*L0AT4cdJbOVhBBFbu$4}n@_wYBpbBm`d@qXG zj?x794+dgnuq4ow;-K?cD`F&AXCNJxXqL$xfV=KX@L~1>7IXR+`Uf<$S6ywXhz^_D zL=N)=oq<^VSfd!W;M{ZJLp1F7lvhH8KyR)SL!>g^kIYU1vjWiWXAF!0mQK+o1aAG$ z+e@qrkrmP1xxB*l9P)?Fm8B&x-D9D2aB#G+M}~eBv+aNBurTpRV9)Kw$B`;e8Tj`z z0SdO7<+)`GPBp#BCrg51XQF@axVwvDDIa+kQSMnIi#v${PXJf0vIo%B^(4Os%MeC*^kXEk4{FapD!+bxnAl6_Ez=|Lk#hV(DO*RLa!gCXMeK295+md;MSp| zhMi!^U1hTs9*x$YwCAi+UqSxf+zM8m9&zcAxU=~~285c{+K<_X6o?U_w|lL+dD%7~ zh(LKWkT_DFA#n(=w6iZmJtA`dRjw<=eM%^f}Qu zUHoA(lH?LK^Wo-yfWcF46OF*PEtmGen{@0%?oD{nU2tkYl(!xSroS&QqkwnIFuE7A zq-r@mc;8uhI1+~=W$be*4`+{LR*Gf)V`zhVui0xBe6g0wVDZtq2kyFgE8ar| z0226nefNS(M+HvRbwb^Shp|Pd(~5Km#_svDD-tg-PE>=ly#&n7xl3>ljb=UmnO&}^ zp46Q#^#!=5onjrfnv)gKhoEzHRnU7o5ev(xpIljUu`t8LT;0UHvkq+T9eUyg<4i~J zz8JKzVVRaPX(we*B#)rf(`#VkH(|nhIaUunTIU;(_hb+J_tK0da?PxpnP;VFqU%$y z$j$S3dBQ|AWklp&kd^}Vk_B>)$!o7)?`>>u;Ka~SZc@CU31JhPbhG%joo^=IqBaO$ ztPCG?B9H#UAsUO0?R0G>HS(E5^J7AQtlm`RNqUN`e=1)k#74k47;t0>|6$^PQ4;}d zEbqGr=de4yOVQ|~2Iy-kKzsFo!b~dGaR5NuD|*0VJ_+d@;Xb%Z|IF_pab(RLwY(0M zIgYE&%gflp&g=T7aW1oL=fum!wjzD0=vMYf*>Zrzs{|}f06@*c=W1hrR~mZJZ-6T5)v*S|^^d7+m|M7;{HULE*Crz9kRtRLRbs2o51NSTNfvKk-_ zGOV68O`jvZR7_bI5ZNN-ZTyFYNT&^iDLXUpPTPA{jAx8GW2!D(L^3uP_3!q#*KF6E zzOvufmWR!SdIQjFz<+#Z(Wx-Ps-rq)OU>xU{KsIcs)Nz>{c37$4?7wk1?*Dw6Mc3B zAPc_?HjK~Vj(#l71%$eTDMhUHrJ@s~bfH#Nw&aSgtCV|0@$*Nslv-R0$V$Yh0Ej*M zp@WGT#%Oc11D&I(`RQR)wQKc9uOK@7BNXGRcs*d>i}_lychmK zKQyQLNSLB?;AXmaW3I%KsWkt|o+yTC{WWai>C34fbf&G=&*Y_E(YCxM3ewYV+Fd~O z`)G6Zrk?W<0OJB`VLLxLnX{XNjA{W^U2g0$n_Ml07mZG7(RT*hR)O2Q165T^-oe|$ z?{)7pe2{H_9DI94aWg_gFQcFOYcW)Y#25~G`q9_k$jY+kl^Q!kv{4t^6*;!Kv`^L zi)CPHw)DLpE^@Od)L9<0%d6Q2nENjx(|P*sgW7%?fFz^zV(MfhMOGNHTm;93IyZZ{ z8F*^3D(h{N;U{BOQ5kc3S1%1e)~Fq$O6SoNwFZ0`R~R?oq#z`Ib@zzvaRB2V z&x-=R#)y~_%cSQvbee+^I(p6IBou6|LNsh|772W#2b{I(!=KZ&ABB)n3;ky;EyoC5 zs#c^YclZ5fl`%b_Ntw`3)}KHxCjhjx2Dt!sp`a{E=JzXb)mzlHMSID@zb_agsS3gG zPEr+BmDe6O!@vFqUkdljk^J zTai*`Mta6Pjx0otW)U8aNS?~LEkjK#Y}&*vJ(f2h76LzTRpx_}hoj0;S12Vf`##?> ze#ltWc|XUI;P>6hkl>x4Mq~S;%nFH_#j1r5r51_Moc#o>oGPfgADO*)*-qFZ|(2Sj(phxfJ?N+h3_&8 zx$?C}=5IP-5|tI}gl{+x0P3NuWsznj>C3Du`3wz-glY16 zxCwr)sMp}(3>++!E-fbn>=)16YU;=K`RfE9n)|5H)OS7o5d45{Z?Qj2s|YsySxiQD zTW!Lzg6sD8??EGb;@6z@C*nyxXEkpZ*Q2Ll5tGYZtq56=*+GgabJ4HCF}mFC(uZuDZhGZen^#`O(S6 zOZOdq#@Zv`PmKKsKF&X}0I_s6zZW^u)n_fwYeoUzF*jwgLv-5rM;QhWa)p1EVnT0g#)2ri3Qf66 z@KGa4d%VSh$;yY3U%p>px|IC=F%DA&W^xvzFF$hxi;v7hL}pBHi~eX>yN?)}o6QU! zxeyvtw!`Fu_51bw$^^^V-b&*9J|FubTi5RUlk~(KLi<6Kem?@)tCA>|c`I<$JM8~k zyvELD&A9JMKyR7aC|Vo+t!K?M6KTyeIHQxYI_6RFXv7%pwY=*!=4&F$B(%imMGISM zuBrBKanmk)ob=;NqfrWj(fMajV8ky1l&y(doO<(ED_mH{TMu7}efy4)Ab2Sg5s$vO za2ABZ*D_$0{A)T|-N_`+`4=gDtj#V$m)R(MfIlbRUw1DEPt@H$RByPCP1@JSs2ghc z#||j}YpIK^yL97_NRua(Tx7oae{pkH71v6)q)ztJefuAWtcjlXnlSEwKK^qhx3WqHyo*%0&H zAz{nU6l8Yz(1*nEM!RTw%D#57A*aNCjc(FB{Y_I#Q`mw8;>4)Pj@-!O5NbTOjd;!D z$z886*Ou~(aVFFBPk2U3Qo3lgmv{Y*BP**;k5Vf9!$3+#iU%^;*d23JR>J?*You@T zin`;#V#(2*b~Iz%?2mH*+rfEnm(~GWyvy$Dg~2kWLcDjjOO`)My}q@frQ@(Y^U%8| zLpEO~bs{Essqdg|H?^S=6j^{7S@mE1?If`q{N#@3V>`H`rar{M@AiLyFE3-%8R#e| zq*SY@=En;QNNf678f;8dIAY)Kvjg1^PrY~NSK62?4j-p4F=Xl-%2woAY(3lzl0JNR zq4{>g<^Xwaz@hqwKfqwgOl@za+t{}5$c*rUB)A;~zwB1NqQLR*fm@@U*UvaFNTpv} zdoF8OEv`<;N00tSCQNvZBw`?u>M?~0{S?+ttpXwz6h}r2a@Qbm%2|)q#%Q4?s;o-? zC{@#%+TK{Z&QAKZI%Yss&CSy{tF2TF{q3KaP%O7j;oFRlwA$xZxuxRcdzH=4QhpvgkBLWpjGw;4fC)!#v8PnigrFawP; zo}=RKYW901s#0MG6tr+` zf`(({m#8mKD1#7>ft)|Fqjs1O6QFvwlRdmHNTg(}d<+#WqT_aFYm2e}h-#@g@rJK& zjBOtE;=t*cL0f0tan$u~;s2{Ev(GmdXBZLfs# z2j4?fFTL-nPE9fPD!&PsepiQlXpW>$(b1n7tnpWEkDh;w@!X$0+K_z_w)ASn-g*Fu zPsVk2c7npgu?)QmU-9>M{0L4{RcYWPfO2&`G^Yg`e%;cCf6CLg~r|7iM z-GL4cl`~~a%|>mCa+qb>Sk7|H@%~-k-@mYH*Y$qCUa!aN@wAW5O>Lih(PWWcdfwxt z-Eeh(`Qm2Lz_jca-_0}&K<5_d;Q1uypGRm3lN_1W#iW=~DGARVb`6PF90iFpOwf6P zP!>{tfNm&q_D;m3_{gBp^@8J2uK2`iN#I7QBP7K2^%1TMo<;Mtri? z#pD14We%joBRVyk2SpcjD`xrbifKB{<--BDFnKB`Cx(4{IF(&z^4(G6qxB#KZer^e z5yJvOJV|FkchRnfru_RLO48J}cUuT=RE)!$+QtChnJ(7bs~C9O)7SM zb^%QtmzA{L5i|zOx0Jx~`U~uU3j74Yh)ZyM)sO(=sKgv_^>!6fH57>AVwf?)K5mho z@ac$lZvHGBht6{ICdguczAyZCJMTDpUSzE#V zxDxz24ofKkVvVdJ0>P+?EXP`nZk3(N0i%htxxtA*3}YX;Xhq^|3FrE{Yl zOCdd%JeJz48%Pk*7>i+(70tHl#{*3JkRf3)G14#FrxtqI*_zCS#7BCy6lwRPxI+&z z;b&kWAejuoX2tLv=%fU`nfSOGCP+nRD`g#|OF}@w(C3E_+{|6xbHB7>O=o5O-kd$P z3R&E&N!DWKsWeW9{4_4D=5H+0NDTmm^Vyw2bTz~}8?}kzB?}^! z8nWH61hG>VFadW6+HtnZ@9l8DevTvwQO89gCBv)*MRbAsq_rGg-inv7`ykV-@B*5p zeeAYp&~7>@~$Z`Jn^vj zNhsdC)pp?0)o8Zm5q8q0O~Gnox@T<1G2`M^YjpxHzAaXkD?lQ-=u^I~8?uFPTw3S$ zmZ`K(faIc(<*07@T0Xp_+Ltru|9W_FbVd*^6p4zMro|MfI~|fh*-62Vw_C3Z zDV~zaR>yKV6X4@(DOIf;H0YmMoSksX&?rc4SWu33ablQ=m|EqnP%VX?E7KXz*8tgb zw)z0YvEpw{&%Fs)lz^|!4Q?Tlk#Jx^jNYkAw_&IH!vO=KC=s?GMj0_6f7=9<-HZAU zfD33&mQJ>G0-s_#jt>sjLnC#nH3)>Yi;M$)GJqeq^;a6{Zih2( z!Bao8RZ@jZ=xk3s6gq^ZNf`+e0SaT$?o4nLFZ&pzyuC2~v8+09wqcw3{XUK*kGJ^t zKs@|m2w`nreVNaBKt@OM(25(+$Ppp1i}F0~aaQ{1hroMManq+!!NnZ#sdUr24D+@6C z2hCndOLrh&fwF=acNBM^&*=VGQ|$%{qYV+IUH<=ei4?+oZxiFeBWWxMi!*Th-@41PK8wXPSmRpM*0IMu@;kyVRDi0#LQTwxRrZ&gEuI(~E<);7*p~x{i3n=OW zGYCRO5k~i=t5chfw;L{0->T}0>iV_qq&Zc);m)QQmG?I>T6qXtgFe}LT+ZVR{lmAe z1lyrsrAuqAj$iBxWm@|?pwka`20t)9J(gqL1JK+7TbddfiL)bUi&gI8x)Tp=QNwH( z?3%VK$Ivtp)_6z64#&9R8H&`Y)IRcQ_=RKh=fvSND;H7cwqR??hs^_MfR;t#DZX=9 zb4XkVbANVgo#8!VnqvD{Kuk1vl53Gqb?PByq2{X9xs@jM4=5U~6Nj^Y;}j51PNFXs zsuGkEhCN4Okv>{!K8`bbAO75mz{*q2uq5l7c6m(3Us$@-Jhq#7?n(cb?j-v>;o?!- z#e`nnFh1s7)T;&?`LZ)52BFM^8^^Ous+ta$d^U|EqknIVz1b zI=v!;@J{n7UkCSB(4y0EQ?zbcSsHa{F$>cR0r0*AB=te9kq;x_wSV-Pb7gNDhA$9@ zgQ-;`H7NlBo}=FH6V*e)v>FRc&X^(9aC*@>yjm}xa+I+5A5-z*M~J3oOS}3tlvbkB zWTyox=EnQTh{_A`7BGhFRJP9!)Tv4;_HxjXbfI`RC)#_`++DrMmee=MtRXB4Op&I< z%murgVgoSkm40@m*WyIKN9}r3Em>LHcaB;*+wrCMPv^H77ivgdlxP$)&js;R^T(q?nrez^si6UO*VW`|w zI}5k(tF-9fbxl>Vb-}`?_B0Y7gEHI8vCh*5`z zrXM-bP(87|Z3r`>MrpUypE&;X0IgWlHuZ$H-jeE3LLR2ct1-% zbs5&s=xUn(0f-BWg_Z=AFzhF>VZR?0Waph45B7}46%M>Qxy9(^_%wfNF*hPHsEgd_*Z4n#t(VIUh>6;y(LhD7xX7E z^638K>#IK++PrN@J`ZhJ7=Q}f0Z_djFmUWNt%S|hZIxbi_w%G>bBpnd8Xg{J{+(@# z1a%V3>K#w`PCF4A+68LP{f)c-QkG!kC=!wTtY+i4n*G>@eR+w1B@QA`)vQ&bdZ89$ z>Oy2+4bmXn5`bqjU8%`hgDD}cDt&5xxL=;?J_-iHL(gZ=F*ij}N$;j;EGN5yvjgZj zH2V3ZTgTwEeqyEcTp@-h^f^M+P`OBw++M-f^~m^ zOBYgBslnIAY$w2O<#k8{R8Ms~#citEc`QNv`c+=g$8}jg8IpzgP^ z(%pa7ELJC6%2AI!@2$RkgKb@0j&-2x2%LH1k1?(1!0^;RFGtxLT&;h_+K#;d77Mb_ zP#g9$x@C*;U`fK+Z_1dSwt4@E98O|rPPZyTGqNnZaN!-}8HQ`M!>}i@k5x0{*wdWx4TNt&Qbn-z369{e+qM zn2JX0|E&HN9S`n!c#Is&z40(Mw5;Rxw{QE$odTC6Cz}45mbk;- z9;j$rw?oK2a@!KmPXr1QaN#v4oUe_Im&rrxYMAG<9Co3f<&Z{rzIn}4t<5Go0rfHZ zzLZ-DO)}eC&-a;U1^nN@;qsx)W~4-5J?G^ZR~EGXq#2kf6ZiU|yTjcihnHc_*S%aM zZPD9wKB|3zGRQERMhK_tk1!PP&)5Ha+jS;xrEoDxTlmNKm$QqJkr4%%pJ(@M2DRGPy{thT+_>z_kaOh+o;!$dD3WpHU6r@6Tt}&|L{~*x!YX%Ap z_uG?7#$=@gN3)>6zZ+V9v>x7zM~4n~9A>SRAH5i&v11?q5H+3DiF<6Yy_NG+q`mLy zw(P->Y0jQK4jnh1l~ieV_V4l_9-BEPJhntEZ}NP1bY^k(Ns(YyyGOZ0r#ba`!q@s9tA3I~=A&wYIO$1j%(bC!yr zJs@p90rje=(yAQxi_C+4~r|Y3x7F_I)hg)-lN1Oxc)x%_sTG&>317%G|o9aAiJ2z9C%!aP>i z9AYEb=o66GR5cz4!KJ9tZ)e64B8FoK}W_Pu}wH^{<;*02rhs zV`;Hz>N|5e1NXAKh_4A-X#r2HGLS(|SLvMd{K2Jyn7@2GD}UbaKbYHfviTsdx-R+q zo2Z($ut9~5c~LcV0A}IFgaCB#a zmxc%d;p3$_t}1=U0(5yvu9&v}nt%+(^rPuy{nXixrISiYSJ68+ zEVwxNeYsW)XN8xbe(JpWi#+JkXOg`cGn2-*nF&GSVVMVlA16;pR{PTOya_E}Rc-{x zu@64^gQb!~kgm@6K5$tW$-}-B`zlrE)|y&-&s1#fSXv?XFbv5&?JQeX2oR22aBLwQ zR~lh3RxLp>B18gG0HSCyGYFdkjpA1LvYSIBx*)oSnK;~u4yWqiI`uXJ@~k~x#c<;7 za9Aip!yyy_@HGHOht)rKVrlyo2xLw%n-St*EQ@YP^BYJ`ZYCxOvD&o-I!_!g#EI2j zH^*V_zio`+tY=&G?S67`#_wOEt|C?Rm4M>GGVh`IaxT~wF|I6lCiZNp`82<(Ev>nP zbvdGf80a#*Qhvbb5z|G0Leog@Ly-@u5aP9Ub*TbT^n$0e`#{45#aGyJtpi7C=!}9D zdOnbaBSnM{k3)D^M-qTx#z@-r$YP=!HAX{P8u4$9q&jn{^JAIUI1+h7*^Mtv@B-+2v9_mWy?~Qw)rc5hl9WH5B zfG5DnHtmXdQ)bGPLO&1-RV#wj@rBr|D!+EM2vdGv3@Sy#4( zX&rv#0^s};4~?_7CWw#5r+6InTQ2J-Hq6hgtBLv`ajWj{dJt+|=oKT1ZkJ3 zYHsKCtPnskUB{h+W8uFu-$u6>zP!sY24K3Dw2KLFqf3`ptz#rZxlB4)?QADmL~CHQwePDXG&JqF*iO9EUwKV}AVD zb9$Fspx@nC>FiozR{i7iw|vT@D5BB$OO4f5sl!}F7Jzlgcg(CsVGH(c4~`3x!(qya zR3W_QH6uYdhBtuPj;UyZLTe~$qE9|Ti5AEpS#vmsnkQ}+o61ufCMe>eQOL3Jl=LT) zk^fdM&i5}#zHmjPq3;c~@~#JR)^h57u1vXe|1zp}4$6w=D$p;HXuwhD?Pd@xg#Zv9 zXq8|;Ld%~9tC3NEZmECTa`2%^0%scNv!qiXN+g#b<6Yi0xO%DJ5%JAzd{yc2%*y*r z;%!}9nJN#H%M7?tG$&yq6|bYYADc0(+*C%&Fv=7NK?(P8(-?0){Z-tqm1P+N@~U7o zWyi=R(`a^aow5iI#cJ8J5YgR?<7mH8FF#5Ag|hp3Rn<##mmL2wWUI>o`A;iW8kalV zS4RAG&88iJhZ(&IP@>Mk00(#o|??C%S zFy%xqvd7W3sqDsT*Yrw8=){P{$sJ~$|3miZ*E?pCr97v32>g>%0a;qj z8S&MD=zPkeEsQ1j3!?t&VrpAbhZp{(r^gUW19Z7OQ=nX=|+_XvjIhxpQDO$+97a$pVN|Bv$cBsrw+yzF?{H@ zwg3qS%_{3FTzGJ5oWcMK{#<7r1tFmXU+ly6HJLXp4|ko-7&wxEsGs7JdTiVWD;?>YUCM55mKXg#WMOP}@P;j%O z4KoczZDGfWaIbjTEMFP;IL*#5UN-*X-xxg;pk@*Cj%eXsLpCRV?zFz zJsrGNT7xUcOLLhc5yxXZ94=tjV>JuRq+H8Pm$V5 zhKWW7`WdGk0T|~Q`!7Z=-;h*vj551Z`qK4CT z<|1Kip!t7$3qmprQDGu?Ay?XB<{Ln)zzU_Q3uk2GTaQo=ck0nU-l&1xD&G5^3AIog z;F_&QRQb(T-}jf6mn;=m*MLvcp!&I%u5Hncbt%&n+J~F@y-f*W`{xCiU{~WGFHdED zTruN}^*&-0O~0SXu84#}{+TwI#DZ50kfOJGh3VCQDkty}boVVTjhsncD2jK9=aLgoR6b};Ky()`lX_b?a}G#iiA#rtTV)jl-y? zH7Vd<`UbBxYdyt{ut=I-hN7vM^e{#G;n~ny+xPNS}T&68T#+j1kJ<)9JC6- z^H#v0QTHzXF}sp74jY`WuPpR%v_0D!IXVLvs)izbs1ZQG)8jevpNT!n1ri_~!p$Wu#-95forki)O5$FLPNWJT&;j9MTjtQNB zM-y*R)gV|*xp@Lr@g?cemt$wbpHzQN>RsK3%afL#&R=rsn)nZ}hBi11K|;@?5@h^HppR&U)b(?t67lK;UHc-NipUir#d^ zM@D=(wixiFCfx2~(Qp?RulC(r-T$h}y;LkdR6UVLJQAeqZi-h-HacEBQ~U3|5^~?G zze<}X2N$+|!@{9wYX~R@PEvsCz`}ZrAk-U`mPH!pUC*JdGj>4UphM%82RAG7}|cPTA%0E z8kM5m(%1;C)GP!YZwf8FaNo9d)uG|``r5^Ss86g}g$m_ji&szI!KAPAcTSb$=L96b z?XmeI=>4y1gk6vk@0!xViWt8gK=@tKIf&|~YQ4-*b-lqN!2w<0hCFBA*V(DHsn+$! zCce~vlNuLh_Mi8@TmMb`WX+>m+z~mqCk1S_tZq6+vXZ26;y!{S@t!zW)Q(^C}n zK3a4O9;PT!uHT=VE}eWkUe)n@ba7IVd*a*G z27r#5u?vZX_U60w}n zzl7pn+Ye=F8b3aC^Xc&&qR&ELs@V~c+K$aG9CMGCG^{$wT)!;%Q+mrSGQDjDr$Abs zhFN5i2*!}pxty+CFFCN~i-Kgo+piX^?1 z`S1Jw>I=n2x9rMyQ0z9kp4ttLn$*nSn-+T{PfC{7UflItxD{~pQUQ2&u7C;Dj5>G) zJbJXBVMyT0%JfusE0Bd5iVOE@z-6Pd?O~{=rr;YYw*ZCEKA#!*Q)aS-BdG8A=6S0DdsR7 z8Gu*aa9$D+@J(vF41Pgv%_R0r>x=4&NF0<;_jGh?+MlBZorwpSNz+HNyENTJ?u%@< z@5l{uj?&4-!l^-wY@L_Xz}ID9><9*r2~Z4R=^A#$7qcXnXlKvF@&|2`hI<13?`~Ce zOcMXLDRZvx8B1qsLJZetnUu&)jp$Y#rjL)fwx&ZJkJjW6SH8c2A4+8@^v;&->W7v6PaE;;-iNI^IRdIkau%3Ba)a2+-Fz047aT*!5WxpilsHg zF(VNc?lAO%dU*QREH*cH(fB%;{q6Yc=9d%G-{#!|Kp?Q}epfW^N2BD}`IBAVTpYs{ zjSkW~B5$I!uyiSLvZ=(|8ssXU;DvHqrqXLOT-z)s#G zji7W`zxutFZ^q3nhH}!_adOU_FMp} zLTu<6u3A}XI?){MS08sUYVb)uxXq~`L*(Un$K_?k98Z?kf%mG~qU#(S)5>_CS;AMz zZ9gwh;|WTxc)2*lh@%=^9Oem*G2I(HVN5Hbq~QLHBul3Zj$`O}oxL8ot31Bn1H^7( zCb-yjU}FH7<0rrr3N#zO?-RN1U@ZnwCm4Aj(u9)9jOjERW>ptz!ZL|Lx%f7Sq%PpX zYiggmiwL|vGD4?3xQl*Y^}thhyVLyKkd27Cp;Rt+JWl;ROY6Qj0CxlLlXbrbH+n69U^Hl$S$a zUgm_uaamx==b-CJ*Ez*&anQ_8k@4VDpueE1WgnQbL?tNl_uKY>MiuL^Z@0cktKRnC zy4aATOA91BC}Q{?AgtG(o6Gb(PG8r#1H1FjX#VtMmrCKN?LnSNlP7 zbU#5)il1>6^qMkx(+4cYbK_;|mRV<(kew6nyfT_?uRlorY#x1{Bn ztE4eBs7+R;%xI>LQFN}r!RNBVLf!;t>a>Bm;=vHi3NJ}94j^D>ZF&OG45_;zq|ds^ za&FNb_lxzzMG{9K1gVkmNU@{mt_D1c3s=jycc$##(wVirXFMVo-qf7@nvU|i?M&xt z=@Br{0=hGbaN-ek^x9i$9iT$_K^UWfmseKd55A>yiTh|}XgG&iY*;Hs@gdDIEeDuZ zTNFEZfYt=Ij(1vteKb3HF2z3XQmUnyrG|+GxXU&%LIj*~ zoLCv;lhY~hqqIcBS8xJGX=bk_pT#1#U@ReAp}Y$_l4yLz6f_Ic9%c~h_-ZbSS)>Th zlQX66D7gL{;^3b%@vl1~9o@h+1l2n6DMl^2WEKTQn8Og;*@z<*>ZevrA1T zgMed$kS3ZXU88k%OcC#>)UKpAT9DLq_HHtBhL18S?L|3f(W;|7F~C|K=-}keSb<_X zPZIYI3WbX`N)5|77uO{M<?*JBDenMYD1Tj8zo7Klw+Hq%p$S{pd2?TU1&S(x{OMC~>r zZGRd|$*|#yd}M=Pc z?X8C_$#Ft;ys0L9XGcCXZ^Xk&c|AQZX#$0@Y8|*;5huQMn~LP?ps0jL&YNO(Xj%iN zR6t}ST(eBdW|KvU=Kt$DcsTB4S9xH)UWv@4{>VVmOj<#q6!)B#GVF-3lqHCKU$e^8 zaVswZig>s&X>A314pl;zsi=*e%5Zkr;k)Q!dM>D9k~1!2oDJflwe;{Upeo{JG!wx21D6g1k>3b54|pR*kOxb^E(N&U)oa8r5^0BO&pp$+UUiYx!JEux zrX9hI9Cb?z<#PDO``pa>Vveq*`aMuMG9&S98d|v?=kFgMkT|}YsD~@WX#Pe?GY)?S z?NYc{s%ANSh=-n_;lg;h>Px+S>(&=6LITN90-#6}Qah(R>4Vj&JRY%vL|$fWl=e8E zsN1#QM5{IBQ0?YJ{Fv$ISoC-|Q3WCeV^Pkud@>y^J~>Kx8@jsi<=dR`t5+ctIW$WD zP0L7$3oJX8(PaDmKOiyVv&CVvO_)e{svx8`bi+a&u%RvNs_ILx9J*S9?Be82!212T zy!;M#?e}pG`k5{Ka4jCS*N$0~<1>!%VJ1YJM>cQBd;X?sF(r-KcG2kVTK}cRe68yq z_8ICBZ4ntBPY{1!$71#$2>D~eb-n(De?kb{&161hENy`-IK)YAR{7T#_Ew%1Vh+|p zi>~XtqLH9ZlkRhae=o;|VUvzS+bcrLKc*C&M_2Hp?^-lYMzuUC2uNYx=qFXpbu^3} zpV8f{dNn&B!mP@3K`P3>Z@W`h8|3bqc{>Y17HMD@ba$@l6K9!^dF!ET zzI}khIF5PQs7DObbG$x*g=TC7wu_R&_Y|e2y)O9aYE%~t>3ah!yVv`@zCSFg@qZ_p zlr#IjNcPTVg`2MxL;S5bF==eumx~=9;G}SL!n9Za`D-;|s+ltYiu4!{!S|P$;*Fj< zt7EyH-ui;Ey>Al=9TN53>px%{q|Ya{qtxPCI4TSZWGr4gKCn0E4ZJmO3DPn(eliQ4 zLm`~Ep!3{evaqX)hZgG8eml(Zr^}zDNwZZ2cgI)blimgp8-Cs|U-J))4LJYme<>l; z3Pztz$i#*>6bEtC*Wek8z*a@!2E(p z$&t|}k0q<3oRnX5uEAbNA|6y0mLa@WUihX3WzS^ZH79d9qz@-!6uPcN$bI28HQ6&w zpakFd#PPky^mbv(j_EwV!z?`>f0fI0`?PQktF?FK<$?GHU2s6hBP=&myr;$FNpdWY zdg5eX-rPGExHA4kI{S5HcGH`w`RR^_YvuhX6j}&Fs>7=f)e8I7p`Y(3y&f^u5i_j`i|MP7j64j zx~8inRlUPC@(a{p^w&LWwT22kox6~@02WCijJAPxsHXJZRg+DE6jY;fcG?rU@^f#K^?8NRr`iE zu+F)D@Vj_|(p5jZJZDsH`uIiF*`?>tlTNOwEnRCMa1D)8BDAIIu=5|!eHO*#&`H1# zl^zqj6SQV%i8;y9^?u*PR!A@1h7uxFSm$OL9lf7&@=koHY8wk8af;{M76!WjKo2O! z^-txmqXxMngZ<@Eve(qBe<#?6t0jo{f#p~2{Dk&TU)P0e{vmS zkPMP0LVHnkw=kaIRMql^8I^!PY$s!j!!9<-E*&^C8veG>>CgWFAY_Nbb~H;%9*yK8 z2kFr)RslS@GyI0sm$A8Fso-`C%=pHL)dw=o4T*1y#2LHyK9c7TGrGl*4^=P2*`U{T zb?wLuYo#$H9TNrUk}*b4o2J3Ldy;{E^|w#`lpm4r<^?ikK~fC`4zSn{*$rndb5yJZ zU?AfPmnARuq%^9~hk{*{=I{eSC3rj%sZjo=xWm6a>{GKgjH6H{Qcla*;Au7|18GrV zq~ZAL-zrCfH76bf;5rZ}y5%uD<`j`D$kuc7$!_KseXnu~cioS?A8gg=3p z@0qt@oj#z`xQd!%QvJw_4R?O|y`BhCidkPaeDC5Lq z(#eav*Fq1(19q{ym{!d(tTNe0oBQ3~>ik5}**^-7_U#E$a~5*nWw(5!OdiU9Hz!H; zu7L1>>>5o^?M`T(B16j>kmY7Zud5I)7i+f&67hI!b;^~fL!D_JVSPrD{;rQN#+uFV z@Z<%WFUM@}*GicF@#yILRe`td78tk*1$B`u9P1&HG{Ir0#xSu+>?#mx@W)oVF{?jf s`0A54TD5%%JfOhMFqJD97ej0ND2W1DN0LO?KeY4B`HteknE!hIACV)^>i_@% diff --git a/examples/platform/nrf528xx/pw_sys_io/BUILD.gn b/examples/platform/nrf528xx/pw_sys_io/BUILD.gn deleted file mode 100644 index 2be63d39f0e519..00000000000000 --- a/examples/platform/nrf528xx/pw_sys_io/BUILD.gn +++ /dev/null @@ -1,44 +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. - -# gn-format disable -import("//build_overrides/pigweed.gni") - -import("$dir_pw_build/target_types.gni") - -import("//build_overrides/nrf5_sdk.gni") - -import("${nrf5_sdk_build_root}/nrf5_executable.gni") -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") -assert(current_os == "freertos") - -nrf5_platform_dir = "${chip_root}/examples/platform/nrf528xx" - -config("default_config") { - include_dirs = [ "include" ] -} - -pw_source_set("pw_sys_io_baremetal_nrf528xx") { - public_configs = [ ":default_config" ] - include_dirs = [ - "${nrf5_sdk_root}/components/boards/", - "${nrf5_sdk_root}/components/libraries/", - ] - deps = [ - "$dir_pw_sys_io:default_putget_bytes", - "$dir_pw_sys_io:facade", - "${nrf5_platform_dir}/sdk:sdk", - ] - sources = [ "sys_io_baremetal_nrf528xx.cc" ] -} diff --git a/examples/platform/nrf528xx/pw_sys_io/include/pw_sys_io_baremetal_nrf528xx/init.h b/examples/platform/nrf528xx/pw_sys_io/include/pw_sys_io_baremetal_nrf528xx/init.h deleted file mode 100644 index 9f375ed5fc2312..00000000000000 --- a/examples/platform/nrf528xx/pw_sys_io/include/pw_sys_io_baremetal_nrf528xx/init.h +++ /dev/null @@ -1,27 +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. - */ - -#pragma once - -#include "pw_preprocessor/util.h" - -PW_EXTERN_C_START - -// The actual implement of PreMainInit() in sys_io_BACKEND. -void pw_sys_io_Init(); - -PW_EXTERN_C_END diff --git a/examples/platform/nrf528xx/pw_sys_io/sys_io_baremetal_nrf528xx.cc b/examples/platform/nrf528xx/pw_sys_io/sys_io_baremetal_nrf528xx.cc deleted file mode 100644 index 3d58872d6c96b9..00000000000000 --- a/examples/platform/nrf528xx/pw_sys_io/sys_io_baremetal_nrf528xx.cc +++ /dev/null @@ -1,104 +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. - */ - -#include - -#include "pw_sys_io/sys_io.h" - -#include "boards.h" -#include "nrf_uarte.h" -#include "uart/app_uart.h" - -namespace { - -void uart_error_handle(app_uart_evt_t * p_event) -{ - if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR) - { - APP_ERROR_HANDLER(p_event->data.error_communication); - } - else if (p_event->evt_type == APP_UART_FIFO_ERROR) - { - APP_ERROR_HANDLER(p_event->data.error_code); - } -} - -} // namespace - -#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */ -#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */ - -extern "C" void pw_sys_io_Init() -{ - const app_uart_comm_params_t comm_params = { RX_PIN_NUMBER, - TX_PIN_NUMBER, - RTS_PIN_NUMBER, - CTS_PIN_NUMBER, - APP_UART_FLOW_CONTROL_DISABLED, - false, - NRF_UARTE_BAUDRATE_115200 }; - uint32_t err_code; - APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_error_handle, APP_IRQ_PRIORITY_LOWEST, err_code); - APP_ERROR_CHECK(err_code); -} - -namespace pw::sys_io { - -// Wait for a byte to read on UARTE. This blocks until a byte is read. This is -// extremely inefficient as it requires the target to burn CPU cycles polling to -// see if a byte is ready yet. -Status ReadByte(std::byte * dest) -{ - while (app_uart_get(reinterpret_cast(dest)) != NRF_SUCCESS) - { - } - return Status::OK; -} - -// Send a byte over UARTE. Since this blocks on every byte, it's rather -// inefficient. At the default baud rate of 115200, one byte blocks the CPU for -// ~87 micro seconds. This means it takes only 10 bytes to block the CPU for -// 1ms! -Status WriteByte(std::byte b) -{ - // Wait for TX buffer to be empty. When the buffer is empty, we can write - // a value to be dumped out of UART. - while (app_uart_put(*reinterpret_cast(&b)) != NRF_SUCCESS) - { - } - return Status::OK; -} - -// Writes a string using pw::sys_io, and add newline characters at the end. -StatusWithSize WriteLine(const std::string_view & s) -{ - size_t chars_written = 0; - StatusWithSize result = WriteBytes(std::as_bytes(std::span(s))); - if (!result.ok()) - { - return result; - } - chars_written += result.size(); - - // Write trailing newline. - result = WriteBytes(std::as_bytes(std::span("\r\n", 2))); - chars_written += result.size(); - - return StatusWithSize(result.status(), chars_written); -} - -} // namespace pw::sys_io diff --git a/examples/platform/nrf528xx/sdk/BUILD.gn b/examples/platform/nrf528xx/sdk/BUILD.gn deleted file mode 100644 index 159b7224d440f6..00000000000000 --- a/examples/platform/nrf528xx/sdk/BUILD.gn +++ /dev/null @@ -1,54 +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. - -# gn-format disable -import("//build_overrides/nrf5_sdk.gni") - -import("${nrf5_sdk_build_root}/nrf5_executable.gni") -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") -assert(current_os == "freertos") - -nrf5_platform_dir = "${chip_root}/examples/platform/nrf528xx" - -declare_args() { - nrf5_app_config_dir = "//" -} - -nrf5_sdk("sdk") { - include_dirs = [ - nrf5_app_config_dir, - "${nrf5_platform_dir}/app/project_include", - "${nrf5_platform_dir}/util/include", - "${nrf5_platform_dir}/app/include", - "${chip_root}/src/app/util", - ] - - sources = [ - "$nrf5_app_config_dir/app_config.h", - "${nrf5_platform_dir}/app/project_include/CHIPProjectConfig.h", - "${nrf5_platform_dir}/app/project_include/FreeRTOSConfig.h", - "${nrf5_platform_dir}/app/project_include/OpenThreadConfig.h", - "${nrf5_platform_dir}/app/project_include/freertos_tasks_c_additions.h", - "${nrf5_platform_dir}/app/project_include/nrf_log_ctrl_internal.h", - ] - - defines = [] - if (is_debug) { - defines += [ "BUILD_RELEASE=0" ] - } else { - defines += [ "BUILD_RELEASE=1" ] - } - - defines += [ "USE_APP_CONFIG" ] -} diff --git a/examples/platform/nrf528xx/util/LEDWidget.cpp b/examples/platform/nrf528xx/util/LEDWidget.cpp deleted file mode 100644 index 1254105378bc60..00000000000000 --- a/examples/platform/nrf528xx/util/LEDWidget.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "boards.h" - -#include "LEDWidget.h" - -#include - -void LEDWidget::Init(uint32_t gpioNum) -{ - mLastChangeTimeUS = 0; - mBlinkOnTimeMS = 0; - mBlinkOffTimeMS = 0; - mGPIONum = gpioNum; - mState = false; - - nrf_gpio_cfg_output(gpioNum); - Set(false); -} - -void LEDWidget::Invert(void) -{ - Set(!mState); -} - -void LEDWidget::Set(bool state) -{ - mBlinkOnTimeMS = mBlinkOffTimeMS = 0; - DoSet(state); -} - -void LEDWidget::Blink(uint32_t changeRateMS) -{ - Blink(changeRateMS, changeRateMS); -} - -void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) -{ - mBlinkOnTimeMS = onTimeMS; - mBlinkOffTimeMS = offTimeMS; - Animate(); -} - -void LEDWidget::Animate() -{ - if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) - { - int64_t nowUS = chip::System::Platform::Layer::GetClock_Monotonic(); - int64_t stateDurUS = ((mState) ? mBlinkOnTimeMS : mBlinkOffTimeMS) * 1000LL; - int64_t nextChangeTimeUS = mLastChangeTimeUS + stateDurUS; - - if (nowUS > nextChangeTimeUS) - { - DoSet(!mState); - mLastChangeTimeUS = nowUS; - } - } -} - -void LEDWidget::DoSet(bool state) -{ - mState = state; - - if (state) - { - nrf_gpio_pin_write(mGPIONum, LEDS_ACTIVE_STATE ? 1 : 0); - } - else - { - nrf_gpio_pin_write(mGPIONum, LEDS_ACTIVE_STATE ? 0 : 1); - } -} diff --git a/examples/platform/nrf528xx/util/include/LEDWidget.h b/examples/platform/nrf528xx/util/include/LEDWidget.h deleted file mode 100644 index a719a127ae1d18..00000000000000 --- a/examples/platform/nrf528xx/util/include/LEDWidget.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -class LEDWidget -{ -public: - void Init(uint32_t gpioNum); - void Set(bool state); - void Invert(void); - void Blink(uint32_t changeRateMS); - void Blink(uint32_t onTimeMS, uint32_t offTimeMS); - void Animate(); - -private: - int64_t mLastChangeTimeUS; - uint32_t mBlinkOnTimeMS; - uint32_t mBlinkOffTimeMS; - uint32_t mGPIONum; - bool mState; - - void DoSet(bool state); -}; diff --git a/examples/platform/nrf528xx/util/streamer/streamer_nrf5.cpp b/examples/platform/nrf528xx/util/streamer/streamer_nrf5.cpp deleted file mode 100644 index a5a02cf9cbb9d9..00000000000000 --- a/examples/platform/nrf528xx/util/streamer/streamer_nrf5.cpp +++ /dev/null @@ -1,107 +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. - */ - -/** - * @file - * Source implementation of an input / output stream for stdio targets. - */ - -#include - -#ifdef NRF_SHELL_STREAMER - -#include "app_uart.h" -#include "bsp.h" -#include "nrf_uarte.h" - -#ifdef FREERTOS -#include "FreeRTOS.h" -#include "task.h" -#endif - -namespace chip { -namespace Shell { - -const size_t c_rx_buffer_size = 256; /**< UART RX buffer size. */ -const size_t c_tx_buffer_size = 512; /**< UART TX buffer size. */ - -void uart_error_handle(app_uart_evt_t * p_event) {} - -void streamer_nrf5_init_internal() -{ - uint32_t err_code; - const app_uart_comm_params_t comm_params = { RX_PIN_NUMBER, - TX_PIN_NUMBER, - RTS_PIN_NUMBER, - CTS_PIN_NUMBER, - APP_UART_FLOW_CONTROL_DISABLED, - false, - NRF_UARTE_BAUDRATE_115200 }; - - APP_UART_FIFO_INIT(&comm_params, c_rx_buffer_size, c_tx_buffer_size, uart_error_handle, APP_IRQ_PRIORITY_LOWEST, err_code); - APP_ERROR_CHECK(err_code); -} - -int streamer_nrf5_init(streamer_t * streamer) -{ - return 0; -} - -int streamer_nrf5_read(streamer_t * streamer, char * buf, size_t len) -{ - size_t count = 0; - while (count < len && app_uart_get(reinterpret_cast(buf + count)) == NRF_SUCCESS) - { - count++; -#ifdef FREERTOS - taskYIELD(); -#endif // FREERTOS - } - - return count; -} - -int streamer_nrf5_write(streamer_t * streamer, const char * buf, size_t len) -{ - size_t count = 0; - while (count < len && app_uart_put(buf[count]) == NRF_SUCCESS) - count++; - - return count; -} - -static streamer_t streamer_nrf5 = { - .init_cb = streamer_nrf5_init, - .read_cb = streamer_nrf5_read, - .write_cb = streamer_nrf5_write, -}; - -streamer_t * streamer_get(void) -{ - static bool initialized = false; - if (!initialized) - { - streamer_nrf5_init_internal(); - initialized = true; - } - return &streamer_nrf5; -} - -} // namespace Shell -} // namespace chip - -#endif //#ifdef NRF_SHELL_STREAMER diff --git a/examples/platform/nrfconnect/pw_sys_io/sys_io_nrfconnect.cc b/examples/platform/nrfconnect/pw_sys_io/sys_io_nrfconnect.cc index d30bc2b919b436..b98bbe03128101 100644 --- a/examples/platform/nrfconnect/pw_sys_io/sys_io_nrfconnect.cc +++ b/examples/platform/nrfconnect/pw_sys_io/sys_io_nrfconnect.cc @@ -19,6 +19,7 @@ #include "console/console.h" #include "pw_sys_io/sys_io.h" +#include #include extern "C" void pw_sys_io_Init() diff --git a/examples/shell/nrf52/.gn b/examples/shell/nrf52/.gn deleted file mode 100644 index 89dc9a6fcb5f6c..00000000000000 --- a/examples/shell/nrf52/.gn +++ /dev/null @@ -1,26 +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. - -# The location of the build configuration file. -buildconfig = "//build/config/BUILDCONFIG.gn" - -# CHIP uses angle bracket includes. -check_system_includes = true - -default_args = { - target_cpu = "arm" - target_os = "freertos" - - import("//args.gni") -} diff --git a/examples/shell/nrf52/BUILD.gn b/examples/shell/nrf52/BUILD.gn deleted file mode 100644 index 5922c6b6a34897..00000000000000 --- a/examples/shell/nrf52/BUILD.gn +++ /dev/null @@ -1,122 +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. - -import("//build_overrides/chip.gni") -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -import("${nrf5_sdk_build_root}/nrf5_executable.gni") -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") - -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -assert(current_os == "freertos") - -nrf5_platform_dir = "${chip_root}/examples/platform/nrf528xx" -project_dir = "./.." - -nrf5_sdk("sdk") { - include_dirs = [ - "include", - "${nrf5_platform_dir}/app/project_include", - "${nrf5_platform_dir}/util/include", - "${nrf5_platform_dir}/app/include", - "${chip_root}/src/app/util", - ] - - sources = [ - "${nrf5_platform_dir}/app/project_include/CHIPProjectConfig.h", - "${nrf5_platform_dir}/app/project_include/FreeRTOSConfig.h", - "${nrf5_platform_dir}/app/project_include/OpenThreadConfig.h", - "${nrf5_platform_dir}/app/project_include/freertos_tasks_c_additions.h", - "${nrf5_platform_dir}/app/project_include/nrf_log_ctrl_internal.h", - "${project_dir}/nrf52/include/app_config.h", - ] - - defines = [] - if (is_debug) { - defines += [ "BUILD_RELEASE=0" ] - } else { - defines += [ "BUILD_RELEASE=1" ] - } - - defines += [ - "USE_APP_CONFIG", - "ENABLE_CHIP_SHELL", - "NRF_SHELL_STREAMER", - "MBEDTLS_PK_WRITE_C", - "MBEDTLS_X509_CREATE_C", - "MBEDTLS_X509_CSR_WRITE_C", - "OPENTHREAD_CONFIG_CLI_TRANSPORT=OT_CLI_TRANSPORT_CONSOLE", - "OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS_MANAGEMENT=1", - ] -} - -nrf5_executable("shell_nrf5") { - output_name = "shell-nrf52840" - - include_dirs = [ - "${chip_root}/src/lib/shell", - "${nrf5_sdk_root}/components/libraries/uart", - ] - - sources = [ - "${nrf5_platform_dir}/app/chipinit.cpp", - "${nrf5_platform_dir}/app/include/Service.h", - "${nrf5_platform_dir}/app/include/chipinit.h", - "${nrf5_platform_dir}/app/support/CXXExceptionStubs.cpp", - "${nrf5_platform_dir}/app/support/nRF5Sbrk.c", - "${nrf5_platform_dir}/util/LEDWidget.cpp", - "${nrf5_platform_dir}/util/include/LEDWidget.h", - "${nrf5_platform_dir}/util/streamer/streamer_nrf5.cpp", - "${project_dir}/nrf52/include/CHIPProjectConfig.h", - "${project_dir}/nrf52/main.cpp", - "${project_dir}/test_identity.cpp", - ] - - deps = [ - ":sdk", - "${chip_root}/src/lib", - "${chip_root}/src/lib/shell", - "${chip_root}/src/setup_payload", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libnordicsemi_nrf52840_radio_driver_softdevice", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libopenthread-nrf52840-softdevice-sdk", - "${nrf5_platform_dir}/app/support:freertos_debugging_hooks", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support", - "${nrf5_platform_dir}/app/support:freertos_newlib_lock_support_test", - "${openthread_root}:libopenthread-cli-ftd", - "${openthread_root}:libopenthread-ftd", - "${project_dir}/shell_common:shell_common", - ] - - output_dir = root_out_dir - - ldscript = "${nrf5_platform_dir}/app/ldscripts/chip-nrf52840-example.ld" - - ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] - - defines = [ - "NRF_SHELL_STREAMER", - "SHELL_STREAMER_APP_SPECIFIC", - ] -} - -group("nrf5") { - deps = [ ":shell_nrf5" ] -} - -group("default") { - deps = [ ":nrf5" ] -} diff --git a/examples/shell/nrf52/args.gni b/examples/shell/nrf52/args.gni deleted file mode 100644 index a76696893dd2b7..00000000000000 --- a/examples/shell/nrf52/args.gni +++ /dev/null @@ -1,20 +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. - -import("//build_overrides/chip.gni") - -import("${chip_root}/examples/platform/nrf528xx/args.gni") - -# SDK target. This is overriden to add our SDK app_config.h & defines. -nrf5_sdk_target = get_label_info(":sdk", "label_no_toolchain") diff --git a/examples/shell/nrf52/build b/examples/shell/nrf52/build deleted file mode 120000 index d56ed62ae4d1ff..00000000000000 --- a/examples/shell/nrf52/build +++ /dev/null @@ -1 +0,0 @@ -third_party/connectedhomeip/build \ No newline at end of file diff --git a/examples/shell/nrf52/build_overrides b/examples/shell/nrf52/build_overrides deleted file mode 120000 index e578e73312ebd1..00000000000000 --- a/examples/shell/nrf52/build_overrides +++ /dev/null @@ -1 +0,0 @@ -../../build_overrides \ No newline at end of file diff --git a/examples/shell/nrf52/include/CHIPProjectConfig.h b/examples/shell/nrf52/include/CHIPProjectConfig.h deleted file mode 100644 index c2acc9aaf0e5f6..00000000000000 --- a/examples/shell/nrf52/include/CHIPProjectConfig.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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 - -#if !BUILD_RELEASE // development build - -// For convenience, Chip Security Test Mode can be enabled and the -// requirement for authentication in various protocols can be disabled. -// -// WARNING: These options make it possible to circumvent basic Chip security functionality, -// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. -// -#define CHIP_CONFIG_SECURITY_TEST_MODE 0 -#define CHIP_CONFIG_REQUIRE_AUTH 1 - -/** - * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY - * - * Enables the use of a hard-coded default CHIP device id and credentials if no device id - * is found in CHIP NV storage. - * - * This option is for testing only and should be disabled in production releases. - */ -#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 34 - -// Use a default pairing code if one hasn't been provisioned in flash. -#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 12345678 -#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 - -/** - * CHIP_DEVICE_CONFIG_USE_TEST_SERIAL_NUMBER - * - * Enables the use of a hard-coded default serial number if none - * is found in CHIP NV storage. - */ -#define CHIP_DEVICE_CONFIG_USE_TEST_SERIAL_NUMBER "DUMMY_SN" - -#endif // BUILD_RELEASE - -/** - * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID - * - * 0x235A: Chip's Vendor Id. - */ -#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0x235A - -/** - * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID - * - * 0xFE00: SDK Sample Lock Resource - */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0xFE00 - -/** - * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_REVISION - * - * The product revision number assigned to device or product by the device vendor. This - * number is scoped to the device product id, and typically corresponds to a revision of the - * physical device, a change to its packaging, and/or a change to its marketing presentation. - * This value is generally *not* incremented for device software revisions. - */ -#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_REVISION 1 - -/** - * CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION - * - * A string identifying the firmware revision running on the device. - * CHIP currently expects the firmware version to be in the format - * {MAJOR_VERSION}.0d{MINOR_VERSION} - */ -#ifndef CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION -#define CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION "1.0d1" -#endif -/** - * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - * - * Enable support for CHIP-over-BLE (CHIPOBLE). - */ -#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 - -/** - * CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC - * - * Enables synchronizing the device's real time clock with a remote CHIP Time service - * using the CHIP Time Sync protocol. - */ -//#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 1 - -/** - * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS - * - * Enable recording UTC timestamps. - */ -#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 - -/** - * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE - * - * A size, in bytes, of the individual debug event logging buffer. - */ -#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) - -/** - * CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE - * - * For a development build, set the default importance of events to be logged as Debug. - * Since debug is the lowest importance level, this means all standard, critical, info and - * debug importance level vi events get logged. - */ -#if BUILD_RELEASE -#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Production -#else -#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Debug -#endif // BUILD_RELEASE - -// Enable support functions for parsing command-line arguments -#define CHIP_CONFIG_ENABLE_ARG_PARSER 1 diff --git a/examples/shell/nrf52/include/app_config.h b/examples/shell/nrf52/include/app_config.h deleted file mode 100644 index 872a97be115ae8..00000000000000 --- a/examples/shell/nrf52/include/app_config.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -// ----- Memory Config ----- - -#define MEM_MANAGER_ENABLED 1 -#define MEMORY_MANAGER_SMALL_BLOCK_COUNT 4 -#define MEMORY_MANAGER_SMALL_BLOCK_SIZE 32 -#define MEMORY_MANAGER_MEDIUM_BLOCK_COUNT 4 -#define MEMORY_MANAGER_MEDIUM_BLOCK_SIZE 256 -#define MEMORY_MANAGER_LARGE_BLOCK_COUNT 1 -#define MEMORY_MANAGER_LARGE_BLOCK_SIZE 1024 - -// ----- Crypto Config ----- - -#define NRF_CRYPTO_ENABLED 0 - -// ----- Soft Device Config ----- - -#define SOFTDEVICE_PRESENT 1 -#define NRF_SDH_ENABLED 1 -#define NRF_SDH_SOC_ENABLED 1 -#define NRF_SDH_BLE_ENABLED 1 -#define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1 -#define NRF_SDH_BLE_VS_UUID_COUNT 2 -#define NRF_BLE_GATT_ENABLED 1 -#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 251 -#define NRF_SDH_BLE_GAP_DATA_LENGTH 251 - -// ----- FDS / Flash Config ----- - -#define FDS_ENABLED 1 -#define FDS_BACKEND NRF_FSTORAGE_SD -#define NRF_FSTORAGE_ENABLED 1 -// Number of virtual flash pages used for FDS data storage. -// NOTE: This value must correspond to FDS_FLASH_PAGES specified in -// linker directives (.ld) file. -#define FDS_VIRTUAL_PAGES 2 - -// ----- Logging Config ----- - -#define NRF_LOG_ENABLED 1 -#define NRF_LOG_DEFAULT_LEVEL 4 -#define NRF_LOG_DEFERRED 0 -#define NRF_LOG_STR_PUSH_BUFFER_SIZE 16 -#define NRF_LOG_USES_TIMESTAMP 1 -#define NRF_LOG_STR_FORMATTER_TIMESTAMP_FORMAT_ENABLED 0 - -#define NRF_LOG_BACKEND_RTT_ENABLED 1 -#define NRF_LOG_BACKEND_UART_ENABLED 0 - -#if NRF_LOG_BACKEND_UART_ENABLED - -#define NRF_LOG_BACKEND_UART_TX_PIN 6 -#define NRF_LOG_BACKEND_UART_BAUDRATE 30801920 -#define NRF_LOG_BACKEND_UART_TEMP_BUFFER_SIZE 64 - -#endif // NRF_LOG_BACKEND_UART_ENABLED - -#if NRF_LOG_BACKEND_RTT_ENABLED - -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 4096 -#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 1 -#define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16 -#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 1 - -// <0=> SKIP -// <1=> TRIM -// <2=> BLOCK_IF_FIFO_FULL -#define SEGGER_RTT_CONFIG_DEFAULT_MODE 1 - -#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS 1 -#define NRF_LOG_BACKEND_RTT_TX_RETRY_CNT 3 - -#endif // NRF_LOG_BACKEND_RTT_ENABLED - -// ----- Misc Config ----- - -// Enable the Nordic ASSERT() macro. This also has the effect of enabling -// FreeRTOS configASSERT() due to logic in FreeRTOSConfig.h -#define DEBUG_NRF 1 - -#define NRF_CLOCK_ENABLED 1 -#define NRF_FPRINTF_ENABLED 1 -#define NRF_STRERROR_ENABLED 1 -#define NRF_QUEUE_ENABLED 1 -#define APP_TIMER_ENABLED 1 -#define APP_UART_ENABLED 1 -#define APP_FIFO_ENABLED 1 -#define BUTTON_ENABLED 1 - -#define UART_ENABLED 1 -#define UART1_ENABLED 1 -#define NRFX_UARTE_ENABLED 1 -#define NRFX_UARTE1_ENABLED 1 -#define APP_UART_DRIVER_INSTANCE 1 -#define NRFX_UART_ENABLED 0 -#define UART_LEGACY_SUPPORT 0 - -#define GPIOTE_ENABLED 1 -#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 2 - -#define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10 - -// ---- Lock Example App Config ---- - -#define LOCK_BUTTON BUTTON_2 -#define FUNCTION_BUTTON BUTTON_1 -#define FUNCTION_BUTTON_DEBOUNCE_PERIOD_MS 50 - -#define SYSTEM_STATE_LED BSP_LED_0 -#define LOCK_STATE_LED BSP_LED_1 - -// ---- Thread Polling Config ---- -#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 -#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 diff --git a/examples/shell/nrf52/main.cpp b/examples/shell/nrf52/main.cpp deleted file mode 100644 index e42a3c5b102d1e..00000000000000 --- a/examples/shell/nrf52/main.cpp +++ /dev/null @@ -1,107 +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. - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#ifdef SOFTDEVICE_PRESENT -#include "nrf_sdh.h" -#include "nrf_sdh_ble.h" -#include "nrf_sdh_soc.h" -#endif //#ifdef SOFTDEVICE_PRESENT - -#if CHIP_ENABLE_OPENTHREAD -extern "C" { -#include -} -#endif // CHIP_ENABLE_OPENTHREAD - -using namespace chip; -using namespace chip::Shell; - -// TODO: Move softdevice initialization behind platform interface. -static void OnSoCEvent(uint32_t sys_evt, void * p_context) -{ -#if CHIP_ENABLE_OPENTHREAD - otSysSoftdeviceSocEvtHandler(sys_evt); -#endif - UNUSED_PARAMETER(p_context); -} - -CHIP_ERROR soft_device_init() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - err = nrf_sdh_enable_request(); - SuccessOrExit(err); - - while (!nrf_sdh_is_enabled()) - { - } - - // Register a handler for SOC events. - NRF_SDH_SOC_OBSERVER(m_soc_observer, NRF_SDH_SOC_STACK_OBSERVER_PRIO, OnSoCEvent, NULL); - - { - uint32_t appRAMStart = 0; - - // Configure the BLE stack using the default settings. - // Fetch the start address of the application RAM. - err = nrf_sdh_ble_default_cfg_set(CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG, &appRAMStart); - SuccessOrExit(err); - - // Enable BLE stack. - err = nrf_sdh_ble_enable(&appRAMStart); - SuccessOrExit(err); - } - -exit: - return err; -} - -int main() -{ - soft_device_init(); - - // Initialize the default streamer that was linked. - const int rc = streamer_init(streamer_get()); - - if (rc != 0) - { - ChipLogError(Shell, "Streamer initialization failed: %d", rc); - return rc; - } - - cmd_misc_init(); - cmd_base64_init(); - cmd_device_init(); - cmd_btp_init(); - cmd_otcli_init(); - - shell_task(nullptr); - return 0; -} diff --git a/examples/shell/nrf52/third_party/connectedhomeip b/examples/shell/nrf52/third_party/connectedhomeip deleted file mode 120000 index c866b86874994d..00000000000000 --- a/examples/shell/nrf52/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../.. \ No newline at end of file diff --git a/gn_build.sh b/gn_build.sh index 6283a9d0f55f0a..addc6e211118ea 100755 --- a/gn_build.sh +++ b/gn_build.sh @@ -94,21 +94,6 @@ else echo "Hint: Set \$ANDROID_HOME and \$ANDROID_NDK_HOME to enable building for Android" fi -# nRF5 SDK setup -nrf5_sdk_args="" - -if [[ -d "$NRF5_SDK_ROOT/components/libraries" ]]; then - nrf5_sdk_args+="nrf5_sdk_root=\"$NRF5_SDK_ROOT\"" - extra_args+=" $nrf5_sdk_args enable_nrf5_builds=true" -fi - -echo -if [[ ! -d "$NRF5_SDK_ROOT/components/libraries" ]]; then - echo "Hint: Set \$NRF5_SDK_ROOT to enable building for nRF5" -else - echo 'To build the nRF5 lock sample as a standalone project': - echo "(cd $CHIP_ROOT/examples/lock-app/nrf5; gn gen out/debug --args='$nrf5_sdk_args'; ninja -C out/debug)" -fi echo # EFR32 SDK setup diff --git a/integrations/docker/images/chip-build-nrf-platform/Dockerfile b/integrations/docker/images/chip-build-nrf-platform/Dockerfile index a8291ad749c3c7..8bb17a3038201f 100644 --- a/integrations/docker/images/chip-build-nrf-platform/Dockerfile +++ b/integrations/docker/images/chip-build-nrf-platform/Dockerfile @@ -24,19 +24,6 @@ RUN set -x \ | tar jxvf -) \ && : # last line -# ================================================== -# nRF5 SDK -# ================================================== -RUN set -x \ - && curl -o /tmp/nRF5SDKforThreadandZigbee.zip \ - https://www.nordicsemi.com/-/media/Software-and-other-downloads/SDKs/nRF5-SDK-for-Thread/nRF5-SDK-for-Thread-and-Zigbee/nRF5SDKforThreadandZigbeev400dc7186b.zip \ - && (mkdir /opt/NordicSemiconductor/nRF5_SDK_for_Thread_and_Zigbee \ - && cd /opt/NordicSemiconductor/nRF5_SDK_for_Thread_and_Zigbee \ - && unzip /tmp/nRF5SDKforThreadandZigbee.zip) \ - && rm -rf /tmp/nRF5SDKforThreadandZigbee.zip \ - && : # last line - -ENV NRF5_SDK_ROOT=/opt/NordicSemiconductor/nRF5_SDK_for_Thread_and_Zigbee ENV NRF5_TOOLS_ROOT=/opt/NordicSemiconductor/nRF5_tools ENV ARM_GCC_INSTALL_ROOT=/opt/ARM-software/gcc-arm-none-eabi-9-2019-q4-major/bin/ diff --git a/integrations/docker/images/chip-build-vscode/Dockerfile b/integrations/docker/images/chip-build-vscode/Dockerfile index 09246fc9512a63..4abcdec2ec4354 100644 --- a/integrations/docker/images/chip-build-vscode/Dockerfile +++ b/integrations/docker/images/chip-build-vscode/Dockerfile @@ -8,7 +8,6 @@ COPY --from=esp32 /opt/espressif/esp-idf /opt/espressif/esp-idf COPY --from=esp32 /opt/espressif/tools /opt/espressif/tools COPY --from=esp32 /opt/espressif/qemu /opt/espressif/qemu COPY --from=nrf /opt/NordicSemiconductor/nRF5_tools /opt/NordicSemiconductor/nRF5_tools -COPY --from=nrf /opt/NordicSemiconductor/nRF5_SDK_for_Thread_and_Zigbee /opt/NordicSemiconductor/nRF5_SDK_for_Thread_and_Zigbee COPY --from=nrf /opt/ARM-software/gcc-arm-none-eabi-9-2019-q4-major /opt/ARM-software/gcc-arm-none-eabi-9-2019-q4-major COPY --from=efr32 /opt/SiliconLabs/sdk_support /opt/SiliconLabs/sdk_support COPY --from=android /opt/android/sdk /opt/android/sdk @@ -17,7 +16,6 @@ ENV IDF_PATH=/opt/espressif/esp-idf/ ENV IDF_TOOLS_PATH=/opt/espressif/tools ENV QEMU_ESP32_DIR=/opt/espressif/qemu ENV QEMU_ESP32=/opt/espressif/qemu/xtensa-softmmu/qemu-system-xtensa -ENV NRF5_SDK_ROOT=/opt/NordicSemiconductor/nRF5_SDK_for_Thread_and_Zigbee ENV NRF5_TOOLS_ROOT=/opt/NordicSemiconductor/nRF5_tools ENV ARM_GCC_INSTALL_ROOT=/opt/ARM-software/gcc-arm-none-eabi-9-2019-q4-major/bin ENV EFR32_SDK_ROOT=/opt/SiliconLabs/sdk_support diff --git a/scripts/examples/gn_nrf_example.sh b/scripts/examples/gn_nrf_example.sh deleted file mode 100755 index f0b6760d8416f3..00000000000000 --- a/scripts/examples/gn_nrf_example.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# -# 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. -# - -set -e - -# Build script for GN nRF5 examples GitHub workflow. - -CHIP_ROOT="$(dirname "$0")/../.." - -source "$CHIP_ROOT/scripts/activate.sh" - -set -x -env - -gn gen --check --root="$1" --args="nrf5_sdk_root=\"$NRF5_SDK_ROOT\"" "$2" - -ninja -v -C "$2" diff --git a/scripts/flashing/nrf5_firmware_utils.py b/scripts/flashing/nrf5_firmware_utils.py deleted file mode 100755 index 266f5cd7125c9b..00000000000000 --- a/scripts/flashing/nrf5_firmware_utils.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env python3 -# 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. -"""Flash an NRF5 device. - -This is layered so that a caller can perform individual operations -through an `Flasher` instance, or operations according to a command line. -For `Flasher`, see the class documentation. For the parse_command() -interface or standalone execution: - -usage: nrf5_firmware_utils.py [-h] [--verbose] [--erase] [--application FILE] - [--verify_application] [--reset] [--skip_reset] - [--nrfjprog FILE] [--snr SERIAL] - [--family FAMILY] [--softdevice FILE] - [--skip_softdevice] - -Flash NRF5 device - -optional arguments: - -h, --help show this help message and exit - -configuration: - --verbose, -v Report more verbosely - --nrfjprog FILE File name of the nrfjprog executable - --snr SERIAL, --serial SERIAL, -s SERIAL - Serial number of device to flash - --family FAMILY NRF5 device family - -operations: - --erase Erase device - --application FILE Flash an image - --verify_application, --verify-application - Verify the image after flashing - --reset Reset device after flashing - --skip_reset, --skip-reset - Do not reset device after flashing - --softdevice FILE Softdevice image file name - --skip_softdevice, --skip-softdevice - Do not flash softdevice even if softdevice is set -""" - -import errno -import os -import sys - -import firmware_utils - -# Additional options that can be use to configure an `Flasher` -# object (as dictionary keys) and/or passed as command line options. -NRF5_OPTIONS = { - # Configuration options define properties used in flashing operations. - 'configuration': { - # Tool configuration options. - 'nrfjprog': { - 'help': 'File name of the nrfjprog executable', - 'default': 'nrfjprog', - 'argparse': { - 'metavar': 'FILE' - }, - 'command': [ - '{nrfjprog}', - {'optional': 'family'}, - {'optional': 'snr'}, - () - ], - 'verify': ['{nrfjprog}', '--version'], - 'error': - """\ - Unable to execute {nrfjprog}. - - Please ensure that this tool is installed and - available. See the NRF5 example README for - installation instructions. - - """, - }, - 'snr': { - 'help': 'Serial number of device to flash', - 'default': None, - 'alias': ['--serial', '-s'], - 'argparse': { - 'metavar': 'SERIAL' - }, - }, - - # Device configuration options. - 'family': { - 'help': 'NRF5 device family', - 'default': None, - 'argparse': { - 'metavar': 'FAMILY' - }, - }, - }, - - # Action control options specify operations that Flasher.action() or - # the function interface flash_command() will perform. - 'operations': { - 'softdevice': { - 'help': 'Softdevice image file name', - 'default': None, - 'argparse': { - 'metavar': 'FILE' - }, - }, - 'skip_softdevice': { - 'help': 'Do not flash softdevice even if softdevice is set', - 'default': False, - 'argparse': { - 'action': 'store_true' - }, - }, - } -} - - -class Flasher(firmware_utils.Flasher): - """Manage nrf5 flashing.""" - - def __init__(self, **options): - super().__init__(platform='NRF5', module=__name__, **options) - self.define_options(NRF5_OPTIONS) - - def erase(self): - """Perform nrfjprog --eraseall""" - return self.run_tool('nrfjprog', ['--eraseall'], name='Erase all') - - def verify(self, image): - """Verify image.""" - return self.run_tool('nrfjprog', - ['--quiet', '--verify', image], - name='Verify', - pass_message='Verified', - fail_message='Not verified', - fail_level=2) - - def flash(self, image): - """Flash image.""" - return self.run_tool('nrfjprog', - ['--program', image, '--sectorerase'], - name='Flash') - - def reset(self): - """Reset the device.""" - return self.run_tool('nrfjprog', ['--reset'], name='Reset') - - def actions(self): - """Perform actions on the device according to self.option.""" - self.log(3, 'Options:', self.option) - - if self.option.erase: - if self.erase().err: - return self - - softdevice = self.optional_file(self.option.softdevice) - if softdevice and not self.option.skip_softdevice: - if self.verify(softdevice).err: - if self.err == errno.ENOENT: - return self - if self.flash(softdevice).err: - return self - if self.option.verify_application: - if self.verify(softdevice).err: - return self - - application = self.optional_file(self.option.application) - if application: - if self.flash(application).err: - return self - if self.option.verify_application: - if self.verify(application).err: - return self - if self.option.reset is None: - self.option.reset = True - - if self.option.reset: - if self.reset().err: - return self - - return self - -### Mobly integration -class Nrf5Platform: - def __init__(self, flasher_args): - self.flasher = Flasher(**flasher_args) - - def flash(self): - self.flasher.flash_command([os.getcwd()]) - -def verify_platform_args(platform_args): - required_args = ['application', 'softdevice'] - for r in required_args: - if not r in platform_args: - raise ValueError("Required argument %s missing" % r) - -def create_platform(platform_args): - verify_platform_args(platform_args[0]) - return Nrf5Platform(platform_args[0]) - -### End of Mobly integration - -if __name__ == '__main__': - sys.exit(Flasher().flash_command(sys.argv)) diff --git a/scripts/helpers/update_compile_commands.sh b/scripts/helpers/update_compile_commands.sh index 475449641b5aa9..012cd5ab4ad74a 100755 --- a/scripts/helpers/update_compile_commands.sh +++ b/scripts/helpers/update_compile_commands.sh @@ -38,8 +38,5 @@ mv "$CHIP_ROOT/out/debug/compile_commands.json" "$CHIP_ROOT/out/debug/compile_co gn --root="$CHIP_ROOT" gen "$CHIP_ROOT/out/debug" --export-compile-commands=all_android_arm64 mv "$CHIP_ROOT/out/debug/compile_commands.json" "$CHIP_ROOT/out/debug/compile_commands.android_arm64.json" -gn --root="$CHIP_ROOT" gen "$CHIP_ROOT/out/debug" --export-compile-commands=nrf5_lock_app,nrf5_lighting_app -mv "$CHIP_ROOT/out/debug/compile_commands.json" "$CHIP_ROOT/out/debug/compile_commands.nrf5.json" - gn --root="$CHIP_ROOT" gen "$CHIP_ROOT/out/debug" --export-compile-commands=efr32_lock_app mv "$CHIP_ROOT/out/debug/compile_commands.json" "$CHIP_ROOT/out/debug/compile_commands.efr32.json" diff --git a/src/lwip/BUILD.gn b/src/lwip/BUILD.gn index e67069faa8eaa1..40fa3eae7712a7 100644 --- a/src/lwip/BUILD.gn +++ b/src/lwip/BUILD.gn @@ -28,8 +28,8 @@ if (lwip_platform == "") { } assert(lwip_platform == "external" || lwip_platform == "standalone" || - lwip_platform == "nrf5" || lwip_platform == "efr32" || - lwip_platform == "k32w" || lwip_platform == "qpg6100", + lwip_platform == "efr32" || lwip_platform == "k32w" || + lwip_platform == "qpg6100", "Unsupported lwIP platform: ${lwip_platform}") if (lwip_platform != "external") { @@ -39,9 +39,7 @@ if (lwip_platform != "external") { } } -if (lwip_platform == "nrf5") { - import("//build_overrides/nrf5_sdk.gni") -} else if (lwip_platform == "efr32") { +if (lwip_platform == "efr32") { import("//build_overrides/efr32_sdk.gni") } else if (lwip_platform == "qpg6100") { import("//build_overrides/qpg6100_sdk.gni") @@ -107,9 +105,7 @@ if (current_os == "zephyr") { } public_deps = [ ":lwip_buildconfig" ] - if (lwip_platform == "nrf5") { - public_deps += [ "${nrf5_sdk_build_root}:nrf5_sdk" ] - } else if (lwip_platform == "efr32") { + if (lwip_platform == "efr32") { public_deps += [ "${efr32_sdk_build_root}:efr32_sdk" ] } else if (lwip_platform == "qpg6100") { public_deps += [ "${qpg6100_sdk_build_root}:qpg6100_sdk" ] diff --git a/src/lwip/nrf5/arch/cc.h b/src/lwip/nrf5/arch/cc.h deleted file mode 100644 index 292118fe91e63a..00000000000000 --- a/src/lwip/nrf5/arch/cc.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018-2019 Google LLC. - * - * 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. - */ - -/* - * - * Description: - * This file defines processor-architecture- and toolchain- - * specific constants and types required for building - * LwIP against FreeRTOS. - * - */ - -#ifndef CHIP_LWIP_FREERTOS_ARCH_CC_H -#define CHIP_LWIP_FREERTOS_ARCH_CC_H - -#include -#include -#include -#include -#include - -#if CHIP_CONFIG_MEMORY_MGMT_MALLOC -#include -#endif - -#include - -#include "app_error.h" - -#if __cplusplus -extern "C" { -#endif - -#ifndef LWIP_NOASSERT -#ifdef DEBUG -#define LWIP_PLATFORM_ASSERT(MSG) APP_ERROR_HANDLER(0) -#else -#define LWIP_PLATFORM_ASSERT(MSG) APP_ERROR_HANDLER(0) -#endif -#else -#define LWIP_PLATFORM_ASSERT(message) -#endif - -#ifndef BYTE_ORDER -#if defined(__LITTLE_ENDIAN__) -#define BYTE_ORDER LITTLE_ENDIAN -#elif defined(__BIG_ENDIAN__) -#define BYTE_ORDER BIG_ENDIAN -#elif defined(__BYTE_ORDER__) -#define BYTE_ORDER __BYTE_ORDER__ -#endif -#endif // BYTE_ORDER - -#define PACK_STRUCT_STRUCT __attribute__((__packed__)) -#define PACK_STRUCT_FIELD(x) x - -extern void LwIPLog(const char * fmt, ...); -#define LWIP_PLATFORM_DIAG(x) \ - do \ - { \ - LwIPLog x; \ - } while (0) - -// Place LwIP pools into their own subsections of .bss to make it easier to see -// their sizes in the linker map file. -extern uint8_t __attribute__((section(".bss.lwip_ND6_QUEUE"))) memp_memory_ND6_QUEUE_base[]; -extern uint8_t __attribute__((section(".bss.lwip_IP6_REASSDATA"))) memp_memory_IP6_REASSDATA_base[]; -extern uint8_t __attribute__((section(".bss.lwip_RAW_PCB"))) memp_memory_RAW_PCB_base[]; -extern uint8_t __attribute__((section(".bss.lwip_TCP_SEG"))) memp_memory_TCP_SEG_base[]; -extern uint8_t __attribute__((section(".bss.lwip_PBUF_POOL"))) memp_memory_PBUF_POOL_base[]; -extern uint8_t __attribute__((section(".bss.lwip_FRAG_PBUF"))) memp_memory_FRAG_PBUF_base[]; -extern uint8_t __attribute__((section(".bss.lwip_PBUF"))) memp_memory_PBUF_base[]; -extern uint8_t __attribute__((section(".bss.lwip_TCP_PCB_LISTEN"))) memp_memory_TCP_PCB_LISTEN_base[]; -extern uint8_t __attribute__((section(".bss.lwip_REASSDATA"))) memp_memory_REASSDATA_base[]; -extern uint8_t __attribute__((section(".bss.lwip_UDP_PCB"))) memp_memory_UDP_PCB_base[]; -extern uint8_t __attribute__((section(".bss.lwip_MLD6_GROUP"))) memp_memory_MLD6_GROUP_base[]; -extern uint8_t __attribute__((section(".bss.lwip_IGMP_GROUP"))) memp_memory_IGMP_GROUP_base[]; -extern uint8_t __attribute__((section(".bss.lwip_TCP_PCB"))) memp_memory_TCP_PCB_base[]; -extern uint8_t __attribute__((section(".bss.lwip_SYS_TIMEOUT"))) memp_memory_SYS_TIMEOUT_base[]; - -#if __cplusplus -} -#endif - -#endif /* CHIP_LWIP_FREERTOS_ARCH_CC_H */ diff --git a/src/lwip/nrf5/arch/perf.h b/src/lwip/nrf5/arch/perf.h deleted file mode 100644 index 5c15942730ca8f..00000000000000 --- a/src/lwip/nrf5/arch/perf.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018-2019 Google LLC. - * - * 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. - */ - -/* - * - * Description: - * This file defines processor-architecture-specific constants, - * interfaces and types required for LwIP performance - * measurement. - * - */ - -#ifndef CHIP_LWIP_FREERTOS_ARCH_PERF_H -#define CHIP_LWIP_FREERTOS_ARCH_PERF_H - -#define PERF_START -#define PERF_STOP(s) - -#endif /* CHIP_LWIP_FREERTOS_ARCH_PERF_H */ diff --git a/src/lwip/nrf5/lwipopts.h b/src/lwip/nrf5/lwipopts.h deleted file mode 100644 index 808e7b76ff8242..00000000000000 --- a/src/lwip/nrf5/lwipopts.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Compile-time configuration for LwIP on nRF52 platforms using the - * Nordic nRF5 SDK. - * - */ - -#ifndef __LWIPOPTS_H__ -#define __LWIPOPTS_H__ - -#if CHIP_HAVE_CONFIG_H -#include -#endif - -#include - -#define NO_SYS 0 -#define MEM_ALIGNMENT (4) -#define MEMP_NUM_TCP_SEG (TCP_SND_QUEUELEN + 1) -#define LWIP_TIMEVAL_PRIVATE (0) -#define MEM_LIBC_MALLOC (0) -#define LWIP_COMPAT_MUTEX (0) -#define SYS_LIGHTWEIGHT_PROT (1) -#define LWIP_AUTOIP (0) -#define LWIP_DHCP_AUTOIP_COOP (0) -#define LWIP_SOCKET_SET_ERRNO 0 -#define IP_REASS_MAX_PBUFS 0 -#define IP_REASSEMBLY 0 -#define MEMP_NUM_REASSDATA 0 -#define LWIP_SO_RCVTIMEO 0 -#define SO_REUSE (1) -#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS (1) -#define LWIP_STATS (0) -#define LWIP_TCPIP_CORE_LOCKING 1 -#define TCP_QUEUE_OOSEQ 0 -#define ARP_QUEUEING (0) -#define TCPIP_THREAD_NAME "LWIP" - -#define LWIP_SOCKET 0 - -// TODO: seems like this is unnecessary on Thread-only platforms -#define LWIP_RAW 1 -#define MEMP_NUM_RAW_PCB (5) - -// TODO: verify count -#define MEMP_NUM_UDP_PCB (7) - -#define LWIP_HAVE_LOOPIF (0) - -// TODO: not sure why this is disabled -#define LWIP_NETIF_LOOPBACK (0) - -#define MEMP_NUM_NETCONN (0) - -#define LWIP_IPV4 0 -#define LWIP_IPV6 1 -#define LWIP_ARP (0) -#define LWIP_DNS (0) -#define LWIP_ICMP (0) -#define LWIP_IGMP (0) -#define LWIP_DHCP (0) -#define LWIP_IPV6_REASS (0) -#define LWIP_IPV6_DHCP6 0 -#define LWIP_IPV6_AUTOCONFIG (0) -#define LWIP_IPV6_ROUTER_SUPPORT 0 -#define LWIP_ND6_LISTEN_RA 0 - -#define LWIP_ND6_NUM_NEIGHBORS (0) -#define LWIP_ND6_NUM_DESTINATIONS (0) -#define LWIP_ND6_NUM_PREFIXES (0) -#define LWIP_ND6_NUM_ROUTERS (0) -#define LWIP_ND6_MAX_MULTICAST_SOLICIT (0) -#define LWIP_ND6_MAX_UNICAST_SOLICIT (0) -#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT (0) -#define LWIP_ND6_TCP_REACHABILITY_HINTS (0) - -#define MEMP_SEPARATE_POOLS (1) -#define LWIP_PBUF_FROM_CUSTOM_POOLS (0) -#define MEMP_USE_CUSTOM_POOLS (0) -#define PBUF_POOL_SIZE (8) -#define PBUF_POOL_BUFSIZE (1500) -#define PBUF_POOL_SIZE_LARGE (3) -#define PBUF_POOL_SIZE_MEDIUM (4) -#define PBUF_POOL_SIZE_SMALL (5) -#define PBUF_POOL_BUFSIZE_LARGE (1280) -#define PBUF_POOL_BUFSIZE_MEDIUM (640) -#define PBUF_POOL_BUFSIZE_SMALL (256) -#define PBUF_CUSTOM_POOL_IDX_START (MEMP_PBUF_POOL_SMALL) -#define PBUF_CUSTOM_POOL_IDX_END (MEMP_PBUF_POOL_LARGE) - -#define TCP_MSS (1152) -#define TCP_SND_BUF (2 * TCP_MSS) -#define TCP_LISTEN_BACKLOG (1) - -#define ETH_PAD_SIZE (0) -#define SUB_ETHERNET_HEADER_SPACE (0) -#define PBUF_LINK_HLEN (0) - -#define TCPIP_THREAD_STACKSIZE (4096) -#define TCPIP_THREAD_PRIO (2) - -#define NETIF_MAX_HWADDR_LEN 8U - -#define LWIP_IPV6_NUM_ADDRESSES 5 - -#define LWIP_IPV6_ND 0 -#define LWIP_ND6_QUEUEING 0 - -#define LWIP_MULTICAST_PING 0 - -#define TCPIP_MBOX_SIZE 6 -#define DEFAULT_RAW_RECVMBOX_SIZE 6 -#define DEFAULT_UDP_RECVMBOX_SIZE 6 -#define DEFAULT_TCP_RECVMBOX_SIZE 6 - -// TODO: make LWIP_DEBUG conditional on build type - -#ifndef LWIP_DEBUG -#define LWIP_DEBUG 1 -#endif - -#define MEMP_OVERFLOW_CHECK (0) -#define MEMP_SANITY_CHECK (0) -#define MEM_DEBUG (LWIP_DBG_OFF) -#define MEMP_DEBUG (LWIP_DBG_OFF) -#define PBUF_DEBUG (LWIP_DBG_OFF) -#define API_LIB_DEBUG (LWIP_DBG_OFF) -#define API_MSG_DEBUG (LWIP_DBG_OFF) -#define TCPIP_DEBUG (LWIP_DBG_OFF) -#define NETIF_DEBUG (LWIP_DBG_OFF) -#define SOCKETS_DEBUG (LWIP_DBG_OFF) -#define DEMO_DEBUG (LWIP_DBG_OFF) -#define DHCP_DEBUG (LWIP_DBG_OFF) -#define AUTOIP_DEBUG (LWIP_DBG_OFF) -#define ETHARP_DEBUG (LWIP_DBG_OFF) -#define IP_DEBUG (LWIP_DBG_OFF) -#define IP_REASS_DEBUG (LWIP_DBG_OFF) -#define IP6_DEBUG (LWIP_DBG_OFF) -#define RAW_DEBUG (LWIP_DBG_OFF) -#define ICMP_DEBUG (LWIP_DBG_OFF) -#define UDP_DEBUG (LWIP_DBG_OFF) -#define TCP_DEBUG (LWIP_DBG_OFF) -#define TCP_INPUT_DEBUG (LWIP_DBG_OFF) -#define TCP_OUTPUT_DEBUG (LWIP_DBG_OFF) -#define TCP_RTO_DEBUG (LWIP_DBG_OFF) -#define TCP_CWND_DEBUG (LWIP_DBG_OFF) -#define TCP_WND_DEBUG (LWIP_DBG_OFF) -#define TCP_FR_DEBUG (LWIP_DBG_OFF) -#define TCP_QLEN_DEBUG (LWIP_DBG_OFF) -#define TCP_RST_DEBUG (LWIP_DBG_OFF) -#define PPP_DEBUG (LWIP_DBG_OFF) - -#define LWIP_DBG_TYPES_ON \ - (LWIP_DBG_ON | LWIP_DBG_TRACE) /* (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) */ - -#endif /* __LWIPOPTS_H__ */ diff --git a/src/lwip/nrf5/lwippools.h b/src/lwip/nrf5/lwippools.h deleted file mode 100644 index 2c42ac043074da..00000000000000 --- a/src/lwip/nrf5/lwippools.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2020 Project CHIP Authors - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ diff --git a/src/lwip/qpg6100/lwipopts.h b/src/lwip/qpg6100/lwipopts.h index 9f719ebec0bb9b..7a3aaaf3f06bb1 100644 --- a/src/lwip/qpg6100/lwipopts.h +++ b/src/lwip/qpg6100/lwipopts.h @@ -18,8 +18,7 @@ /** * @file - * Compile-time configuration for LwIP on nRF52 platforms using the - * Nordic nRF5 SDK. + * Compile-time configuration for LwIP on QPG6100 platforms. * */ diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 3daffa9e67ee6f..2cf62921c7760b 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -25,10 +25,6 @@ if (chip_enable_openthread) { import("//build_overrides/ot_br_posix.gni") } -if (chip_device_platform == "nrf5") { - import("//build_overrides/nrf5_sdk.gni") -} - if (chip_device_platform == "linux" && chip_enable_mdns) { pkg_config("avahi_client_config") { packages = [ "avahi-client" ] @@ -96,11 +92,6 @@ if (chip_device_platform != "none") { "CHIP_DEVICE_LAYER_TARGET_LINUX=1", "CHIP_DEVICE_LAYER_TARGET=Linux", ] - } else if (chip_device_platform == "nrf5") { - defines += [ - "CHIP_DEVICE_LAYER_TARGET_NRF5=1", - "CHIP_DEVICE_LAYER_TARGET=nRF5", - ] } else if (chip_device_platform == "nrfconnect") { defines += [ "CHIP_DEVICE_LAYER_TARGET_NRFCONNECT=1", @@ -375,47 +366,6 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { } public_deps += [ "${chip_root}/third_party/inipp" ] - } else if (chip_device_platform == "nrf5") { - sources += [ - "FreeRTOS/SystemTimeSupport.cpp", - "nRF5/BLEManagerImpl.cpp", - "nRF5/BLEManagerImpl.h", - "nRF5/BlePlatformConfig.h", - "nRF5/CHIPDevicePlatformConfig.h", - "nRF5/CHIPDevicePlatformEvent.h", - "nRF5/CHIPPlatformConfig.h", - "nRF5/ConfigurationManagerImpl.cpp", - "nRF5/ConfigurationManagerImpl.h", - "nRF5/ConnectivityManagerImpl.cpp", - "nRF5/ConnectivityManagerImpl.h", - "nRF5/DeviceNetworkProvisioningDelegateImpl.cpp", - "nRF5/DeviceNetworkProvisioningDelegateImpl.h", - "nRF5/InetPlatformConfig.h", - "nRF5/Logging.cpp", - "nRF5/PlatformManagerImpl.cpp", - "nRF5/PlatformManagerImpl.h", - "nRF5/SystemPlatformConfig.h", - "nRF5/nRF5Config.cpp", - "nRF5/nRF5Config.h", - "nRF5/nRF5Utils.cpp", - "nRF5/nRF5Utils.h", - ] - - public_deps += [ "${nrf5_sdk_build_root}:nrf5_sdk" ] - - if (chip_enable_openthread) { - public_deps += [ - "${chip_root}/third_party/openthread/platforms/nrf528xx:libnordicsemi_nrf52840_radio_driver_softdevice", - "${chip_root}/third_party/openthread/platforms/nrf528xx:libopenthread-nrf52840-softdevice-sdk", - "${openthread_root}:libopenthread-ftd", - ] - - sources += [ - "OpenThread/OpenThreadUtils.cpp", - "nRF5/ThreadStackManagerImpl.cpp", - "nRF5/ThreadStackManagerImpl.h", - ] - } } else if (chip_device_platform == "nrfconnect") { sources += [ "Zephyr/SystemTimeSupport.cpp", diff --git a/src/platform/device.gni b/src/platform/device.gni index adfb781337908c..9237b06ce6ae13 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -15,7 +15,7 @@ import("//build_overrides/chip.gni") declare_args() { - # Device platform layer: darwin, efr32, esp32, external, freertos, linux, nrf5, nrfconnect, k32w, qpg6100, none. + # Device platform layer: darwin, efr32, esp32, external, freertos, linux, nrfconnect, k32w, qpg6100, none. chip_device_platform = "auto" chip_platform_target = "" } @@ -33,8 +33,8 @@ if (chip_device_platform == "auto") { declare_args() { # Enable openthread support. chip_enable_openthread = - chip_device_platform == "linux" || chip_device_platform == "nrf5" || - chip_device_platform == "efr32" || chip_device_platform == "k32w" + chip_device_platform == "linux" || chip_device_platform == "efr32" || + chip_device_platform == "k32w" # Enable wifi support. chip_enable_wifi = chip_device_platform == "linux" @@ -56,8 +56,6 @@ if (chip_device_platform == "darwin") { _chip_device_layer = "ESP32" } else if (chip_device_platform == "linux") { _chip_device_layer = "Linux" -} else if (chip_device_platform == "nrf5") { - _chip_device_layer = "nRF5" } else if (chip_device_platform == "nrfconnect") { _chip_device_layer = "nrfconnect" } else if (chip_device_platform == "qpg6100") { @@ -99,7 +97,7 @@ assert( (current_os != "freertos" && chip_device_platform == "none") || chip_device_platform == "darwin" || chip_device_platform == "efr32" || chip_device_platform == "esp32" || chip_device_platform == "external" || - chip_device_platform == "linux" || chip_device_platform == "nrf5" || + chip_device_platform == "linux" || chip_device_platform == "nrfconnect" || chip_device_platform == "k32w" || chip_device_platform == "qpg6100", "Please select a valid value for chip_device_platform") diff --git a/src/platform/nRF5/BLEManagerImpl.cpp b/src/platform/nRF5/BLEManagerImpl.cpp deleted file mode 100644 index fd270dbba11f98..00000000000000 --- a/src/platform/nRF5/BLEManagerImpl.cpp +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the BLEManager singleton object - * for the nRF5 platforms. - */ -/* this file behaves like a config.h, comes first */ -#include - -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - -#include -#include - -#include -#include - -#include - -#include "ble.h" -#include "ble_advdata.h" -#include "ble_gap.h" -#include "ble_gattc.h" -#include "ble_srv_common.h" -#include "nrf_ble_gatt.h" -#include "nrf_error.h" - -#ifdef SOFTDEVICE_PRESENT -#include "nrf_sdh.h" -#include "nrf_sdh_ble.h" -#include "nrf_sdh_soc.h" -#endif - -#if CHIP_ENABLE_OPENTHREAD -extern "C" { -#include -} -#endif // CHIP_ENABLE_OPENTHREAD - -#define NRF_LOG_MODULE_NAME chip -#include "nrf_log.h" - -#if NRF_LOG_ENABLED -#include "nrf_log_backend_uart.h" -#include "nrf_log_ctrl.h" -#include "nrf_log_default_backends.h" -#endif // NRF_LOG_ENABLED - -using namespace chip::Ble; - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -namespace { - -const uint16_t UUID16_CHIPoBLEService = 0xFEAF; -const ble_uuid_t UUID_CHIPoBLEService = { UUID16_CHIPoBLEService, BLE_UUID_TYPE_BLE }; - -const ble_uuid128_t UUID128_CHIPoBLEChar_RX = { { 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, - 0x2E, 0xEE, 0x18 } }; -ble_uuid_t UUID_CHIPoBLEChar_RX; -const ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, - 0x9D, 0x11 } }; - -const ble_uuid128_t UUID128_CHIPoBLEChar_TX = { { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, - 0x2E, 0xEE, 0x18 } }; -ble_uuid_t UUID_CHIPoBLEChar_TX; -const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, - 0x9D, 0x12 } }; - -NRF_BLE_GATT_DEF(GATTModule); - -CHIP_ERROR RegisterVendorUUID(ble_uuid_t & uuid, const ble_uuid128_t & vendorUUID) -{ - CHIP_ERROR err; - - err = sd_ble_uuid_vs_add(&vendorUUID, &uuid.type); - SuccessOrExit(err); - static_assert(CHAR_BIT == 8, "We're about to assume chars are at most 8 bits wide"); - static_assert(std::is_same::type, const unsigned char>::value, - "Our bits will overlap"); - uuid.uuid = static_cast((((uint16_t) vendorUUID.uuid128[13]) << 8) | vendorUUID.uuid128[12]); - -exit: - return err; -} - -} // unnamed namespace - -BLEManagerImpl BLEManagerImpl::sInstance; -#ifndef CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY -#define CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY 3 -#endif // CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY - -static uint32_t LogTimestamp(void) -{ - return 0; -} - -CHIP_ERROR BLEManagerImpl::_PlatformInit() -{ - if (!nrf_sdh_is_enabled()) - { - return CHIP_ERROR_WELL_UNINITIALIZED; - } - else - { - return CHIP_NO_ERROR; - } -} - -CHIP_ERROR BLEManagerImpl::_Init() -{ - CHIP_ERROR err; - uint16_t svcHandle; - ble_add_char_params_t addCharParams; - - mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; - mFlags = CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? kFlag_AdvertisingEnabled : 0; - mAdvHandle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; - mNumGAPCons = 0; - for (int i = 0; i < kMaxConnections; i++) - { - mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; - } - - NRF_LOG_INFO("Starting BLE initialization"); - NRF_LOG_FLUSH(); - - // Initialize the CHIP BleLayer. - err = BleLayer::Init(this, this, &SystemLayer); - SuccessOrExit(err); - - // Initialize the Softdevice - err = _PlatformInit(); - SuccessOrExit(err); - - // Register vendor-specific UUIDs with the soft device. - // NOTE: An NRF_ERROR_NO_MEM here means the soft device hasn't been configured - // with space for enough custom UUIDs. Typically, this limit is set by overriding - // the NRF_SDH_BLE_VS_UUID_COUNT config option. - err = RegisterVendorUUID(UUID_CHIPoBLEChar_RX, UUID128_CHIPoBLEChar_RX); - SuccessOrExit(err); - err = RegisterVendorUUID(UUID_CHIPoBLEChar_TX, UUID128_CHIPoBLEChar_TX); - SuccessOrExit(err); - - // Add the CHIPoBLE service. - err = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, (ble_uuid_t *) &UUID_CHIPoBLEService, &svcHandle); - SuccessOrExit(err); - - // Add the CHIPoBLEChar_RX characteristic to the CHIPoBLE service. - memset(&addCharParams, 0, sizeof(addCharParams)); - addCharParams.uuid = UUID_CHIPoBLEChar_RX.uuid; - addCharParams.uuid_type = UUID_CHIPoBLEChar_RX.type; - addCharParams.max_len = NRF_SDH_BLE_GATT_MAX_MTU_SIZE; - addCharParams.init_len = 0; - addCharParams.is_var_len = true; - addCharParams.char_props.write_wo_resp = 1; - addCharParams.char_props.write = 1; - addCharParams.read_access = SEC_OPEN; - addCharParams.write_access = SEC_OPEN; - addCharParams.cccd_write_access = SEC_NO_ACCESS; - err = characteristic_add(svcHandle, &addCharParams, &mCHIPoBLECharHandle_RX); - SuccessOrExit(err); - - // Add the CHIPoBLEChar_TX characteristic. - memset(&addCharParams, 0, sizeof(addCharParams)); - addCharParams.uuid = UUID_CHIPoBLEChar_TX.uuid; - addCharParams.uuid_type = UUID_CHIPoBLEChar_TX.type; - addCharParams.max_len = NRF_SDH_BLE_GATT_MAX_MTU_SIZE; - addCharParams.is_var_len = true; - addCharParams.char_props.read = 1; - addCharParams.char_props.write = 1; - addCharParams.char_props.indicate = 1; - addCharParams.read_access = SEC_OPEN; - addCharParams.write_access = SEC_OPEN; - addCharParams.cccd_write_access = SEC_OPEN; - err = characteristic_add(svcHandle, &addCharParams, &mCHIPoBLECharHandle_TX); - SuccessOrExit(err); - - // Initialize the nRF5 GATT module and set the allowable GATT MTU and GAP packet sizes - // based on compile-time config values. - err = nrf_ble_gatt_init(&GATTModule, NULL); - SuccessOrExit(err); - err = nrf_ble_gatt_att_mtu_periph_set(&GATTModule, NRF_SDH_BLE_GATT_MAX_MTU_SIZE); - SuccessOrExit(err); - err = nrf_ble_gatt_data_length_set(&GATTModule, BLE_CONN_HANDLE_INVALID, NRF_SDH_BLE_GAP_DATA_LENGTH); - SuccessOrExit(err); - - // Register a handler for BLE events. - NRF_SDH_BLE_OBSERVER(sBLEObserver, CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY, SoftDeviceBLEEventCallback, NULL); - - // Set a default device name. - err = _SetDeviceName(NULL); - SuccessOrExit(err); - - // TODO: call sd_ble_gap_ppcp_set() to set gap parameters??? - - PlatformMgr().ScheduleWork(DriveBLEState, 0); - -exit: - ChipLogProgress(DeviceLayer, "BLEManagerImpl::Init() complete"); - return err; -} - -CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); - - if (val != mServiceMode) - { - mServiceMode = val; - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); - - if (GetFlag(mFlags, kFlag_AdvertisingEnabled) != val) - { - SetFlag(mFlags, kFlag_AdvertisingEnabled, val); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::_SetFastAdvertisingEnabled(bool val) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); - - if (GetFlag(mFlags, kFlag_FastAdvertisingEnabled) != val) - { - SetFlag(mFlags, kFlag_FastAdvertisingEnabled, val); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize) -{ - CHIP_ERROR err; - uint16_t len = (uint16_t)(bufSize - 1); - - err = sd_ble_gap_device_name_get((uint8_t *) buf, &len); - SuccessOrExit(err); - - buf[len] = 0; - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * devName) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - ble_gap_conn_sec_mode_t secMode; - char devNameBuf[kMaxDeviceNameLength + 1]; - - VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); - - if (devName != NULL && devName[0] != 0) - { - VerifyOrExit(strlen(devName) <= kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); - strcpy(devNameBuf, devName); - } - else - { - // FIXME: the name should be derived from factory data - snprintf(devNameBuf, sizeof(devNameBuf), "%s%04" PRIX32, CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, (uint32_t) 0); - devNameBuf[kMaxDeviceNameLength] = 0; - } - - // Do not allow device name characteristic to be changed - BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&secMode); - - // Configure the device name within the BLE soft device. - static_assert(CHAR_BIT == 8, "We're casting char to uint8_t"); - static_assert(sizeof(devNameBuf) < UINT16_MAX, "Our length might not fit in a uint16_t"); - err = sd_ble_gap_device_name_set(&secMode, (const uint8_t *) devNameBuf, static_cast(strlen(devNameBuf))); - SuccessOrExit(err); - -exit: - return err; -} - -void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) -{ - switch (event->Type) - { - case DeviceEventType::kSoftDeviceBLEEvent: - HandleSoftDeviceBLEEvent(event); - break; - - case DeviceEventType::kCHIPoBLERXCharWriteEvent: - HandleRXCharWrite(event); - break; - - case DeviceEventType::kCHIPoBLEOutOfBuffersEvent: - ChipLogError(DeviceLayer, "BLEManagerImpl: Out of buffers during CHIPoBLE RX"); - break; - - case DeviceEventType::kFabricMembershipChange: - case DeviceEventType::kServiceProvisioningChange: - case DeviceEventType::kAccountPairingChange: - - // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the - // device's provisioning state, then automatically disable CHIPoBLE advertising if the device - // is now fully provisioned. -#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - if (ConfigurationMgr().IsFullyProvisioned()) - { - ClearFlag(mFlags, kFlag_AdvertisingEnabled); - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); - } -#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - - // Force the advertising state to be refreshed to reflect new provisioning state. - SetFlag(mFlags, kFlag_AdvertisingRefreshNeeded); - - DriveBLEState(); - - break; - - default: - break; - } -} - -bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported"); - return false; -} - -bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported"); - return false; -} - -bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); - - // Initiate a GAP disconnect. - err = sd_ble_gap_disconnect(conId, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "sd_ble_gap_disconnect() failed: %s", ErrorStr(err)); - } - - return (err == CHIP_NO_ERROR); -} - -uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const -{ - return nrf_ble_gatt_eff_mtu_get(&GATTModule, conId); -} - -bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, - PacketBuffer * data) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - ble_gatts_hvx_params_t hvxParams; - uint16_t dataLen = data->DataLength(); - - VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT); - - ChipLogDetail(DeviceLayer, "Sending indication for CHIPoBLE TX characteristic (con %u, len %u)", conId, dataLen); - - // Send a indication for the CHIPoBLE TX characteristic to the client containing the supplied data. - // Note that this call copies the data from the buffer. - memset(&hvxParams, 0, sizeof(hvxParams)); - hvxParams.type = BLE_GATT_HVX_INDICATION; - hvxParams.handle = mCHIPoBLECharHandle_TX.value_handle; - hvxParams.offset = 0; - hvxParams.p_len = &dataLen; - hvxParams.p_data = data->Start(); - err = sd_ble_gatts_hvx(conId, &hvxParams); - SuccessOrExit(err); - -exit: - PacketBuffer::Free(data); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err)); - return false; - } - return true; -} - -bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, - PacketBuffer * pBuf) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported"); - return false; -} - -bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, - PacketBuffer * pBuf) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported"); - return false; -} - -bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, - const ChipBleUUID * svcId, const ChipBleUUID * charId) -{ - ChipLogProgress(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported"); - return false; -} - -void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) -{ - // Nothing to do -} - -void BLEManagerImpl::DriveBLEState(void) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - // Perform any initialization actions that must occur after the CHIP task is running. - if (!GetFlag(mFlags, kFlag_AsyncInitCompleted)) - { - SetFlag(mFlags, kFlag_AsyncInitCompleted); - - // If CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, - // disable CHIPoBLE advertising if the device is fully provisioned. -#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - if (ConfigurationMgr().IsFullyProvisioned()) - { - ClearFlag(mFlags, kFlag_AdvertisingEnabled); - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); - } -#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED - } - - // If the application has enabled CHIPoBLE and BLE advertising... - if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && - GetFlag(mFlags, kFlag_AdvertisingEnabled) -#if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION - // and no connections are active... - && (mNumGAPCons == 0) -#endif - ) - { - // Start/re-start SoftDevice advertising if not already advertising, or if the - // advertising state of the SoftDevice needs to be refreshed. - if (!GetFlag(mFlags, kFlag_Advertising) || GetFlag(mFlags, kFlag_AdvertisingRefreshNeeded)) - { - err = StartAdvertising(); - SuccessOrExit(err); - } - } - - // Otherwise, stop advertising if currently active. - else - { - err = StopAdvertising(); - SuccessOrExit(err); - } - -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); - mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; - } -} - -#ifndef CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG -#define CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG 1 -#endif // CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG - -CHIP_ERROR BLEManagerImpl::StartAdvertising(void) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - ble_gap_adv_data_t gapAdvData; - ble_gap_adv_params_t gapAdvParams; - uint16_t numCHIPoBLECons; - bool connectable; - - // If necessary, inform the ThreadStackManager that CHIPoBLE advertising is about to start. -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - if (!GetFlag(mFlags, kFlag_Advertising)) - { - ThreadStackMgr().OnCHIPoBLEAdvertisingStart(); - } -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD - - // Since we're about to update the SoftDevice, clear the refresh needed flag. - ClearFlag(mFlags, kFlag_AdvertisingRefreshNeeded); - - if (mAdvHandle != BLE_GAP_ADV_SET_HANDLE_NOT_SET) - { - // Instruct the SoftDevice to stop advertising. - // Ignore any error indicating that advertising is already stopped. This case is arises - // when a connection is established, which causes the SoftDevice to immediately cease - // advertising. - err = sd_ble_gap_adv_stop(mAdvHandle); - if (err == NRF_ERROR_INVALID_STATE) - { - err = CHIP_NO_ERROR; - } - SuccessOrExit(err); - - // Force the SoftDevice to relinquish its references to the buffers containing the advertising - // data. This ensures the SoftDevice is not accessing these buffers while we are encoding - // new advertising data into them. - err = sd_ble_gap_adv_set_configure(&mAdvHandle, NULL, NULL); - SuccessOrExit(err); - } - - // Encode the data that will be sent in the advertising packet and the scan response packet. - err = EncodeAdvertisingData(gapAdvData); - SuccessOrExit(err); - - // Set advertising parameters. - memset(&gapAdvParams, 0, sizeof(gapAdvParams)); - gapAdvParams.primary_phy = BLE_GAP_PHY_1MBPS; - gapAdvParams.duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED; - gapAdvParams.filter_policy = BLE_GAP_ADV_FP_ANY; - - // Advertise connectable if we haven't reached the maximum number of CHIPoBLE connections or the - // maximum number of GAP connections. (Note that the SoftDevice will return an error if connectable - // advertising is requested when the max number of GAP connections exist). - numCHIPoBLECons = NumConnections(); - connectable = (numCHIPoBLECons < kMaxConnections && mNumGAPCons < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT); - gapAdvParams.properties.type = - connectable ? BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED : BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED; - - // Advertise in fast mode if not fully provisioned and there are no CHIPoBLE connections, or - // if the application has expressly requested fast advertising. - // TODO: Return back the !ConfigurationMgr().IsFullyProvisioned() checking when the ConfigurationMgr() will be available - gapAdvParams.interval = - ((numCHIPoBLECons == 0 /* && !ConfigurationMgr().IsFullyProvisioned()*/) || GetFlag(mFlags, kFlag_FastAdvertisingEnabled)) - ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL; - -#if CHIP_PROGRESS_LOGGING - - { - char devNameBuf[kMaxDeviceNameLength + 1]; - GetDeviceName(devNameBuf, sizeof(devNameBuf)); - ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable, device name %s)", - (((uint32_t) gapAdvParams.interval) * 10) / 16, (connectable) ? "" : "non-", devNameBuf); - } - -#endif // CHIP_PROGRESS_LOGGING - - // Configure an "advertising set" in the BLE soft device with the data and parameters for CHIP advertising. - // If the advertising set doesn't exist, this call will create it and return its handle. - err = sd_ble_gap_adv_set_configure(&mAdvHandle, &gapAdvData, &gapAdvParams); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "sd_ble_gap_adv_set_configure() failed: %s", ErrorStr(err)); - } - SuccessOrExit(err); - - // Instruct the BLE soft device to start advertising using the configured advertising set. - err = sd_ble_gap_adv_start(mAdvHandle, CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "sd_ble_gap_adv_start() failed: %s", ErrorStr(err)); - } - SuccessOrExit(err); - - // Transition to the Advertising state... - if (!GetFlag(mFlags, kFlag_Advertising)) - { - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started"); - - SetFlag(mFlags, kFlag_Advertising); - - // Post a CHIPoBLEAdvertisingChange(Started) event. - { - ChipDeviceEvent advChange; - advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; - advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; - PlatformMgr().PostEvent(&advChange); - } - } - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::StopAdvertising(void) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - // Since we're about to update the SoftDevice, clear the refresh needed flag. - ClearFlag(mFlags, kFlag_AdvertisingRefreshNeeded); - - // Instruct the SoftDevice to stop advertising. - // Ignore any error indicating that advertising is already stopped. This case is arises - // when a connection is established, which causes the SoftDevice to immediately cease - // advertising. - err = sd_ble_gap_adv_stop(mAdvHandle); - if (err == NRF_ERROR_INVALID_STATE) - { - err = CHIP_NO_ERROR; - } - SuccessOrExit(err); - - // Transition to the not Advertising state... - if (GetFlag(mFlags, kFlag_Advertising)) - { - ClearFlag(mFlags, kFlag_Advertising); - - ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); - - // Directly inform the ThreadStackManager that CHIPoBLE advertising has stopped. -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - ThreadStackMgr().OnCHIPoBLEAdvertisingStop(); -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD - - // Post a CHIPoBLEAdvertisingChange(Stopped) event. - { - ChipDeviceEvent advChange; - advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; - advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; - PlatformMgr().PostEvent(&advChange); - } - } - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::EncodeAdvertisingData(ble_gap_adv_data_t & gapAdvData) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - ble_advdata_t advData; - ble_advdata_service_data_t serviceData; - ChipBLEDeviceIdentificationInfo deviceIdInfo; - - // Form the contents of the advertising packet. - memset(&advData, 0, sizeof(advData)); - advData.name_type = BLE_ADVDATA_FULL_NAME; - advData.include_appearance = false; - advData.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; - advData.uuids_complete.uuid_cnt = 1; - advData.uuids_complete.p_uuids = (ble_uuid_t *) &UUID_CHIPoBLEService; - gapAdvData.adv_data.p_data = mAdvDataBuf; - gapAdvData.adv_data.len = sizeof(mAdvDataBuf); - err = ble_advdata_encode(&advData, mAdvDataBuf, &gapAdvData.adv_data.len); - SuccessOrExit(err); - - // Initialize the CHIP BLE Device Identification Information block that will be sent as payload - // within the BLE service advertisement data. - err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); - SuccessOrExit(err); - - // Form the contents of the scan response packet. - memset(&serviceData, 0, sizeof(serviceData)); - serviceData.service_uuid = UUID16_CHIPoBLEService; - serviceData.data.size = sizeof(deviceIdInfo); - serviceData.data.p_data = (uint8_t *) &deviceIdInfo; - memset(&advData, 0, sizeof(advData)); - advData.name_type = BLE_ADVDATA_NO_NAME; - advData.include_appearance = false; - advData.p_service_data_array = &serviceData; - advData.service_data_count = 1; - gapAdvData.scan_rsp_data.p_data = mScanRespDataBuf; - gapAdvData.scan_rsp_data.len = sizeof(mScanRespDataBuf); - err = ble_advdata_encode(&advData, mScanRespDataBuf, &gapAdvData.scan_rsp_data.len); - SuccessOrExit(err); - -exit: - return err; -} - -uint16_t BLEManagerImpl::_NumConnections(void) -{ - uint16_t numCons = 0; - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] != BLE_CONNECTION_UNINITIALIZED) - { - numCons++; - } - } - return numCons; -} - -void BLEManagerImpl::DriveBLEState(intptr_t arg) -{ - sInstance.DriveBLEState(); -} - -void BLEManagerImpl::HandleSoftDeviceBLEEvent(const ChipDeviceEvent * event) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - const ble_evt_t * bleEvent = &event->Platform.SoftDeviceBLEEvent.EventData; - - ChipLogDetail(DeviceLayer, "BLE SoftDevice event 0x%02x", bleEvent->header.evt_id); - - switch (bleEvent->header.evt_id) - { - case BLE_GAP_EVT_CONNECTED: - err = HandleGAPConnect(event); - SuccessOrExit(err); - break; - - case BLE_GAP_EVT_DISCONNECTED: - err = HandleGAPDisconnect(event); - SuccessOrExit(err); - break; - - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: - // BLE Pairing not supported - err = sd_ble_gap_sec_params_reply(bleEvent->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); - SuccessOrExit(err); - break; - - case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { - ChipLogDetail(DeviceLayer, "BLE GAP PHY update request (con %" PRIu16 ")", bleEvent->evt.gap_evt.conn_handle); - const ble_gap_phys_t phys = { BLE_GAP_PHY_AUTO, BLE_GAP_PHY_AUTO }; - err = sd_ble_gap_phy_update(bleEvent->evt.gap_evt.conn_handle, &phys); - SuccessOrExit(err); - break; - } - - case BLE_GATTS_EVT_SYS_ATTR_MISSING: - err = sd_ble_gatts_sys_attr_set(bleEvent->evt.gatts_evt.conn_handle, NULL, 0, 0); - SuccessOrExit(err); - break; - - case BLE_GATTS_EVT_TIMEOUT: - ChipLogProgress(DeviceLayer, "BLE GATT Server timeout (con %" PRIu16 ")", bleEvent->evt.gatts_evt.conn_handle); - err = sd_ble_gap_disconnect(bleEvent->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); - SuccessOrExit(err); - break; - - case BLE_GATTS_EVT_WRITE: - // Handle the event if it is a write to the CHIPoBLE TX CCCD attribute. Otherwise simply - // ignore it. - if (bleEvent->evt.gatts_evt.params.write.handle == mCHIPoBLECharHandle_TX.cccd_handle) - { - err = HandleTXCharCCCDWrite(event); - SuccessOrExit(err); - } - break; - - case BLE_GATTS_EVT_HVC: - err = HandleTXComplete(event); - SuccessOrExit(err); - break; - - default: - break; - } - -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); - sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } -} - -void BLEManagerImpl::SoftDeviceBLEEventCallback(const ble_evt_t * bleEvent, void * context) -{ - ChipDeviceEvent event; - - // NB: When NRF_SDH_DISPATCH_MODEL_INTERRUPT is enabled (the typical case), this method runs - // in interrupt context. - - // If the event is a write event for the CHIPoBLE RX characteristic value... - if (bleEvent->header.evt_id == BLE_GATTS_EVT_WRITE && - bleEvent->evt.gatts_evt.params.write.handle == sInstance.mCHIPoBLECharHandle_RX.value_handle) - { - PacketBuffer * buf; - const uint16_t valLen = bleEvent->evt.gatts_evt.params.write.len; - // TODO: This cast does not obviously looks safe. - // https://github.com/project-chip/connectedhomeip/issues/2571 - const uint16_t minBufSize = static_cast(CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE + valLen); - - // Attempt to allocate a packet buffer with enough space to hold the characteristic value. - // Note that we must use pbuf_alloc() directly, as PacketBuffer::New() is not interrupt-safe. - buf = (PacketBuffer *) (pbuf_alloc(PBUF_RAW, minBufSize, PBUF_POOL)); - - // If successful... - if (buf != NULL) - { - // Copy the characteristic value into the packet buffer. - memcpy(buf->Start(), bleEvent->evt.gatts_evt.params.write.data, valLen); - buf->SetDataLength(valLen); - - // Arrange to post a CHIPoBLERXWriteEvent event to the CHIP queue. - event.Type = DeviceEventType::kCHIPoBLERXCharWriteEvent; - event.Platform.RXCharWriteEvent.ConId = bleEvent->evt.gatts_evt.conn_handle; - event.Platform.RXCharWriteEvent.WriteArgs = bleEvent->evt.gatts_evt.params.write; - event.Platform.RXCharWriteEvent.Data = buf; - } - - // If we failed to allocate a buffer, post a kCHIPoBLEOutOfBuffersEvent event. - else - { - event.Type = DeviceEventType::kCHIPoBLEOutOfBuffersEvent; - } - } - - else - { - // Ignore any events that are larger than a particular size. - // - // With the exception of GATT write events to the CHIPoBLE RX characteristic, which are handled above, - // all BLE events that CHIP is interested are of a limited size, roughly equal to sizeof(ble_evt_t) - // plus a couple of bytes of payload data. Any event that is larger than this size and not handled - // above must represent an event related to some *other* user of the BLE SoftDevice and therefore - // can be safely ignored by CHIP. - VerifyOrExit(bleEvent->header.evt_len <= sizeof(event.Platform.SoftDeviceBLEEvent), /**/); - - // Ignore any write event for anything *other* than the CHIPoBLE TX CCCD value. - VerifyOrExit(bleEvent->header.evt_id != BLE_GATTS_EVT_WRITE || - bleEvent->evt.gatts_evt.params.write.handle == sInstance.mCHIPoBLECharHandle_TX.cccd_handle, - /**/); - - // Arrange to post a SoftDeviceBLEEvent containing a copy of the BLE event. - event.Type = DeviceEventType::kSoftDeviceBLEEvent; - memcpy(&event.Platform.SoftDeviceBLEEvent.EventData, bleEvent, bleEvent->header.evt_len); - } - - // Post the event to the CHIP queue. -#if (NRF_SDH_DISPATCH_MODEL == NRF_SDH_DISPATCH_MODEL_INTERRUPT) - BaseType_t yieldRequired; - PlatformMgrImpl().PostEventFromISR(&event, yieldRequired); - portYIELD_FROM_ISR(yieldRequired); -#else - PlatformMgrImpl().PostEvent(&event); -#endif - -exit: - return; -} - -CHIP_ERROR BLEManagerImpl::HandleGAPConnect(const ChipDeviceEvent * event) -{ - const ble_gap_evt_t * gapEvent = &event->Platform.SoftDeviceBLEEvent.EventData.evt.gap_evt; - - ChipLogProgress(DeviceLayer, "BLE GAP connection established (con %" PRIu16 ")", gapEvent->conn_handle); - - // Track the number of active GAP connections. - mNumGAPCons++; - - // The SoftDevice automatically disables advertising whenever a connection is established. - // So record that the SoftDevice state needs to be refreshed. If advertising needs to be - // re-enabled, this will be handled in DriveBLEState() the next time it runs. - SetFlag(mFlags, kFlag_AdvertisingRefreshNeeded); - - // Schedule DriveBLEState() to run. - PlatformMgr().ScheduleWork(DriveBLEState, 0); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(const ChipDeviceEvent * event) -{ - const ble_gap_evt_t * gapEvent = &event->Platform.SoftDeviceBLEEvent.EventData.evt.gap_evt; - - ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (con %" PRIu16 ", reason 0x%02" PRIx8 ")", gapEvent->conn_handle, - gapEvent->params.disconnected.reason); - - // Update the number of GAP connections. - if (mNumGAPCons > 0) - { - mNumGAPCons--; - } - - // If indications were enabled for this connection, record that they are now disabled and - // notify the BLE Layer of a disconnect. - if (UnsetSubscribed(gapEvent->conn_handle)) - { - CHIP_ERROR disconReason; - switch (gapEvent->params.disconnected.reason) - { - case BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION: - disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; - break; - case BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION: - disconReason = BLE_ERROR_APP_CLOSED_CONNECTION; - break; - default: - disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; - break; - } - HandleConnectionError(gapEvent->conn_handle, disconReason); - } - - // Force a reconfiguration of advertising in case we switched to non-connectable mode when - // the BLE connection was established. - SetFlag(mFlags, kFlag_AdvertisingRefreshNeeded); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR BLEManagerImpl::HandleRXCharWrite(const ChipDeviceEvent * event) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - PacketBuffer * buf = event->Platform.RXCharWriteEvent.Data; - - // Only allow write requests or write commands. - VerifyOrExit((event->Platform.RXCharWriteEvent.WriteArgs.op == BLE_GATTS_OP_WRITE_REQ || - event->Platform.RXCharWriteEvent.WriteArgs.op == BLE_GATTS_OP_WRITE_CMD), - err = CHIP_ERROR_INVALID_ARGUMENT); - - // NB: The initial write to the RX characteristic happens *before* the client enables - // indications on the TX characteristic. - - ChipLogDetail(DeviceLayer, "Write request/command received for CHIPoBLE RX characteristic (con %" PRIu16 ", len %" PRIu16 ")", - event->Platform.RXCharWriteEvent.ConId, buf->DataLength()); - - // Pass the data to the BLEEndPoint - HandleWriteReceived(event->Platform.RXCharWriteEvent.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, buf); - buf = NULL; - -exit: - PacketBuffer::Free(buf); - return err; -} - -CHIP_ERROR BLEManagerImpl::HandleTXCharCCCDWrite(const ChipDeviceEvent * event) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - const ble_gatts_evt_t * gattsEvent = &event->Platform.SoftDeviceBLEEvent.EventData.evt.gatts_evt; - bool indicationsEnabled; - enum - { - // Per the BLE GATT spec... - kCCCDBit_NotificationsEnabled = 0x0001, - kCCCDBit_IndicationsEnabled = 0x0002, - }; - - // Only allow write requests or write commands. - VerifyOrExit((gattsEvent->params.write.op == BLE_GATTS_OP_WRITE_REQ || gattsEvent->params.write.op == BLE_GATTS_OP_WRITE_CMD), - err = CHIP_ERROR_INVALID_ARGUMENT); - - ChipLogDetail(DeviceLayer, - "Write request/command received for CHIPoBLE TX CCCD characteristic (con %" PRIu16 ", len %" PRIu16 ")", - gattsEvent->conn_handle, gattsEvent->params.write.len); - - // Ignore the write request if the value is 0 length. - VerifyOrExit(gattsEvent->params.write.len > 0, /**/); - - ChipLogDetail(DeviceLayer, "CCCD value: 0x%04" PRIx16, - (((uint16_t) gattsEvent->params.write.data[1]) << 8) | gattsEvent->params.write.data[0]); - - // Determine if the client is enabling or disabling indications. - indicationsEnabled = ((gattsEvent->params.write.data[0] & kCCCDBit_IndicationsEnabled) != 0); - - // If the client has requested to enabled indications... - if (indicationsEnabled) - { - // If indications are not already enabled for the connection... - if (!IsSubscribed(gattsEvent->conn_handle)) - { - // Record that indications have been enabled for this connection. If this fails because - // there are too many CHIPoBLE connections, simply ignore client's attempt to subscribe. - err = SetSubscribed(gattsEvent->conn_handle); - VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); - SuccessOrExit(err); - - // Alert the BLE layer that CHIPoBLE "subscribe" has been received. - HandleSubscribeReceived(gattsEvent->conn_handle, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); - -#if CHIP_PROGRESS_LOGGING - { - uint16_t gattMTU; - uint8_t packetDataLen; - - gattMTU = nrf_ble_gatt_eff_mtu_get(&GATTModule, gattsEvent->conn_handle); - nrf_ble_gatt_data_length_get(&GATTModule, gattsEvent->conn_handle, &packetDataLen); - ChipLogProgress(DeviceLayer, - "CHIPoBLE connection established (con %" PRIu16 ", packet data len %" PRIu8 ", GATT MTU %" PRIu16 - ")", - gattsEvent->conn_handle, packetDataLen, gattMTU); - } -#endif // CHIP_PROGRESS_LOGGING - - // Post a CHIPoBLEConnectionEstablished event to the DeviceLayer and the application. - { - ChipDeviceEvent conEstEvent; - conEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; - PlatformMgr().PostEvent(&conEstEvent); - } - } - } - - else - { - // If indications had previously been enabled for this connection, record that they are no longer - // enabled and inform the BLE layer that the client has "unsubscribed" the connection. - if (UnsetSubscribed(gattsEvent->conn_handle)) - { - HandleUnsubscribeReceived(gattsEvent->conn_handle, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); - } - } - -exit: - return err; -} - -CHIP_ERROR BLEManagerImpl::HandleTXComplete(const ChipDeviceEvent * event) -{ - const ble_gatts_evt_t * gattsEvent = &event->Platform.SoftDeviceBLEEvent.EventData.evt.gatts_evt; - - ChipLogDetail(DeviceLayer, "Confirm received for CHIPoBLE TX characteristic indication (con %" PRIu16 ")", - gattsEvent->conn_handle); - - // Signal the BLE Layer that the outstanding indication is complete. - HandleIndicationConfirmation(gattsEvent->conn_handle, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId) -{ - uint16_t freeIndex = kMaxConnections; - - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] == conId) - { - return CHIP_NO_ERROR; - } - else if (mSubscribedConIds[i] == BLE_CONNECTION_UNINITIALIZED && i < freeIndex) - { - freeIndex = i; - } - } - - if (freeIndex < kMaxConnections) - { - mSubscribedConIds[freeIndex] = conId; - return CHIP_NO_ERROR; - } - else - { - return CHIP_ERROR_NO_MEMORY; - } -} - -bool BLEManagerImpl::UnsetSubscribed(uint16_t conId) -{ - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] == conId) - { - mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; - return true; - } - } - return false; -} - -bool BLEManagerImpl::IsSubscribed(uint16_t conId) -{ - if (conId != BLE_CONNECTION_UNINITIALIZED) - { - for (uint16_t i = 0; i < kMaxConnections; i++) - { - if (mSubscribedConIds[i] == conId) - { - return true; - } - } - } - return false; -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip - -#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/nRF5/BLEManagerImpl.h b/src/platform/nRF5/BLEManagerImpl.h deleted file mode 100644 index bafedbeaa6bae0..00000000000000 --- a/src/platform/nRF5/BLEManagerImpl.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the BLEManager singleton object - * for the nRF5 platforms. - */ - -#pragma once - -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - -#include "nrf_ble_gatt.h" -#include "nrf_sdh_ble.h" - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -using namespace chip::Ble; - -/** - * Concrete implementation of the NetworkProvisioningServer singleton object for the nRF5 platforms. - */ -class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePlatformDelegate, private BleApplicationDelegate -{ - // Allow the BLEManager interface class to delegate method calls to - // the implementation methods provided by this class. - friend BLEManager; - -public: - // ===== Platform-specific members available for use by the application. - - uint8_t GetAdvertisingHandle(void); - void SetAdvertisingHandle(uint8_t handle); - -private: - // ===== Members that implement the BLEManager internal interface. - - CHIP_ERROR _Init(void); - CHIP_ERROR _PlatformInit(void); - CHIPoBLEServiceMode _GetCHIPoBLEServiceMode(void); - CHIP_ERROR _SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val); - bool _IsAdvertisingEnabled(void); - CHIP_ERROR _SetAdvertisingEnabled(bool val); - bool _IsFastAdvertisingEnabled(void); - CHIP_ERROR _SetFastAdvertisingEnabled(bool val); - bool _IsAdvertising(void); - CHIP_ERROR _GetDeviceName(char * buf, size_t bufSize); - CHIP_ERROR _SetDeviceName(const char * deviceName); - uint16_t _NumConnections(void); - void _OnPlatformEvent(const ChipDeviceEvent * event); - BleLayer * _GetBleLayer(void); - - // ===== Members that implement virtual methods on BlePlatformDelegate. - - bool SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, - const Ble::ChipBleUUID * charId) override; - bool UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, - const Ble::ChipBleUUID * charId) override; - bool CloseConnection(BLE_CONNECTION_OBJECT conId) override; - uint16_t GetMTU(BLE_CONNECTION_OBJECT conId) const override; - bool SendIndication(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, - System::PacketBuffer * pBuf) override; - bool SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, - System::PacketBuffer * pBuf) override; - bool SendReadRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, - System::PacketBuffer * pBuf) override; - bool SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, const Ble::ChipBleUUID * svcId, - const Ble::ChipBleUUID * charId) override; - - // ===== Members that implement virtual methods on BleApplicationDelegate. - - void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) override; - - // ===== Members for internal use by the following friends. - - friend BLEManager & BLEMgr(void); - friend BLEManagerImpl & BLEMgrImpl(void); - - static BLEManagerImpl sInstance; - - // ===== Private members reserved for use by this class only. - - enum - { - kFlag_AsyncInitCompleted = 0x0001, /**< One-time asynchronous initialization actions have been performed. */ - kFlag_AdvertisingEnabled = 0x0002, /**< The application has enabled CHIPoBLE advertising. */ - kFlag_FastAdvertisingEnabled = 0x0004, /**< The application has enabled fast advertising. */ - kFlag_Advertising = 0x0008, /**< The system is currently CHIPoBLE advertising. */ - kFlag_AdvertisingRefreshNeeded = - 0x0010, /**< The advertising state/configuration has changed, but the SoftDevice has yet to be updated. */ - }; - - enum - { - kMaxConnections = MIN(BLE_LAYER_NUM_BLE_ENDPOINTS, NRF_SDH_BLE_PERIPHERAL_LINK_COUNT), - kMaxDeviceNameLength = 20, // TODO: right-size this - kMaxAdvertismentDataSetSize = 31 // TODO: verify this - }; - - ble_gatts_char_handles_t mCHIPoBLECharHandle_RX; - ble_gatts_char_handles_t mCHIPoBLECharHandle_TX; - CHIPoBLEServiceMode mServiceMode; - uint16_t mFlags; - uint16_t mNumGAPCons; - uint16_t mSubscribedConIds[kMaxConnections]; - uint8_t mAdvHandle; - uint8_t mAdvDataBuf[kMaxAdvertismentDataSetSize]; - uint8_t mScanRespDataBuf[kMaxAdvertismentDataSetSize]; - - void DriveBLEState(void); - CHIP_ERROR ConfigureAdvertising(void); - CHIP_ERROR EncodeAdvertisingData(ble_gap_adv_data_t & gapAdvData); - CHIP_ERROR StartAdvertising(void); - CHIP_ERROR StopAdvertising(void); - void HandleSoftDeviceBLEEvent(const ChipDeviceEvent * event); - CHIP_ERROR HandleGAPConnect(const ChipDeviceEvent * event); - CHIP_ERROR HandleGAPDisconnect(const ChipDeviceEvent * event); - CHIP_ERROR HandleRXCharWrite(const ChipDeviceEvent * event); - CHIP_ERROR HandleTXCharCCCDWrite(const ChipDeviceEvent * event); - CHIP_ERROR HandleTXComplete(const ChipDeviceEvent * event); - CHIP_ERROR SetSubscribed(uint16_t conId); - bool UnsetSubscribed(uint16_t conId); - bool IsSubscribed(uint16_t conId); - - static void DriveBLEState(intptr_t arg); - static void SoftDeviceBLEEventCallback(const ble_evt_t * bleEvent, void * context); -}; - -/** - * Returns a reference to the public interface of the BLEManager singleton object. - * - * Internal components should use this to access features of the BLEManager object - * that are common to all platforms. - */ -inline BLEManager & BLEMgr(void) -{ - return BLEManagerImpl::sInstance; -} - -/** - * Returns the platform-specific implementation of the BLEManager singleton object. - * - * Internal components can use this to gain access to features of the BLEManager - * that are specific to the NRF5* platforms. - */ -inline BLEManagerImpl & BLEMgrImpl(void) -{ - return BLEManagerImpl::sInstance; -} - -inline uint8_t BLEManagerImpl::GetAdvertisingHandle(void) -{ - return mAdvHandle; -} - -inline void BLEManagerImpl::SetAdvertisingHandle(uint8_t handle) -{ - mAdvHandle = handle; -} - -inline BleLayer * BLEManagerImpl::_GetBleLayer() -{ - return this; -} - -inline BLEManager::CHIPoBLEServiceMode BLEManagerImpl::_GetCHIPoBLEServiceMode(void) -{ - return mServiceMode; -} - -inline bool BLEManagerImpl::_IsAdvertisingEnabled(void) -{ - return GetFlag(mFlags, kFlag_AdvertisingEnabled); -} - -inline bool BLEManagerImpl::_IsFastAdvertisingEnabled(void) -{ - return GetFlag(mFlags, kFlag_FastAdvertisingEnabled); -} - -inline bool BLEManagerImpl::_IsAdvertising(void) -{ - return GetFlag(mFlags, kFlag_Advertising); -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip - -#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/nRF5/BlePlatformConfig.h b/src/platform/nRF5/BlePlatformConfig.h deleted file mode 100644 index 9d0385ea6f12bf..00000000000000 --- a/src/platform/nRF5/BlePlatformConfig.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Platform-specific configuration overrides for the CHIP BLE - * Layer on nRF52 platforms using the Nordic nRF5 SDK. - * - */ - -#pragma once - -#include - -// ==================== Platform Adaptations ==================== - -#define BLE_CONNECTION_OBJECT uint16_t -#define BLE_CONNECTION_UNINITIALIZED ((uint16_t) BLE_CONN_HANDLE_INVALID) -#define BLE_MAX_RECEIVE_WINDOW_SIZE 5 - -#define BLE_CONFIG_ERROR_TYPE ret_code_t -#define BLE_CONFIG_NO_ERROR NRF_SUCCESS -#define BLE_CONFIG_ERROR_MIN 6000000 -#define BLE_CONFIG_ERROR_MAX 6000999 -#define _BLE_CONFIG_ERROR(e) (BLE_CONFIG_ERROR_MIN + (e)) - -// ========== Platform-specific Configuration Overrides ========= - -/* none so far */ diff --git a/src/platform/nRF5/CHIPDevicePlatformConfig.h b/src/platform/nRF5/CHIPDevicePlatformConfig.h deleted file mode 100644 index 906b8ae05aaa86..00000000000000 --- a/src/platform/nRF5/CHIPDevicePlatformConfig.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Platform-specific configuration overrides for the chip Device Layer - * on nRF52 platforms using the Nordic nRF5 SDK. - */ - -#pragma once - -// ==================== Platform Adaptations ==================== - -#define CHIP_DEVICE_CONFIG_NRF5_ERROR_MIN 1 -#define CHIP_DEVICE_CONFIG_NRF5_ERROR_MAX 1000000 - -#define CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MIN 10000000 -#define CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MAX 10000999 - -#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0 -#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 - -#if CHIP_ENABLE_OPENTHREAD -#define CHIP_DEVICE_CONFIG_ENABLE_THREAD 1 -#endif - -#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 - -#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0 - -#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_CRIT_EIDC_KEY 2 -#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_PROD_EIDC_KEY 3 -#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_INFO_EIDC_KEY 4 -#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_DEBUG_EIDC_KEY 5 - -// ========== Platform-specific Configuration ========= - -// These are configuration options that are unique to the nRF52 platform. -// These can be overridden by the application as needed. - -/** - * @def CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY - * - * The priority of the SoftDevice observer event handler registered by the - * Openchip BleLayer. - */ -#ifndef CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY -#define CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY 3 -#endif // CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY - -/** - * @def CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG - * - * The SoftDevice BLE connection configuration tag used by the Openchip - * BleLayer. - */ -#ifndef CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG -#define CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG 1 -#endif // CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG - -// ========== Platform-specific Configuration Overrides ========= - -#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE -#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE 4096 -#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE - -#ifndef CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE -#define CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE 4096 -#endif // CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE - -#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY 0 -#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY 0 -#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY_FULL 0 -#define CHIP_DEVICE_CONFIG_LOG_PROVISIONING_HASH 0 diff --git a/src/platform/nRF5/CHIPDevicePlatformEvent.h b/src/platform/nRF5/CHIPDevicePlatformEvent.h deleted file mode 100644 index 8fb8dbd8d5398a..00000000000000 --- a/src/platform/nRF5/CHIPDevicePlatformEvent.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Defines platform-specific event types and data for the chip - * Device Layer on nRF52 platforms using the Nordic nRF5 SDK. - */ - -#pragma once - -#include - -#include "ble.h" -#include "nrf_ble_gatt.h" - -namespace chip { -namespace System { -class PacketBuffer; -} -} // namespace chip - -namespace chip { -namespace DeviceLayer { - -namespace DeviceEventType { - -/** - * Enumerates nRF52 platform-specific event types that are visible to the application. - */ -enum PublicPlatformSpecificEventTypes -{ - /* None currently defined */ -}; - -/** - * Enumerates nRF52 platform-specific event types that are internal to the chip Device Layer. - */ -enum InternalPlatformSpecificEventTypes -{ - kSoftDeviceBLEEvent = kRange_InternalPlatformSpecific, - kCHIPoBLERXCharWriteEvent, - kCHIPoBLEOutOfBuffersEvent, -}; - -} // namespace DeviceEventType - -/** - * Represents platform-specific event information for Nordic nRF52 platforms. - */ -struct ChipDevicePlatformEvent final -{ - union - { - struct - { - ble_evt_t EventData; - uint8_t PayloadPadding[2]; - } SoftDeviceBLEEvent; - struct - { - uint16_t ConId; - ble_gatts_evt_write_t WriteArgs; - ::chip::System::PacketBuffer * Data; - } RXCharWriteEvent; - }; -}; - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/CHIPPlatformConfig.h b/src/platform/nRF5/CHIPPlatformConfig.h deleted file mode 100644 index f50cba92e76821..00000000000000 --- a/src/platform/nRF5/CHIPPlatformConfig.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Platform-specific configuration overrides for CHIP on - * Nordic nRF52 platforms. - */ - -#pragma once - -#include "sdk_config.h" -#include "sdk_errors.h" - -// ==================== General Platform Adaptations ==================== - -#define CHIP_CONFIG_ERROR_TYPE ret_code_t -#define CHIP_CONFIG_NO_ERROR NRF_SUCCESS -#define CHIP_CONFIG_ERROR_MIN 4000000 -#define CHIP_CONFIG_ERROR_MAX 4000999 - -#define ASN1_CONFIG_ERROR_TYPE ret_code_t -#define ASN1_CONFIG_NO_ERROR NRF_SUCCESS -#define ASN1_CONFIG_ERROR_MIN 5000000 -#define ASN1_CONFIG_ERROR_MAX 5000999 - -#define ChipDie() abort() - -#define CHIP_CONFIG_PERSISTED_STORAGE_KEY_TYPE uint16_t -#define CHIP_CONFIG_PERSISTED_STORAGE_ENC_MSG_CNTR_ID 1 -#define CHIP_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH 2 - -#define CHIP_CONFIG_TIME_ENABLE_CLIENT 1 -#define CHIP_CONFIG_TIME_ENABLE_SERVER 0 - -// ==================== Security Adaptations ==================== - -#define CHIP_CONFIG_USE_OPENSSL_ECC 0 -#define CHIP_CONFIG_USE_MICRO_ECC 0 - -#define CHIP_CONFIG_HASH_IMPLEMENTATION_OPENSSL 0 -#define CHIP_CONFIG_HASH_IMPLEMENTATION_MINCRYPT 1 -#define CHIP_CONFIG_HASH_IMPLEMENTATION_MBEDTLS 0 -#define CHIP_CONFIG_HASH_IMPLEMENTATION_PLATFORM 0 - -#define CHIP_CONFIG_AES_IMPLEMENTATION_OPENSSL 0 -#define CHIP_CONFIG_AES_IMPLEMENTATION_AESNI 0 -#define CHIP_CONFIG_AES_IMPLEMENTATION_MBEDTLS 1 -#define CHIP_CONFIG_AES_IMPLEMENTATION_PLATFORM 0 - -#define CHIP_CONFIG_RNG_IMPLEMENTATION_OPENSSL 0 -#define CHIP_CONFIG_RNG_IMPLEMENTATION_CHIPDRBG 1 -#define CHIP_CONFIG_RNG_IMPLEMENTATION_PLATFORM 0 - -#define CHIP_CONFIG_ENABLE_PASE_INITIATOR 0 -#define CHIP_CONFIG_ENABLE_PASE_RESPONDER 1 -#define CHIP_CONFIG_ENABLE_CASE_INITIATOR 1 - -#define CHIP_CONFIG_SUPPORT_PASE_CONFIG0 0 -#define CHIP_CONFIG_SUPPORT_PASE_CONFIG1 0 -#define CHIP_CONFIG_SUPPORT_PASE_CONFIG2 0 -#define CHIP_CONFIG_SUPPORT_PASE_CONFIG3 0 -#define CHIP_CONFIG_SUPPORT_PASE_CONFIG4 1 - -#define CHIP_CONFIG_ENABLE_KEY_EXPORT_INITIATOR 0 - -#define CHIP_CONFIG_ENABLE_PROVISIONING_BUNDLE_SUPPORT 0 - -// ==================== General Configuration Overrides ==================== - -#ifndef CHIP_CONFIG_MAX_PEER_NODES -#define CHIP_CONFIG_MAX_PEER_NODES 16 -#endif // CHIP_CONFIG_MAX_PEER_NODES - -#ifndef CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS -#define CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS 16 -#endif // CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS - -#ifndef CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS -#define CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS 8 -#endif // CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS - -#ifndef CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT -#define CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT 6 -#endif // CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT - -#ifndef CHIP_LOG_FILTERING -#define CHIP_LOG_FILTERING 0 -#endif // CHIP_LOG_FILTERING - -#ifndef CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS -#define CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS 1 -#endif // CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS - -// ==================== Security Configuration Overrides ==================== - -#ifndef CHIP_CONFIG_MAX_APPLICATION_GROUPS -#define CHIP_CONFIG_MAX_APPLICATION_GROUPS 4 -#endif // CHIP_CONFIG_MAX_APPLICATION_GROUPS - -#ifndef CHIP_CONFIG_DEBUG_CERT_VALIDATION -#define CHIP_CONFIG_DEBUG_CERT_VALIDATION 0 -#endif // CHIP_CONFIG_DEBUG_CERT_VALIDATION - -#ifndef CHIP_CONFIG_ENABLE_CASE_RESPONDER -#define CHIP_CONFIG_ENABLE_CASE_RESPONDER 1 -#endif // CHIP_CONFIG_ENABLE_CASE_RESPONDER diff --git a/src/platform/nRF5/ConfigurationManagerImpl.cpp b/src/platform/nRF5/ConfigurationManagerImpl.cpp deleted file mode 100644 index 29a1b378353e63..00000000000000 --- a/src/platform/nRF5/ConfigurationManagerImpl.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides the implementation of the Device Layer ConfigurationManager object - * for nRF52 platforms using the Nordic nRF5 SDK. - */ -/* this file behaves like a config.h, comes first */ -#include - -#include -#include - -#include -#include - -#if CHIP_DEVICE_CONFIG_ENABLE_FACTORY_PROVISIONING -#include -#endif // CHIP_DEVICE_CONFIG_ENABLE_FACTORY_PROVISIONING - -#include -#include - -namespace chip { -namespace DeviceLayer { - -using namespace ::chip::DeviceLayer::Internal; - -// TODO: Define a Singleton instance of CHIP Group Key Store here (#1204) - -/** Singleton instance of the ConfigurationManager implementation object. - */ -ConfigurationManagerImpl ConfigurationManagerImpl::sInstance; - -CHIP_ERROR ConfigurationManagerImpl::_Init() -{ - CHIP_ERROR err; - bool failSafeArmed; - - // Initialize the generic implementation base class. - err = Internal::GenericConfigurationManagerImpl::_Init(); - SuccessOrExit(err); - - // TODO: Initialize the global GroupKeyStore object here (#1204) - -#if CHIP_DEVICE_CONFIG_ENABLE_FACTORY_PROVISIONING - - { - FactoryProvisioning factoryProv; - uint8_t * const kDeviceRAMStart = (uint8_t *) 0x20000000; - uint8_t * const kDeviceRAMEnd = kDeviceRAMStart + (NRF_FICR->INFO.RAM * 1024) - 1; - - // Scan device RAM for injected provisioning data and save to persistent storage if found. - err = factoryProv.ProvisionDeviceFromRAM(kDeviceRAMStart, kDeviceRAMEnd); - SuccessOrExit(err); - } - -#endif // CHIP_DEVICE_CONFIG_ENABLE_FACTORY_PROVISIONING - - // If the fail-safe was armed when the device last shutdown, initiate a factory reset. - if (_GetFailSafeArmed(failSafeArmed) == CHIP_NO_ERROR && failSafeArmed) - { - ChipLogProgress(DeviceLayer, "Detected fail-safe armed on reboot; initiating factory reset"); - _InitiateFactoryReset(); - } - err = CHIP_NO_ERROR; - -exit: - return err; -} - -bool ConfigurationManagerImpl::_CanFactoryReset() -{ - // TODO: query the application to determine if factory reset is allowed. - return true; -} - -void ConfigurationManagerImpl::_InitiateFactoryReset() -{ - PlatformMgr().ScheduleWork(DoFactoryReset); -} - -CHIP_ERROR ConfigurationManagerImpl::_ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key persistedStorageKey, - uint32_t & value) -{ - CHIP_ERROR err; - uintmax_t recordKey = persistedStorageKey + kPersistedCounterRecordKeyBase; - - VerifyOrExit(recordKey <= kPersistedCounterRecordKeyMax, err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); - static_assert(kPersistedCounterRecordKeyMax <= UINT16_MAX, "Key won't fit in uint16_t"); - - err = ReadConfigValue(NRF5ConfigKey(NRF5Config::kFileId_ChipCounter, static_cast(recordKey)), value); - if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) - { - err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; - } - SuccessOrExit(err); - -exit: - return err; -} - -CHIP_ERROR ConfigurationManagerImpl::_WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key persistedStorageKey, - uint32_t value) -{ - CHIP_ERROR err; - uintmax_t recordKey = persistedStorageKey + kPersistedCounterRecordKeyBase; - - VerifyOrExit(recordKey <= kPersistedCounterRecordKeyMax, err = CHIP_ERROR_INVALID_ARGUMENT); - static_assert(kPersistedCounterRecordKeyMax <= UINT16_MAX, "Key won't fit in uint16_t"); - - err = WriteConfigValue(NRF5ConfigKey(NRF5Config::kFileId_ChipCounter, static_cast(recordKey)), value); - SuccessOrExit(err); - -exit: - return err; -} - -void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) -{ - CHIP_ERROR err; - - ChipLogProgress(DeviceLayer, "Performing factory reset"); - - err = FactoryResetConfig(); - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "FactoryResetConfig() failed: %s", ErrorStr(err)); - } - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - - ThreadStackMgr().ErasePersistentInfo(); - -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD - - // Restart the system. - ChipLogProgress(DeviceLayer, "System restarting"); - NVIC_SystemReset(); -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/ConfigurationManagerImpl.h b/src/platform/nRF5/ConfigurationManagerImpl.h deleted file mode 100644 index 4ddd962b1daae6..00000000000000 --- a/src/platform/nRF5/ConfigurationManagerImpl.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the ConfigurationManager object - * for nRF52 platforms using the Nordic nRF5 SDK. - */ - -#pragma once - -#include -#include - -namespace chip { -namespace DeviceLayer { - -/** - * Concrete implementation of the ConfigurationManager singleton object for the nRF52 platform. - */ -class ConfigurationManagerImpl final : public ConfigurationManager, - public Internal::GenericConfigurationManagerImpl, - private Internal::NRF5Config -{ - // Allow the ConfigurationManager interface class to delegate method calls to - // the implementation methods provided by this class. - friend class ConfigurationManager; - - // Allow the GenericConfigurationManagerImpl base class to access helper methods and types - // defined on this class. -#ifndef DOXYGEN_SHOULD_SKIP_THIS - friend class Internal::GenericConfigurationManagerImpl; -#endif - -private: - // ===== Members that implement the ConfigurationManager public interface. - - CHIP_ERROR _Init(void); - CHIP_ERROR _GetPrimaryWiFiMACAddress(uint8_t * buf); - bool _CanFactoryReset(void); - void _InitiateFactoryReset(void); - CHIP_ERROR _ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value); - CHIP_ERROR _WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value); - - // NOTE: Other public interface methods are implemented by GenericConfigurationManagerImpl<>. - - // ===== Members for internal use by the following friends. - - friend ConfigurationManager & ConfigurationMgr(void); - friend ConfigurationManagerImpl & ConfigurationMgrImpl(void); - - static ConfigurationManagerImpl sInstance; - - // ===== Private members reserved for use by this class only. - - static void DoFactoryReset(intptr_t arg); -}; - -/** - * Returns the public interface of the ConfigurationManager singleton object. - * - * chip applications should use this to access features of the ConfigurationManager object - * that are common to all platforms. - */ -inline ConfigurationManager & ConfigurationMgr(void) -{ - return ConfigurationManagerImpl::sInstance; -} - -/** - * Returns the platform-specific implementation of the ConfigurationManager singleton object. - * - * chip applications can use this to gain access to features of the ConfigurationManager - * that are specific to the ESP32 platform. - */ -inline ConfigurationManagerImpl & ConfigurationMgrImpl(void) -{ - return ConfigurationManagerImpl::sInstance; -} - -inline CHIP_ERROR ConfigurationManagerImpl::_GetPrimaryWiFiMACAddress(uint8_t * buf) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/ConnectivityManagerImpl.cpp b/src/platform/nRF5/ConnectivityManagerImpl.cpp deleted file mode 100644 index 668eff80900aca..00000000000000 --- a/src/platform/nRF5/ConnectivityManagerImpl.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* this file behaves like a config.h, comes first */ -#include - -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE -#include -#endif - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace ::chip; -using namespace ::chip::Inet; -using namespace ::chip::System; -using namespace ::chip::TLV; -using namespace ::chip::DeviceLayer::Internal; - -namespace chip { -namespace DeviceLayer { - -ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; - -CHIP_ERROR ConnectivityManagerImpl::_Init() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - // Initialize the generic base classes that require it. -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - GenericConnectivityManagerImpl_Thread::_Init(); -#endif - - SuccessOrExit(err); - -exit: - return err; -} - -void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) -{ - // Forward the event to the generic base classes as needed. -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - GenericConnectivityManagerImpl_Thread::_OnPlatformEvent(event); -#endif -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/ConnectivityManagerImpl.h b/src/platform/nRF5/ConnectivityManagerImpl.h deleted file mode 100644 index 1519b7248a973e..00000000000000 --- a/src/platform/nRF5/ConnectivityManagerImpl.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE -#include -#else -#include -#endif -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD -#include -#else -#include -#endif -#include - -namespace chip { -namespace Inet { -class IPAddress; -} // namespace Inet -} // namespace chip - -namespace chip { -namespace DeviceLayer { - -/** - * Concrete implementation of the ConnectivityManager singleton object for Nordic nRF52 platforms. - */ -class ConnectivityManagerImpl final : public ConnectivityManager, - public Internal::GenericConnectivityManagerImpl, -#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - public Internal::GenericConnectivityManagerImpl_BLE, -#else - public Internal::GenericConnectivityManagerImpl_NoBLE, -#endif -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - public Internal::GenericConnectivityManagerImpl_Thread, -#else - public Internal::GenericConnectivityManagerImpl_NoThread, -#endif - public Internal::GenericConnectivityManagerImpl_NoWiFi -{ - // Allow the ConnectivityManager interface class to delegate method calls to - // the implementation methods provided by this class. - friend class ConnectivityManager; - -private: - // ===== Members that implement the ConnectivityManager abstract interface. - - bool _HaveIPv4InternetConnectivity(void); - bool _HaveIPv6InternetConnectivity(void); - bool _HaveServiceConnectivity(void); - CHIP_ERROR _Init(void); - void _OnPlatformEvent(const ChipDeviceEvent * event); - - // ===== Members for internal use by the following friends. - - friend ConnectivityManager & ConnectivityMgr(void); - friend ConnectivityManagerImpl & ConnectivityMgrImpl(void); - - static ConnectivityManagerImpl sInstance; -}; - -inline bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity(void) -{ - return false; -} - -inline bool ConnectivityManagerImpl::_HaveIPv6InternetConnectivity(void) -{ - return false; -} - -inline bool ConnectivityManagerImpl::_HaveServiceConnectivity(void) -{ - return _HaveServiceConnectivityViaThread(); -} - -/** - * Returns the public interface of the ConnectivityManager singleton object. - * - * chip applications should use this to access features of the ConnectivityManager object - * that are common to all platforms. - */ -inline ConnectivityManager & ConnectivityMgr(void) -{ - return ConnectivityManagerImpl::sInstance; -} - -/** - * Returns the platform-specific implementation of the ConnectivityManager singleton object. - * - * chip applications can use this to gain access to features of the ConnectivityManager - * that are specific to the ESP32 platform. - */ -inline ConnectivityManagerImpl & ConnectivityMgrImpl(void) -{ - return ConnectivityManagerImpl::sInstance; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.cpp b/src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.cpp deleted file mode 100644 index 0575bcf4ef9bd2..00000000000000 --- a/src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.cpp +++ /dev/null @@ -1,44 +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. - */ - -#include "DeviceNetworkProvisioningDelegateImpl.h" - -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#endif - -namespace chip { -namespace DeviceLayer { - -CHIP_ERROR DeviceNetworkProvisioningDelegateImpl::_ProvisionThreadNetwork(DeviceLayer::Internal::DeviceNetworkInfo & threadData) -{ -#if CHIP_ENABLE_OPENTHREAD - CHIP_ERROR error = CHIP_NO_ERROR; - - SuccessOrExit(error = ThreadStackMgr().SetThreadEnabled(false)); - SuccessOrExit(error = ThreadStackMgr().SetThreadProvision(threadData)); - SuccessOrExit(error = ThreadStackMgr().SetThreadEnabled(true)); -exit: - return error; -#else - return CHIP_ERROR_NOT_IMPLEMENTED; -#endif // CHIP_ENABLE_OPENTHREAD -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.h b/src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.h deleted file mode 100644 index 05a642417934d4..00000000000000 --- a/src/platform/nRF5/DeviceNetworkProvisioningDelegateImpl.h +++ /dev/null @@ -1,43 +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. - */ - -#pragma once - -#include - -namespace chip { -namespace DeviceLayer { - -namespace Internal { - -template -class GenericDeviceNetworkProvisioningDelegateImpl; - -} // namespace Internal - -class DeviceNetworkProvisioningDelegateImpl final - : public Internal::GenericDeviceNetworkProvisioningDelegateImpl -{ - friend class GenericDeviceNetworkProvisioningDelegateImpl; - -private: - CHIP_ERROR _ProvisionWiFiNetwork(const char * ssid, const char * passwd) { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR _ProvisionThreadNetwork(DeviceLayer::Internal::DeviceNetworkInfo & threadData); -}; - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/Entropy.cpp b/src/platform/nRF5/Entropy.cpp deleted file mode 100644 index 7cad7014783df7..00000000000000 --- a/src/platform/nRF5/Entropy.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides implementations for the chip entropy sourcing functions - * on the Nordic nRF52 platforms. - */ - -// -// !!!TEMPORARY CODE!!! -// -// The following code is a temporary implementation of the CHIP Entropy APIs -// that has been specially designed to work around the lack of thread-safety in the -// Nordic port of OpenThread. -// -// In Nordic's OpenThread platform implementation, the code assumes it has exclusive -// access to the underlying entropy source. In a multi-threaded environment such as -// an CHIP application this precludes code running in other threads from directly -// sourcing entropy. -// -// To work around this, the code here acquires the OpenThread stack lock before interacting -// with the entropy source, effectively blocking all OpenThread activity until CHIP -// has acquired its entropy. Because the entropy is being fed into a DRBG, which then feeds -// the application, this should happen extremely rarely. -// -// Ultimately this code will be revised to use a new thread-safe entropy sourcing API -// provided by Nordic. -// - -#include -#include - -#if SOFTDEVICE_PRESENT -#include -#else -#include -#endif - -using namespace ::chip; - -#if !CHIP_CONFIG_RNG_IMPLEMENTATION_CHIPDRBG -#error "CHIP DRBG implementation must be enabled on nRF5 platforms" -#endif // !CHIP_CONFIG_RNG_IMPLEMENTATION_CHIPDRBG - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -/** - * Retrieve entropy from the underlying RNG source. - * - * This function is called by the CHIP DRBG to acquire entropy. - */ -int GetEntropy_nRF5(uint8_t * buf, size_t count) -{ - int res; - - VerifyOrDie(count <= UINT16_MAX); - - // If OpenThread is active, acquire the stack lock to prevent the - // OpenThread task from interacting with the entropy source. -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - if (ThreadStackManagerImpl::IsInitialized()) - { - ThreadStackMgr().LockThreadStack(); - } -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD - -#if SOFTDEVICE_PRESENT - - // Loop until we get the requested number of random bytes... - while (count > 0) - { - // Determine how many byte of entropy are currently available in - // the SoftDevice. - uint8_t avail; - sd_rand_application_bytes_available_get(&avail); - - // Only collect as many as we need. - if (avail > count) - { - avail = count; - } - - // Attempt to read the random bytes from the SoftDevice. Note that - // it could be that something in the SoftDevice as consumed the available - // entropy in which case NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES will be returned. - uint32_t err = sd_rand_application_vector_get(buf, avail); - if (err == NRF_SUCCESS) - { - buf += avail; - count -= avail; - } - else if (err != NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES) - { - res = 0; - break; - } - } - -#else // SOFTDEVICE_PRESENT - - // In the absence of the SoftDevice, call the OpenThread platform API for - // retrieving entropy. - otError otErr = otPlatRandomGetTrue(buf, (uint16_t) count); - res = (otErr == OT_ERROR_NONE); - -#endif // SOFTDEVICE_PRESENT - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - if (ThreadStackManagerImpl::IsInitialized()) - { - ThreadStackMgr().UnlockThreadStack(); - } -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD - - return res; -} - -CHIP_ERROR InitEntropy() -{ - CHIP_ERROR err; - - // Initialize the CHIP DRBG. - err = Platform::Security::InitSecureRandomDataSource(GetEntropy_nRF5, 64, NULL, 0); - SuccessOrExit(err); - - // Seed the standard rand() pseudo-random generator with data from the secure random source. - { - unsigned int seed; - err = Platform::Security::GetSecureRandomData((uint8_t *) &seed, sizeof(seed)); - SuccessOrExit(err); - srand(seed); - } - -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(Crypto, "InitEntropy() failed: 0x%08" PRIX32, err); - } - return err; -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/GroupKeyStoreImpl.cpp b/src/platform/nRF5/GroupKeyStoreImpl.cpp deleted file mode 100644 index 3ce3103e6c43f8..00000000000000 --- a/src/platform/nRF5/GroupKeyStoreImpl.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the CHIP GroupKeyStore interface - * for platforms based on the Nordic nRF5 SDK. - */ - -#include -#include - -#include "mem_manager.h" - -using namespace ::chip; -using namespace ::chip::Profiles::Security::AppKeys; - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -CHIP_ERROR GroupKeyStoreImpl::RetrieveGroupKey(uint32_t keyId, ChipGroupKey & key) -{ - CHIP_ERROR err; - - // Iterate over all the GroupKey records looking for a matching key... - err = ForEachRecord( - kGroupKeyFileId, kGroupKeyRecordKey, [keyId, &key](const fds_flash_record_t & rec, bool & deleteRec) -> CHIP_ERROR { - uint32_t curKeyId; - CHIP_ERROR err2 = CHIP_NO_ERROR; - - // Decode the CHIP key id for the current key. - err2 = DecodeGroupKeyId((const uint8_t *) rec.p_data, rec.p_header->length_words * kFDSWordSize, curKeyId); - SuccessOrExit(err2); - - // If it matches the key we're looking for... - if (curKeyId == keyId) - { - // Decode the associated key data. - err2 = DecodeGroupKey((const uint8_t *) rec.p_data, rec.p_header->length_words * kFDSWordSize, key); - SuccessOrExit(err2); - - // End the iteration by returning a CHIP_END_OF_INPUT result. - ExitNow(err2 = CHIP_END_OF_INPUT); - } - - exit: - return err2; - }); - - // If a matching key was found, return success. - if (err == CHIP_END_OF_INPUT) - { - err = CHIP_NO_ERROR; - } - - // If no match was found, return CHIP_ERROR_KEY_NOT_FOUND. - else if (err == CHIP_NO_ERROR) - { - err = CHIP_ERROR_KEY_NOT_FOUND; - } - SuccessOrExit(err); - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::StoreGroupKey(const ChipGroupKey & key) -{ - CHIP_ERROR err; - uint8_t * storedVal = NULL; - size_t storedValLen = FDSWords(kMaxEncodedKeySize) * kFDSWordSize; - - // Delete any existing group key with the same id. - err = DeleteGroupKey(key.KeyId); - SuccessOrExit(err); - - // Allocate a buffer to hold the encoded key. - storedVal = (uint8_t *) pvPortMalloc(storedValLen); - VerifyOrExit(storedVal != NULL, err = CHIP_ERROR_NO_MEMORY); - - // Encode the key for storage in an FDS record. - err = EncodeGroupKey(key, storedVal, storedValLen, storedValLen); - SuccessOrExit(err); - - // Add a GroupKey FDS record containing the encoded key. - { - FDSAsyncOp addOp(FDSAsyncOp::kAddRecord); - addOp.FileId = kGroupKeyFileId; - addOp.RecordKey = kGroupKeyRecordKey; - addOp.RecordData = storedVal; - addOp.RecordDataLengthWords = FDSWords(storedValLen); - err = DoAsyncFDSOp(addOp); - SuccessOrExit(err); - } - -#if CHIP_PROGRESS_LOGGING - - { - char extraKeyInfo[32]; - if (ChipKeyId::IsAppEpochKey(key.KeyId)) - { - snprintf(extraKeyInfo, sizeof(extraKeyInfo), ", start time %" PRId32, key.StartTime); - } - else if (ChipKeyId::IsAppGroupMasterKey(key.KeyId)) - { - snprintf(extraKeyInfo, sizeof(extraKeyInfo), ", global id 0x%08" PRIX32, key.GlobalId); - } - else - { - extraKeyInfo[0] = 0; - } - -#if CHIP_CONFIG_SECURITY_TEST_MODE - ChipLogProgress(SecurityManager, - "GroupKeyStore: storing key 0x%08" PRIX32 " (%s), len %" PRId8 ", data 0x%02" PRIX8 "...%s", key.KeyId, - ChipKeyId::DescribeKey(key.KeyId), key.KeyLen, key.Key[0], extraKeyInfo); -#else - ChipLogProgress(SecurityManager, "GroupKeyStore: storing key 0x%08" PRIX32 " (%s), len %" PRId8 "%s", key.KeyId, - ChipKeyId::DescribeKey(key.KeyId), key.KeyLen, extraKeyInfo); -#endif - } - -#endif // CHIP_PROGRESS_LOGGING - -exit: - if (storedVal != NULL) - { - ClearSecretData(storedVal, storedValLen); - vPortFree(storedVal); - } - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::DeleteGroupKey(uint32_t keyId) -{ - CHIP_ERROR err; - - // Iterate over all the GroupKey records looking for matching keys... - err = - ForEachRecord(kGroupKeyFileId, kGroupKeyRecordKey, [keyId](const fds_flash_record_t & rec, bool & deleteRec) -> CHIP_ERROR { - uint32_t curKeyId; - CHIP_ERROR err2; - - // Decode the CHIP key id for the current group key. - err2 = DecodeGroupKeyId((const uint8_t *) rec.p_data, rec.p_header->length_words * kFDSWordSize, curKeyId); - SuccessOrExit(err2); - - // If it matches the key looking for, arrange for the record to be deleted. - deleteRec = (curKeyId == keyId); - - if (deleteRec) - { - ChipLogProgress(DeviceLayer, "GroupKeyStore: deleting key 0x%08" PRIX32, curKeyId); - } - - exit: - return err2; - }); - SuccessOrExit(err); - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::DeleteGroupKeysOfAType(uint32_t keyType) -{ - CHIP_ERROR err; - - // Iterate over all the GroupKey records looking for matching keys... - err = ForEachRecord( - kGroupKeyFileId, kGroupKeyRecordKey, [keyType](const fds_flash_record_t & rec, bool & deleteRec) -> CHIP_ERROR { - uint32_t curKeyId; - CHIP_ERROR err2; - - // Decode the CHIP key id for the current group key. - err2 = DecodeGroupKeyId((const uint8_t *) rec.p_data, rec.p_header->length_words * kFDSWordSize, curKeyId); - SuccessOrExit(err2); - - // If the current key matches the type we're looking for, arrange for the - // record to be deleted. - deleteRec = (ChipKeyId::GetType(curKeyId) == keyType); - - if (deleteRec) - { - ChipLogProgress(DeviceLayer, "GroupKeyStore: deleting key 0x%08" PRIX32, curKeyId); - } - - exit: - return err2; - }); - SuccessOrExit(err); - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::EnumerateGroupKeys(uint32_t keyType, uint32_t * keyIds, uint8_t keyIdsArraySize, uint8_t & keyCount) -{ - CHIP_ERROR err; - - keyCount = 0; - - // Iterate over all the GroupKey records looking for keys of the specified type... - err = ForEachRecord( - kGroupKeyFileId, kGroupKeyRecordKey, - [keyType, keyIds, keyIdsArraySize, &keyCount](const fds_flash_record_t & rec, bool & deleteRec) -> CHIP_ERROR { - uint32_t curKeyId; - CHIP_ERROR err2 = CHIP_NO_ERROR; - - // Decode the CHIP key id for the current key. - err2 = DecodeGroupKeyId((const uint8_t *) rec.p_data, rec.p_header->length_words * kFDSWordSize, curKeyId); - SuccessOrExit(err2); - - // If the current key matches the type we're looking for, add it to the keyIds array. - if (keyType == ChipKeyId::kType_None || ChipKeyId::GetType(curKeyId) == keyType) - { - keyIds[keyCount++] = curKeyId; - - // Stop iterating if there's no more room in the keyIds array. - VerifyOrExit(keyCount < keyIdsArraySize, err2 = CHIP_ERROR_BUFFER_TOO_SMALL); - } - - exit: - return err2; - }); - - // Simply return a truncated list if there are more matching keys than will fit in the array. - if (err == CHIP_ERROR_BUFFER_TOO_SMALL) - { - err = CHIP_NO_ERROR; - } - SuccessOrExit(err); - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::Clear(void) -{ - CHIP_ERROR err; - - // Iterate over all GroupKey records deleting each one. - err = ForEachRecord(kGroupKeyFileId, kGroupKeyRecordKey, [](const fds_flash_record_t & rec, bool & deleteRec) -> CHIP_ERROR { - deleteRec = true; - return CHIP_NO_ERROR; - }); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "GroupKeyStore: cleared"); - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::RetrieveLastUsedEpochKeyId(void) -{ - CHIP_ERROR err; - - err = ReadConfigValue(kConfigKey_LastUsedEpochKeyId, LastUsedEpochKeyId); - if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) - { - LastUsedEpochKeyId = ChipKeyId::kNone; - err = CHIP_NO_ERROR; - } - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::StoreLastUsedEpochKeyId(void) -{ - return WriteConfigValue(kConfigKey_LastUsedEpochKeyId, LastUsedEpochKeyId); -} - -CHIP_ERROR GroupKeyStoreImpl::Init() -{ - // Nothing to do - return CHIP_NO_ERROR; -} - -CHIP_ERROR GroupKeyStoreImpl::EncodeGroupKey(const ChipGroupKey & key, uint8_t * buf, size_t bufSize, size_t & encodedKeyLen) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - uint8_t * p = buf; - - VerifyOrExit(bufSize >= kFixedEncodedKeySize + key.KeyLen, err = CHIP_ERROR_BUFFER_TOO_SMALL); - - Encoding::LittleEndian::Write32(p, key.KeyId); - Encoding::LittleEndian::Write32(p, key.StartTime); - Encoding::Write8(p, key.KeyLen); - memcpy(p, key.Key, key.KeyLen); - p += key.KeyLen; - - encodedKeyLen = p - buf; - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::DecodeGroupKey(const uint8_t * encodedKey, size_t encodedKeyLen, ChipGroupKey & key) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - const uint8_t * p = encodedKey; - - VerifyOrExit(encodedKeyLen >= kFixedEncodedKeySize, err = CHIP_ERROR_INVALID_ARGUMENT); - - key.KeyId = Encoding::LittleEndian::Read32(p); - key.StartTime = Encoding::LittleEndian::Read32(p); - key.KeyLen = Encoding::Read8(p); - - VerifyOrExit(encodedKeyLen >= kFixedEncodedKeySize + key.KeyLen, err = CHIP_ERROR_INVALID_ARGUMENT); - - memcpy(key.Key, p, key.KeyLen); - -exit: - return err; -} - -CHIP_ERROR GroupKeyStoreImpl::DecodeGroupKeyId(const uint8_t * encodedKey, size_t encodedKeyLen, uint32_t & keyId) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(encodedKeyLen >= kFixedEncodedKeySize, err = CHIP_ERROR_INVALID_ARGUMENT); - - keyId = Encoding::LittleEndian::Get32(encodedKey); - -exit: - return err; -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/GroupKeyStoreImpl.h b/src/platform/nRF5/GroupKeyStoreImpl.h deleted file mode 100644 index ea7e48be51fc8f..00000000000000 --- a/src/platform/nRF5/GroupKeyStoreImpl.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the chip Group Key Store interface - * for platforms based on the Nordic nRF5 SDK. - */ - -#include -#include -#include - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -class ChipGroupKey -{ -public: - enum - { - MaxKeySize = 36 - }; - uint32_t KeyId; /**< The key ID. */ - uint8_t KeyLen; /**< The key length. */ - uint8_t Key[MaxKeySize]; /**< The secret key material. */ - union - { - uint32_t StartTime; /**< The epoch key start time. */ - uint32_t GlobalId; /**< The application group key global ID. */ - }; -}; - -/** - * An implementation of the chip GroupKeyStoreBase API for platforms based - * on the Nordic nRF5 SDK. - */ -class GroupKeyStoreImpl final : public ::chip::Profiles::Security::AppKeys::GroupKeyStoreBase, private NRF5Config -{ - using ChipGroupKey = ::chip::Profiles::Security::AppKeys::ChipGroupKey; - -public: - CHIP_ERROR Init(); - - CHIP_ERROR RetrieveGroupKey(uint32_t keyId, ChipGroupKey & key) override; - CHIP_ERROR StoreGroupKey(const ChipGroupKey & key) override; - CHIP_ERROR DeleteGroupKey(uint32_t keyId) override; - CHIP_ERROR DeleteGroupKeysOfAType(uint32_t keyType) override; - CHIP_ERROR EnumerateGroupKeys(uint32_t keyType, uint32_t * keyIds, uint8_t keyIdsArraySize, uint8_t & keyCount) override; - CHIP_ERROR Clear(void) override; - CHIP_ERROR RetrieveLastUsedEpochKeyId(void) override; - CHIP_ERROR StoreLastUsedEpochKeyId(void) override; - -private: - static constexpr size_t kFixedEncodedKeySize = 4U + // key id - 4U + // start time / global id - 1U; // key data length - - static constexpr size_t kMaxEncodedKeySize = kFixedEncodedKeySize + ChipGroupKey::MaxKeySize; - - static constexpr uint16_t kGroupKeyFileId = GetFileId(kConfigKey_GroupKey); - static constexpr uint16_t kGroupKeyRecordKey = GetRecordKey(kConfigKey_GroupKey); - - static CHIP_ERROR EncodeGroupKey(const ChipGroupKey & key, uint8_t * buf, size_t bufSize, size_t & encodedKeyLen); - static CHIP_ERROR DecodeGroupKey(const uint8_t * encodedKey, size_t encodedKeyLen, ChipGroupKey & key); - static CHIP_ERROR DecodeGroupKeyId(const uint8_t * encodedKey, size_t encodedKeyLen, uint32_t & keyId); -}; - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/InetPlatformConfig.h b/src/platform/nRF5/InetPlatformConfig.h deleted file mode 100644 index 4c97283e06716e..00000000000000 --- a/src/platform/nRF5/InetPlatformConfig.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Platform-specific configuration overrides for the Openchip Inet - * Layer on nRF52 platforms using the Nordic nRF5 SDK. - * - */ - -#pragma once - -#include "sdk_errors.h" - -// ==================== Platform Adaptations ==================== - -#define INET_CONFIG_ERROR_TYPE ret_code_t -#define INET_CONFIG_NO_ERROR NRF_SUCCESS -#define INET_CONFIG_ERROR_MIN 1000000 -#define INET_CONFIG_ERROR_MAX 1000999 - -#define INET_CONFIG_ENABLE_IPV4 0 - -// ========== Platform-specific Configuration Overrides ========= - -#ifndef INET_CONFIG_NUM_TCP_ENDPOINTS -#define INET_CONFIG_NUM_TCP_ENDPOINTS 4 -#endif // INET_CONFIG_NUM_TCP_ENDPOINTS - -#ifndef INET_CONFIG_NUM_UDP_ENDPOINTS -#define INET_CONFIG_NUM_UDP_ENDPOINTS 4 -#endif // INET_CONFIG_NUM_UDP_ENDPOINTS diff --git a/src/platform/nRF5/Logging.cpp b/src/platform/nRF5/Logging.cpp deleted file mode 100644 index f47342822dc415..00000000000000 --- a/src/platform/nRF5/Logging.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides implementations for the CHIP and LwIP logging functions - * on Nordic nRF52 platforms. - */ - -#define NRF_LOG_MODULE_NAME chip - -#include -#include -#include -#include - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD -#include -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD - -// If deferred logging is NOT enabled, do bother calling the nRF5 SDK nrf_log_push() function. -#if !NRF_LOG_DEFERRED -#undef NRF_LOG_PUSH -#define NRF_LOG_PUSH(x) (x) -#endif - -using namespace ::chip; -using namespace ::chip::DeviceLayer; -using namespace ::chip::DeviceLayer::Internal; - -namespace chip { -namespace DeviceLayer { - -/** - * Called whenever a log message is emitted by chip or LwIP. - * - * This function is intended be overridden by the application to, e.g., - * schedule output of queued log entries. - */ -void __attribute__((weak)) OnLogOutput(void) {} - -} // namespace DeviceLayer -} // namespace chip - -NRF_LOG_MODULE_REGISTER(); - -namespace chip { -namespace Logging { - -/** - * CHIP log output function. - */ - -void LogV(uint8_t module, uint8_t category, const char * msg, va_list v) -{ - (void) module; - (void) category; - -#if NRF_LOG_ENABLED - - if (IsCategoryEnabled(category)) - { - { - char formattedMsg[CHIP_DEVICE_CONFIG_LOG_MESSAGE_MAX_SIZE]; - size_t prefixLen; - - constexpr size_t maxPrefixLen = ChipLoggingModuleNameLen + 3; - static_assert(sizeof(formattedMsg) > maxPrefixLen); - - // Form the log prefix, e.g. "[DL] " - formattedMsg[0] = '['; - GetModuleName(formattedMsg + 1, module); - prefixLen = strlen(formattedMsg); - formattedMsg[prefixLen++] = ']'; - formattedMsg[prefixLen++] = ' '; - - // Append the log message. - vsnprintf(formattedMsg + prefixLen, sizeof(formattedMsg) - prefixLen, msg, v); - - // Invoke the NRF logging library to log the message. - switch (category) - { - case kLogCategory_Error: - NRF_LOG_ERROR("%s", NRF_LOG_PUSH(formattedMsg)); - break; - case kLogCategory_Progress: - case kLogCategory_Retain: - default: - NRF_LOG_INFO("%s", NRF_LOG_PUSH(formattedMsg)); - break; - case kLogCategory_Detail: - NRF_LOG_DEBUG("%s", NRF_LOG_PUSH(formattedMsg)); - break; - } - -#if configCHECK_FOR_STACK_OVERFLOW - // Force a stack overflow check. - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) - taskYIELD(); -#endif - } - - // Let the application know that a log message has been emitted. - DeviceLayer::OnLogOutput(); - } -#else // NRF_LOG_ENABLED - (void) msg; - (void) v; -#endif // NRF_LOG_ENABLED -} - -} // namespace Logging -} // namespace chip - -#undef NRF_LOG_MODULE_NAME -#define NRF_LOG_MODULE_NAME lwip -NRF_LOG_MODULE_REGISTER(); - -/** - * LwIP log output function. - */ -extern "C" void LwIPLog(const char * msg, ...) -{ - va_list v; - - va_start(v, msg); - -#if NRF_LOG_ENABLED - { - char formattedMsg[CHIP_DEVICE_CONFIG_LOG_MESSAGE_MAX_SIZE]; - - // Append the log message. - size_t len = vsnprintf(formattedMsg, sizeof(formattedMsg), msg, v); - - while (len > 0 && isspace(formattedMsg[len - 1])) - { - len--; - formattedMsg[len] = 0; - } - - // Invoke the NRF logging library to log the message. - NRF_LOG_DEBUG("%s", NRF_LOG_PUSH(formattedMsg)); - } - - // Let the application know that a log message has been emitted. - DeviceLayer::OnLogOutput(); - -#endif // NRF_LOG_ENABLED - - va_end(v); -} - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - -#undef NRF_LOG_MODULE_NAME -#define NRF_LOG_MODULE_NAME thread -NRF_LOG_MODULE_REGISTER(); - -extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char * aFormat, ...) -{ - va_list v; - - (void) aLogLevel; - (void) aLogRegion; - - va_start(v, aFormat); - -#if NRF_LOG_ENABLED - { - char formattedMsg[CHIP_DEVICE_CONFIG_LOG_MESSAGE_MAX_SIZE]; - - // Append the log message. - vsnprintf(formattedMsg, sizeof(formattedMsg), aFormat, v); - - // Invoke the NRF logging library to log the message. - switch (aLogLevel) - { - case OT_LOG_LEVEL_CRIT: - NRF_LOG_ERROR("%s", NRF_LOG_PUSH(formattedMsg)); - break; - case OT_LOG_LEVEL_WARN: - NRF_LOG_WARNING("%s", NRF_LOG_PUSH(formattedMsg)); - break; - case OT_LOG_LEVEL_NOTE: - case OT_LOG_LEVEL_INFO: - default: - NRF_LOG_INFO("%s", NRF_LOG_PUSH(formattedMsg)); - break; - case OT_LOG_LEVEL_DEBG: - NRF_LOG_DEBUG("%s", NRF_LOG_PUSH(formattedMsg)); - break; - } - -#if configCHECK_FOR_STACK_OVERFLOW - // Force a stack overflow check. - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) - taskYIELD(); -#endif - } - - // Let the application know that a log message has been emitted. - DeviceLayer::OnLogOutput(); - -#endif // NRF_LOG_ENABLED - - va_end(v); -} - -#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD diff --git a/src/platform/nRF5/PlatformManagerImpl.cpp b/src/platform/nRF5/PlatformManagerImpl.cpp deleted file mode 100644 index c3cb9e3489cfa2..00000000000000 --- a/src/platform/nRF5/PlatformManagerImpl.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the PlatformManager object - * for nRF52 platforms using the Nordic nRF5 SDK. - */ -/* this file behaves like a config.h, comes first */ -#include - -#include -#include -#include - -#include - -namespace chip { -namespace DeviceLayer { - -PlatformManagerImpl PlatformManagerImpl::sInstance; - -CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) -{ - CHIP_ERROR err; - - // Arrange for nRF5 SDK errors to be translated to text. - Internal::RegisterNRFErrorFormatter(); - - // Initialize the configuration system. - err = Internal::NRF5Config::Init(); - SuccessOrExit(err); - - // Initialize LwIP. - tcpip_init(NULL, NULL); - - // Call _InitChipStack() on the generic implementation base class - // to finish the initialization process. - err = Internal::GenericPlatformManagerImpl_FreeRTOS::_InitChipStack(); - SuccessOrExit(err); - -exit: - return err; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/PlatformManagerImpl.h b/src/platform/nRF5/PlatformManagerImpl.h deleted file mode 100644 index 94c036036793ec..00000000000000 --- a/src/platform/nRF5/PlatformManagerImpl.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the PlatformManager object. - */ - -#pragma once - -#include - -namespace chip { -namespace DeviceLayer { - -/** - * Concrete implementation of the PlatformManager singleton object for the nRF52 platform. - */ -class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_FreeRTOS -{ - // Allow the PlatformManager interface class to delegate method calls to - // the implementation methods provided by this class. - friend PlatformManager; - - // Allow the generic implementation base class to call helper methods on - // this class. -#ifndef DOXYGEN_SHOULD_SKIP_THIS - friend Internal::GenericPlatformManagerImpl_FreeRTOS; -#endif - -public: - // ===== Platform-specific members that may be accessed directly by the application. - - /* none so far */ - -private: - // ===== Methods that implement the PlatformManager abstract interface. - - CHIP_ERROR _InitChipStack(void); - - // ===== Members for internal use by the following friends. - - friend PlatformManager & PlatformMgr(void); - friend PlatformManagerImpl & PlatformMgrImpl(void); - friend class Internal::BLEManagerImpl; - - static PlatformManagerImpl sInstance; - - using Internal::GenericPlatformManagerImpl_FreeRTOS::PostEventFromISR; -}; - -/** - * Returns the public interface of the PlatformManager singleton object. - * - * chip applications should use this to access features of the PlatformManager object - * that are common to all platforms. - */ -inline PlatformManager & PlatformMgr(void) -{ - return PlatformManagerImpl::sInstance; -} - -/** - * Returns the platform-specific implementation of the PlatformManager singleton object. - * - * chip applications can use this to gain access to features of the PlatformManager - * that are specific to the ESP32 platform. - */ -inline PlatformManagerImpl & PlatformMgrImpl(void) -{ - return PlatformManagerImpl::sInstance; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/README.md b/src/platform/nRF5/README.md deleted file mode 100644 index 113f288d07f54b..00000000000000 --- a/src/platform/nRF5/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Overview of CHIP nRF52840 Adaption - -The following is an overview of the nRF5 adaptation of CHIP. Most of this code -will have parallels in any new adaptation. - -(All file names are relative to `connectedhomeip/src/platform/nRF5...`). - -`PlatformManagerImpl.h`
`PlatformManagerImpl.cpp` - -- Concrete implementation of PlatformManager interface -- Provides initialization of the CHIP stack and core event loop for the chip - task -- Relies on GenericPlatformManagerImpl_FreeRTOS<> class to provide most of the - implementation - -`ConfigurationManagerImpl.h`
`ConfigurationManagerImpl.cpp` - -- Concrete implementation of ConfigurationManager interface -- Manages storage and retrieval of persistent configuration data -- Relies on GenericConfigurationManagerImpl<> classes to implement most API - functionality -- Delegates low-level reading and writing of persistent values to NRF5Config - class - -`ConnectivityManagerImpl.h`
`ConnectivityManagerImpl.cpp` - -- Concrete implementation of ConnectivityManager interface -- Provides high-level APIs for managing device connectivity -- Relies on GenericConnectivityManagerImpl_Thread<> class to provide most of - the implementation - -`ThreadStackManagerImpl.h`
`ThreadStackManagerImpl.cpp` - -- Concrete implementation of ThreadStackManager interface -- Supports Thread stack initialization and core event loop processing -- Relies on GenericThreadStackManagerImpl_OpenThread/FreeRTOS/LwIP<> classes - to implement most API functionaltiy - -`BLEManagerImpl.h`
`BLEManagerImpl.cpp` - -- Concrete implementation of the BLEManager interface -- Maps CHIP's BLE interface abstractions (BleLayer, BlePlatformDelegate, - BleApplicationDelegate) onto the platform's native BLE services -- Implements CHIP-compatible BLE advertising and GATT service using the - Softdevice BLE stack - -`Entropy.cpp` - -- Implements interface to platform entropy source - -`Logging.cpp` - -- Adaption of chip debug logging to platform logging facility - -`NRF5Config.cpp` - -- Implements low-level read/write of persistent configuration values -- Class API specifically designed to work in conjunction with the - GenericConfigurationManagerImpl<> class. diff --git a/src/platform/nRF5/SoftwareUpdateManagerImpl.cpp b/src/platform/nRF5/SoftwareUpdateManagerImpl.cpp deleted file mode 100644 index 0ac11dca8cb497..00000000000000 --- a/src/platform/nRF5/SoftwareUpdateManagerImpl.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * 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 - -#if CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_UPDATE_MANAGER - -#include - -namespace chip { -namespace DeviceLayer { - -SoftwareUpdateManagerImpl SoftwareUpdateManagerImpl::sInstance; - -CHIP_ERROR SoftwareUpdateManagerImpl::_Init(void) -{ - Internal::GenericSoftwareUpdateManagerImpl::DoInit(); - - return CHIP_NO_ERROR; -} - -} // namespace DeviceLayer -} // namespace chip - -#endif // CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_UPDATE_MANAGER diff --git a/src/platform/nRF5/SystemPlatformConfig.h b/src/platform/nRF5/SystemPlatformConfig.h deleted file mode 100644 index c5a012f33dbf4e..00000000000000 --- a/src/platform/nRF5/SystemPlatformConfig.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Platform-specific configuration overrides for the CHIP System - * Layer on nRF52 platforms using the Nordic nRF5 SDK. - * - */ - -#pragma once - -#include - -#include "sdk_errors.h" - -namespace chip { -namespace DeviceLayer { -struct ChipDeviceEvent; -} // namespace DeviceLayer -} // namespace chip - -// ==================== Platform Adaptations ==================== - -#define CHIP_SYSTEM_CONFIG_POSIX_LOCKING 0 -#define CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING 0 -#define CHIP_SYSTEM_CONFIG_NO_LOCKING 1 -#define CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS 1 -#define CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME 1 -#define CHIP_SYSTEM_CONFIG_LWIP_EVENT_TYPE int -#define CHIP_SYSTEM_CONFIG_LWIP_EVENT_OBJECT_TYPE const struct ::chip::DeviceLayer::ChipDeviceEvent * - -#define CHIP_SYSTEM_CONFIG_ERROR_TYPE ret_code_t -#define CHIP_SYSTEM_CONFIG_NO_ERROR NRF_SUCCESS -#define CHIP_SYSTEM_CONFIG_ERROR_MIN 7000000 -#define CHIP_SYSTEM_CONFIG_ERROR_MAX 7000999 -#define _CHIP_SYSTEM_CONFIG_ERROR(e) (CHIP_SYSTEM_CONFIG_ERROR_MIN + (e)) -#define CHIP_SYSTEM_LWIP_ERROR_MIN 3000000 -#define CHIP_SYSTEM_LWIP_ERROR_MAX 3000128 - -// ========== Platform-specific Configuration Overrides ========= - -#ifndef CHIP_SYSTEM_CONFIG_NUM_TIMERS -#define CHIP_SYSTEM_CONFIG_NUM_TIMERS 16 -#endif // CHIP_SYSTEM_CONFIG_NUM_TIMERS diff --git a/src/platform/nRF5/ThreadStackManagerImpl.cpp b/src/platform/nRF5/ThreadStackManagerImpl.cpp deleted file mode 100644 index 3c0472da0cca40..00000000000000 --- a/src/platform/nRF5/ThreadStackManagerImpl.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the ThreadStackManager object for - * nRF52 platforms using the Nordic nRF5 SDK and the OpenThread - * stack. - * - */ -/* this file behaves like a config.h, comes first */ -#include - -#include -#include - -#include -#include - -#include "boards.h" -#include "nrf_log.h" - -namespace chip { -namespace DeviceLayer { - -using namespace ::chip::DeviceLayer::Internal; - -ThreadStackManagerImpl ThreadStackManagerImpl::sInstance; - -CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack(void) -{ - return InitThreadStack(NULL); -} - -CHIP_ERROR ThreadStackManagerImpl::InitThreadStack(otInstance * otInst) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - // Initialize the generic implementation base classes. - err = GenericThreadStackManagerImpl_FreeRTOS::DoInit(); - SuccessOrExit(err); - err = GenericThreadStackManagerImpl_OpenThread_LwIP::DoInit(otInst); - SuccessOrExit(err); - -exit: - return err; -} - -bool ThreadStackManagerImpl::IsInitialized() -{ - return sInstance.mThreadStackLock != NULL; -} - -void ThreadStackManagerImpl::_OnCHIPoBLEAdvertisingStart(void) -{ - // If Thread-over-BLE is enabled, ensure that ToBLE advertising is stopped before - // starting CHIPoBLE advertising. This is accomplished by disabling the OpenThread - // IPv6 interface via a call to otIp6SetEnabled(false). - // - // On platforms where there is no native support for simultaneous BLE advertising - // (e.g. Nordic’s SoftDevice), it is necessary to coordinate between the different - // advertising modes a CHIP device may employ. This arises in particular when a - // device supports both CHIPoBLE and ToBLE, each of which requires a separate advertising - // regime. The OnCHIPoBLEAdvertisingStart()/OnCHIPoBLEAdvertisingStop() methods handle - // the switching between the two modes. - // -#if OPENTHREAD_CONFIG_ENABLE_TOBLE - LockThreadStack(); - otIp6SetEnabled(OTInstance(), false); - UnlockThreadStack(); -#endif -} - -void ThreadStackManagerImpl::_OnCHIPoBLEAdvertisingStop(void) -{ - // If Thread-over-BLE is enabled, and a Thread provision exists, ensure that ToBLE - // advertising is re-activated once CHIPoBLE advertising stops. - // -#if OPENTHREAD_CONFIG_ENABLE_TOBLE - LockThreadStack(); - if (otThreadGetDeviceRole(OTInstance()) != OT_DEVICE_ROLE_DISABLED && otDatasetIsCommissioned(OTInstance())) - { - otIp6SetEnabled(OTInstance(), true); - } - UnlockThreadStack(); -#endif -} - -} // namespace DeviceLayer -} // namespace chip - -using namespace ::chip::DeviceLayer; - -/** - * Glue function called directly by the OpenThread stack when tasklet processing work - * is pending. - */ -extern "C" void otTaskletsSignalPending(otInstance * p_instance) -{ - ThreadStackMgrImpl().SignalThreadActivityPending(); -} - -/** - * Glue function called directly by the OpenThread stack when system event processing work - * is pending. - */ -extern "C" void otSysEventSignalPending(void) -{ - BaseType_t yieldRequired = ThreadStackMgrImpl().SignalThreadActivityPendingFromISR(); - portYIELD_FROM_ISR(yieldRequired); -} diff --git a/src/platform/nRF5/ThreadStackManagerImpl.h b/src/platform/nRF5/ThreadStackManagerImpl.h deleted file mode 100644 index 11be0c92088387..00000000000000 --- a/src/platform/nRF5/ThreadStackManagerImpl.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Provides an implementation of the ThreadStackManager object - * for nRF52 platforms using the Nordic nRF5 SDK and the OpenThread - * stack. - */ - -#pragma once - -#include -#include - -#include -#include - -extern "C" void otSysEventSignalPending(void); - -namespace chip { -namespace DeviceLayer { - -class ThreadStackManager; -class ThreadStackManagerImpl; -namespace Internal { -extern int GetEntropy_nRF5(uint8_t * buf, size_t bufSize); -} - -/** - * Concrete implementation of the ThreadStackManager singleton object for nRF52 platforms - * using the Nordic nRF5 SDK and the OpenThread stack. - */ -class ThreadStackManagerImpl final : public ThreadStackManager, - public Internal::GenericThreadStackManagerImpl_OpenThread_LwIP, - public Internal::GenericThreadStackManagerImpl_FreeRTOS -{ - // Allow the ThreadStackManager interface class to delegate method calls to - // the implementation methods provided by this class. - friend class ThreadStackManager; - - // Allow the generic implementation base classes to call helper methods on - // this class. -#ifndef DOXYGEN_SHOULD_SKIP_THIS - friend Internal::GenericThreadStackManagerImpl_OpenThread; - friend Internal::GenericThreadStackManagerImpl_OpenThread_LwIP; - friend Internal::GenericThreadStackManagerImpl_FreeRTOS; -#endif - - // Allow glue functions called by OpenThread to call helper methods on this - // class. - friend void ::otTaskletsSignalPending(otInstance * otInst); - friend void ::otSysEventSignalPending(void); - -public: - // ===== Platform-specific members that may be accessed directly by the application. - - using ThreadStackManager::InitThreadStack; - CHIP_ERROR InitThreadStack(otInstance * otInst); - void _OnCHIPoBLEAdvertisingStart(void); - void _OnCHIPoBLEAdvertisingStop(void); - -private: - // ===== Methods that implement the ThreadStackManager abstract interface. - - CHIP_ERROR _InitThreadStack(void); - - // ===== Members for internal use by the following friends. - - friend ThreadStackManager & ::chip::DeviceLayer::ThreadStackMgr(void); - friend ThreadStackManagerImpl & ::chip::DeviceLayer::ThreadStackMgrImpl(void); - friend int Internal::GetEntropy_nRF5(uint8_t * buf, size_t bufSize); - - static ThreadStackManagerImpl sInstance; - - static bool IsInitialized(); - - // ===== Private members for use by this class only. - - ThreadStackManagerImpl() = default; -}; - -/** - * Returns the public interface of the ThreadStackManager singleton object. - * - * chip applications should use this to access features of the ThreadStackManager object - * that are common to all platforms. - */ -inline ThreadStackManager & ThreadStackMgr(void) -{ - return ThreadStackManagerImpl::sInstance; -} - -/** - * Returns the platform-specific implementation of the ThreadStackManager singleton object. - * - * chip applications can use this to gain access to features of the ThreadStackManager - * that are specific to nRF52 platforms. - */ -inline ThreadStackManagerImpl & ThreadStackMgrImpl(void) -{ - return ThreadStackManagerImpl::sInstance; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/args.gni b/src/platform/nRF5/args.gni deleted file mode 100644 index 143fb9bdcedcd9..00000000000000 --- a/src/platform/nRF5/args.gni +++ /dev/null @@ -1,39 +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. - -import("//build_overrides/chip.gni") -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -chip_device_platform = "nrf5" - -lwip_platform = "nrf5" -lwip_ipv6 = true -lwip_ipv4 = false -lwip_api = true - -chip_inet_config_enable_ipv4 = false -chip_inet_config_enable_dns_resolver = false - -chip_build_tests = false - -mbedtls_target = "${chip_root}/third_party/nrf5_sdk" -openthread_external_mbedtls = mbedtls_target - -openthread_project_core_config_file = "openthread-core-nrf52840-config.h" -openthread_core_config_platform_check_file = - "openthread-core-nrf52840-config-check.h" -openthread_core_config_deps = [ "${chip_root}/third_party/openthread/platforms/nrf528xx:openthread_core_config_nrf52840" ] - -openthread_external_platform = "${chip_root}/third_party/openthread/platforms/nrf528xx:libopenthread-nrf52840-softdevice-sdk" diff --git a/src/platform/nRF5/nRF5Config.cpp b/src/platform/nRF5/nRF5Config.cpp deleted file mode 100644 index 8afbf4fd9164f7..00000000000000 --- a/src/platform/nRF5/nRF5Config.cpp +++ /dev/null @@ -1,789 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019-2020 Google LLC. - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Utilities for accessing persisted device configuration on - * platforms based on the Nordic nRF5 SDK. - */ -/* this file behaves like a config.h, comes first */ -#include - -#include - -#include -#include -#include -#include - -#include "FreeRTOS.h" -#include "fds.h" -#include "mem_manager.h" -#include "semphr.h" - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -NRF5Config::FDSAsyncOp * volatile NRF5Config::sActiveAsyncOp; -SemaphoreHandle_t NRF5Config::sAsyncOpCompletionSem; - -CHIP_ERROR NRF5Config::Init() -{ - CHIP_ERROR err; - ret_code_t fdsRes; - - // Create a semaphore to signal the completion of async FDS operations. - sAsyncOpCompletionSem = xSemaphoreCreateBinary(); - VerifyOrExit(sAsyncOpCompletionSem != NULL, err = CHIP_ERROR_NO_MEMORY); - - // Register an FDS event handler. - fdsRes = fds_register(HandleFDSEvent); - SuccessOrExit(err = MapFDSError(fdsRes)); - - // Initialize the FDS module. - { - FDSAsyncOp initOp(FDSAsyncOp::kInit); - err = DoAsyncFDSOp(initOp); - SuccessOrExit(err); - } - -exit: - return err; -} - -CHIP_ERROR NRF5Config::ReadConfigValue(Key key, bool & val) -{ - CHIP_ERROR err; - fds_record_desc_t recDesc; - fds_flash_record_t rec; - uint32_t wordVal; - bool needClose = false; - - err = OpenRecord(key, recDesc, rec); - SuccessOrExit(err); - needClose = true; - - VerifyOrExit(rec.p_header->length_words == 1, err = CHIP_ERROR_INVALID_ARGUMENT); - - wordVal = Encoding::LittleEndian::Get32((const uint8_t *) rec.p_data); - val = (wordVal != 0); - -exit: - if (needClose) - { - fds_record_close(&recDesc); - } - return err; -} - -CHIP_ERROR NRF5Config::ReadConfigValue(Key key, uint32_t & val) -{ - CHIP_ERROR err; - fds_record_desc_t recDesc; - fds_flash_record_t rec; - bool needClose = false; - - err = OpenRecord(key, recDesc, rec); - SuccessOrExit(err); - needClose = true; - - VerifyOrExit(rec.p_header->length_words == 1, err = CHIP_ERROR_INVALID_ARGUMENT); - - val = Encoding::LittleEndian::Get32((const uint8_t *) rec.p_data); - -exit: - if (needClose) - { - fds_record_close(&recDesc); - } - return err; -} - -CHIP_ERROR NRF5Config::ReadConfigValue(Key key, uint64_t & val) -{ - CHIP_ERROR err; - fds_record_desc_t recDesc; - fds_flash_record_t rec; - bool needClose = false; - - err = OpenRecord(key, recDesc, rec); - SuccessOrExit(err); - needClose = true; - - VerifyOrExit(rec.p_header->length_words == 2, err = CHIP_ERROR_INVALID_ARGUMENT); - - val = Encoding::LittleEndian::Get64((const uint8_t *) rec.p_data); - -exit: - if (needClose) - { - fds_record_close(&recDesc); - } - return err; -} - -CHIP_ERROR NRF5Config::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) -{ - CHIP_ERROR err; - fds_flash_record_t rec; - fds_record_desc_t recDesc; - bool needClose = false; - const uint8_t * strEnd; - - err = OpenRecord(key, recDesc, rec); - SuccessOrExit(err); - needClose = true; - - strEnd = (const uint8_t *) memchr(rec.p_data, 0, rec.p_header->length_words * kFDSWordSize); - VerifyOrExit(strEnd != NULL, err = CHIP_ERROR_INVALID_ARGUMENT); - - outLen = strEnd - (const uint8_t *) rec.p_data; - - // NOTE: the caller is allowed to pass NULL for buf to query the length of the stored - // value. - - if (buf != NULL) - { - VerifyOrExit(bufSize > outLen, err = CHIP_ERROR_BUFFER_TOO_SMALL); - - memcpy(buf, rec.p_data, outLen + 1); - } - -exit: - if (needClose) - { - fds_record_close(&recDesc); - } - return err; -} - -CHIP_ERROR NRF5Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) -{ - CHIP_ERROR err; - fds_flash_record_t rec; - fds_record_desc_t recDesc; - bool needClose = false; - - err = OpenRecord(key, recDesc, rec); - SuccessOrExit(err); - needClose = true; - - VerifyOrExit(rec.p_header->length_words >= 1, err = CHIP_ERROR_INVALID_ARGUMENT); - - // First two bytes are length. - outLen = Encoding::LittleEndian::Get16((const uint8_t *) rec.p_data); - - VerifyOrExit((rec.p_header->length_words * kFDSWordSize) >= (outLen + 2), err = CHIP_ERROR_INVALID_ARGUMENT); - - // NOTE: the caller is allowed to pass NULL for buf to query the length of the stored - // value. - - if (buf != NULL) - { - VerifyOrExit(bufSize >= outLen, err = CHIP_ERROR_BUFFER_TOO_SMALL); - - memcpy(buf, ((const uint8_t *) rec.p_data) + 2, outLen); - } - -exit: - if (needClose) - { - fds_record_close(&recDesc); - } - return err; -} - -CHIP_ERROR NRF5Config::WriteConfigValue(Key key, bool val) -{ - CHIP_ERROR err; - uint32_t storedVal = (val) ? 1 : 0; - - FDSAsyncOp addOrUpdateOp(FDSAsyncOp::kAddOrUpdateRecord); - addOrUpdateOp.FileId = GetFileId(key); - addOrUpdateOp.RecordKey = GetRecordKey(key); - addOrUpdateOp.RecordData = (const uint8_t *) &storedVal; - addOrUpdateOp.RecordDataLengthWords = 1; - - err = DoAsyncFDSOp(addOrUpdateOp); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "FDS set: %04" PRIX16 "/%04" PRIX16 " = %s", GetFileId(key), GetRecordKey(key), - val ? "true" : "false"); - -exit: - return err; -} - -CHIP_ERROR NRF5Config::WriteConfigValue(Key key, uint32_t val) -{ - CHIP_ERROR err; - - FDSAsyncOp addOrUpdateOp(FDSAsyncOp::kAddOrUpdateRecord); - addOrUpdateOp.FileId = GetFileId(key); - addOrUpdateOp.RecordKey = GetRecordKey(key); - addOrUpdateOp.RecordData = (const uint8_t *) &val; - addOrUpdateOp.RecordDataLengthWords = 1; - - err = DoAsyncFDSOp(addOrUpdateOp); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "FDS set: 0x%04" PRIX16 "/0x%04" PRIX16 " = %" PRIu32 " (0x%" PRIX32 ")", GetFileId(key), - GetRecordKey(key), val, val); - -exit: - return err; -} - -CHIP_ERROR NRF5Config::WriteConfigValue(Key key, uint64_t val) -{ - CHIP_ERROR err; - - FDSAsyncOp addOrUpdateOp(FDSAsyncOp::kAddOrUpdateRecord); - addOrUpdateOp.FileId = GetFileId(key); - addOrUpdateOp.RecordKey = GetRecordKey(key); - addOrUpdateOp.RecordData = (const uint8_t *) &val; - addOrUpdateOp.RecordDataLengthWords = 2; - - err = DoAsyncFDSOp(addOrUpdateOp); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "FDS set: 0x%04" PRIX16 "/0x%04" PRIX16 " = %" PRIu64 " (0x%" PRIX64 ")", GetFileId(key), - GetRecordKey(key), val, val); - -exit: - return err; -} - -CHIP_ERROR NRF5Config::WriteConfigValueStr(Key key, const char * str) -{ - return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0); -} - -CHIP_ERROR NRF5Config::WriteConfigValueStr(Key key, const char * str, size_t strLen) -{ - CHIP_ERROR err; - uint8_t * storedVal = NULL; - - if (str != NULL) - { - uint32_t storedValWords = FDSWords(strLen + 1); - - storedVal = (uint8_t *) pvPortMalloc(storedValWords * kFDSWordSize); - VerifyOrExit(storedVal != NULL, err = CHIP_ERROR_NO_MEMORY); - - memcpy(storedVal, str, strLen); - storedVal[strLen] = 0; - - FDSAsyncOp addOrUpdateOp(FDSAsyncOp::kAddOrUpdateRecord); - addOrUpdateOp.FileId = GetFileId(key); - addOrUpdateOp.RecordKey = GetRecordKey(key); - addOrUpdateOp.RecordData = storedVal; - addOrUpdateOp.RecordDataLengthWords = storedValWords; - - err = DoAsyncFDSOp(addOrUpdateOp); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "FDS set: 0x%04" PRIX16 "/0x%04" PRIX16 " = \"%s\"", GetFileId(key), GetRecordKey(key), - (const char *) storedVal); - } - - else - { - err = ClearConfigValue(key); - SuccessOrExit(err); - } - -exit: - if (storedVal != NULL) - { - vPortFree(storedVal); - } - return err; -} - -CHIP_ERROR NRF5Config::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) -{ - CHIP_ERROR err; - uint8_t * storedVal = NULL; - - if (data != NULL) - { - uint32_t storedValWords = FDSWords(dataLen + 2); - - storedVal = (uint8_t *) pvPortMalloc(storedValWords * kFDSWordSize); - VerifyOrExit(storedVal != NULL, err = CHIP_ERROR_NO_MEMORY); - - // First two bytes encode the length. - Encoding::LittleEndian::Put16(storedVal, (uint16_t) dataLen); - - memcpy(storedVal + 2, data, dataLen); - - FDSAsyncOp addOrUpdateOp(FDSAsyncOp::kAddOrUpdateRecord); - addOrUpdateOp.FileId = GetFileId(key); - addOrUpdateOp.RecordKey = GetRecordKey(key); - addOrUpdateOp.RecordData = storedVal; - addOrUpdateOp.RecordDataLengthWords = storedValWords; - - err = DoAsyncFDSOp(addOrUpdateOp); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "FDS set: 0x%04" PRIX16 "/0x%04" PRIX16 " = (blob length %" PRId32 ")", GetFileId(key), - GetRecordKey(key), dataLen); - } - - else - { - err = ClearConfigValue(key); - SuccessOrExit(err); - } - -exit: - if (storedVal != NULL) - { - vPortFree(storedVal); - } - return err; -} - -CHIP_ERROR NRF5Config::ClearConfigValue(Key key) -{ - CHIP_ERROR err; - - FDSAsyncOp delOp(FDSAsyncOp::kDeleteRecordByKey); - delOp.FileId = GetFileId(key); - delOp.RecordKey = GetRecordKey(key); - - err = DoAsyncFDSOp(delOp); - SuccessOrExit(err); - - ChipLogProgress(DeviceLayer, "FDS delete: 0x%04" PRIX16 "/0x%04" PRIX16, GetFileId(key), GetRecordKey(key)); - -exit: - return err; -} - -bool NRF5Config::ConfigValueExists(Key key) -{ - ret_code_t fdsRes; - fds_record_desc_t recDesc; - fds_find_token_t findToken; - - // Search for the requested record. - memset(&findToken, 0, sizeof(findToken)); - fdsRes = fds_record_find(GetFileId(key), GetRecordKey(key), &recDesc, &findToken); - - // Return true iff the record was found. - return fdsRes == NRF_SUCCESS; -} - -CHIP_ERROR NRF5Config::FactoryResetConfig(void) -{ - CHIP_ERROR err; - - // Delete the chipConfig file and all records its contains. - { - FDSAsyncOp delOp(FDSAsyncOp::kDeleteFile); - delOp.FileId = kFileId_ChipConfig; - err = DoAsyncFDSOp(delOp); - SuccessOrExit(err); - ChipLogProgress(DeviceLayer, "FDS delete file: 0x%04" PRIX16, kFileId_ChipConfig); - } - - // Force a GC - { - FDSAsyncOp gcOp(FDSAsyncOp::kGC); - err = DoAsyncFDSOp(gcOp); - SuccessOrExit(err); - } - -exit: - return err; -} - -#define CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MIN 10000000 -CHIP_ERROR NRF5Config::MapFDSError(ret_code_t fdsRes) -{ - return (fdsRes == NRF_SUCCESS) ? CHIP_NO_ERROR : CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MIN + fdsRes; -} - -CHIP_ERROR NRF5Config::OpenRecord(NRF5Config::Key key, fds_record_desc_t & recDesc, fds_flash_record_t & rec) -{ - CHIP_ERROR err; - ret_code_t fdsRes; - fds_find_token_t findToken; - - // Search for the requested record. Return "CONFIG_NOT_FOUND" if it doesn't exist. - memset(&findToken, 0, sizeof(findToken)); - fdsRes = fds_record_find(NRF5Config::GetFileId(key), NRF5Config::GetRecordKey(key), &recDesc, &findToken); - err = (fdsRes == FDS_ERR_NOT_FOUND) ? CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND : MapFDSError(fdsRes); - SuccessOrExit(err); - - // Open the record for reading. - fdsRes = fds_record_open(&recDesc, &rec); - err = MapFDSError(fdsRes); - SuccessOrExit(err); - -exit: - return err; -} - -CHIP_ERROR NRF5Config::ForEachRecord(uint16_t fileId, uint16_t recordKey, ForEachRecordFunct funct) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - ; - ret_code_t fdsRes; - fds_find_token_t findToken; - fds_record_desc_t recDesc; - fds_flash_record_t rec; - bool needClose = false; - - memset(&findToken, 0, sizeof(findToken)); - - while (true) - { - // Search for an occurrence of the requested record. If there are no more records, break the loop. - fdsRes = fds_record_find(fileId, recordKey, &recDesc, &findToken); - if (fdsRes == FDS_ERR_NOT_FOUND) - { - break; - } - err = MapFDSError(fdsRes); - SuccessOrExit(err); - - // Open the record for reading. - fdsRes = fds_record_open(&recDesc, &rec); - err = MapFDSError(fdsRes); - SuccessOrExit(err); - needClose = true; - - bool deleteRec = false; - - // Invoke the caller's function. - err = funct(rec, deleteRec); - SuccessOrExit(err); - - // Close the record. - needClose = false; - fdsRes = fds_record_close(&recDesc); - err = MapFDSError(fdsRes); - SuccessOrExit(err); - - // Delete the record if requested. - if (deleteRec) - { - FDSAsyncOp delOp(FDSAsyncOp::kDeleteRecord); - delOp.FileId = fileId; - delOp.RecordKey = recordKey; - delOp.RecordDesc = recDesc; - err = DoAsyncFDSOp(delOp); - SuccessOrExit(err); - } - } - -exit: - if (needClose) - { - fds_record_close(&recDesc); - } - return err; -} - -CHIP_ERROR NRF5Config::DoAsyncFDSOp(FDSAsyncOp & asyncOp) -{ - CHIP_ERROR err; - ret_code_t fdsRes; - fds_record_t rec; - bool gcPerformed = false; - - // Keep trying to perform the requested op until there's a definitive success or failure... - while (true) - { - bool existingRecFound = false; - - // If performing an AddOrUpdateRecord or DeleteRecordByKey, search for an existing record with the given key. - if (asyncOp.OpType == FDSAsyncOp::kAddOrUpdateRecord || asyncOp.OpType == FDSAsyncOp::kDeleteRecordByKey) - { - fds_find_token_t findToken; - memset(&findToken, 0, sizeof(findToken)); - fdsRes = fds_record_find(asyncOp.FileId, asyncOp.RecordKey, &asyncOp.RecordDesc, &findToken); - VerifyOrExit(fdsRes == NRF_SUCCESS || fdsRes == FDS_ERR_NOT_FOUND, err = MapFDSError(fdsRes)); - - // Remember if we found an existing record. - existingRecFound = (fdsRes == NRF_SUCCESS); - } - - // If adding or updating a record, prepare the FDS record structure with the record data. - if (asyncOp.OpType == FDSAsyncOp::kAddRecord || asyncOp.OpType == FDSAsyncOp::kUpdateRecord || - asyncOp.OpType == FDSAsyncOp::kAddOrUpdateRecord) - { - memset(&rec, 0, sizeof(rec)); - rec.file_id = asyncOp.FileId; - rec.key = asyncOp.RecordKey; - rec.data.p_data = asyncOp.RecordData; - rec.data.length_words = asyncOp.RecordDataLengthWords; - } - - // Make the requested op the active op. - sActiveAsyncOp = &asyncOp; - - // Initiate the requested FDS operation. - switch (asyncOp.OpType) - { - case FDSAsyncOp::kInit: - fdsRes = fds_init(); - break; - case FDSAsyncOp::kAddOrUpdateRecord: - // Depending on whether an existing record was found, call fds_record_write or fds_record_update. - if (!existingRecFound) - { - case FDSAsyncOp::kAddRecord: - fdsRes = fds_record_write(NULL, &rec); - break; - } - else - { - case FDSAsyncOp::kUpdateRecord: - fdsRes = fds_record_update(&asyncOp.RecordDesc, &rec); - break; - } - case FDSAsyncOp::kDeleteRecordByKey: - // If performing a kDeleteRecordByKey and no matching record was found, simply return success. - if (!existingRecFound) - { - ExitNow(err = CHIP_NO_ERROR); - } - // fall through... - case FDSAsyncOp::kDeleteRecord: - fdsRes = fds_record_delete(&asyncOp.RecordDesc); - break; - case FDSAsyncOp::kDeleteFile: - fdsRes = fds_file_delete(asyncOp.FileId); - break; - case FDSAsyncOp::kGC: - fdsRes = fds_gc(); - break; - case FDSAsyncOp::kWaitQueueSpaceAvailable: - // In this case, arrange to wait for any operation to complete, which coincides with - // space on the operation queue being available. - fdsRes = NRF_SUCCESS; - break; - default: - ChipDie(); - } - - // If the operation was queued successfully, wait for it to complete and retrieve the result. - // If the FreeRTOS scheduler is not running, poll the completion semaphore; otherwise wait - // indefinitely. - // - if (fdsRes == NRF_SUCCESS) - { - if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) - { - while (xSemaphoreTake(sAsyncOpCompletionSem, 0) == pdFALSE) - ; - } - else - { - xSemaphoreTake(sAsyncOpCompletionSem, portMAX_DELAY); - } - - fdsRes = asyncOp.Result; - } - - // Clear the active operation in case it wasn't done by the event handler. - sActiveAsyncOp = NULL; - - // Return immediately if the operation completed successfully. - if (fdsRes == NRF_SUCCESS) - { - ExitNow(err = CHIP_NO_ERROR); - } - - // If the operation failed for lack of flash space... - if (fdsRes == FDS_ERR_NO_SPACE_IN_FLASH) - { - // If we've already performed a garbage collection, fail immediately. - if (gcPerformed) - { - ExitNow(err = MapFDSError(fdsRes)); - } - - ChipLogProgress(DeviceLayer, "Initiating FDS GC to recover space"); - - // Request a garbage collection cycle and wait for it to complete. - FDSAsyncOp gcOp(FDSAsyncOp::kGC); - err = DoAsyncFDSOp(gcOp); - SuccessOrExit(err); - - // Repeat the requested operation. - continue; - } - - // If the write/update failed because the operation queue is full, wait for - // space to become available and then repeat the requested operation. - if (fdsRes == FDS_ERR_NO_SPACE_IN_QUEUES) - { - FDSAsyncOp waitOp(FDSAsyncOp::kWaitQueueSpaceAvailable); - err = DoAsyncFDSOp(waitOp); - SuccessOrExit(err); - continue; - } - - // If the operation timed out, simply try it again. - if (fdsRes == FDS_ERR_OPERATION_TIMEOUT) - { - continue; - } - - // Otherwise fail with an unrecoverable error. - ExitNow(err = MapFDSError(fdsRes)); - } - -exit: - return err; -} - -void NRF5Config::HandleFDSEvent(const fds_evt_t * fdsEvent) -{ - // Do nothing if there's no async operation active. - if (sActiveAsyncOp == NULL) - { - return; - } - - // Check if the event applies to the active async operation. - switch (sActiveAsyncOp->OpType) - { - case FDSAsyncOp::kInit: - if (fdsEvent->id != FDS_EVT_INIT) - { - return; - } - break; - case FDSAsyncOp::kAddOrUpdateRecord: - case FDSAsyncOp::kAddRecord: - case FDSAsyncOp::kUpdateRecord: - // Ignore the event if its not a WRITE or UPDATE, or if its for a different file/record. - if ((fdsEvent->id != FDS_EVT_WRITE && fdsEvent->id != FDS_EVT_UPDATE) || - fdsEvent->write.file_id != sActiveAsyncOp->FileId || fdsEvent->write.record_key != sActiveAsyncOp->RecordKey) - { - return; - } - break; - case FDSAsyncOp::kDeleteRecord: - case FDSAsyncOp::kDeleteRecordByKey: - // Ignore the event if its not a DEL_RECORD, or if its for a different file/record. - if (fdsEvent->id != FDS_EVT_DEL_RECORD || fdsEvent->del.record_id != sActiveAsyncOp->RecordDesc.record_id) - { - return; - } - break; - case FDSAsyncOp::kDeleteFile: - // Ignore the event if its not a DEL_FILE or its for a different file. - if (fdsEvent->id != FDS_EVT_DEL_FILE || fdsEvent->del.file_id != sActiveAsyncOp->FileId) - { - return; - } - break; - case FDSAsyncOp::kGC: - // Ignore the event if its not a GC. - if (fdsEvent->id != FDS_EVT_GC) - { - return; - } - break; - case FDSAsyncOp::kWaitQueueSpaceAvailable: - break; - } - - // Capture the result. - sActiveAsyncOp->Result = fdsEvent->result; - - // Mark the operation as complete. - sActiveAsyncOp = NULL; - - // Signal the CHIP thread that the operation has completed. -#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT - - // When using the Nodic SoftDevice, HandleFDSEvent() is called in a SoftDevice interrupt - // context. Therefore, we must use xSemaphoreGiveFromISR() to signal completion. - BaseType_t yieldRequired = xSemaphoreGiveFromISR(sAsyncOpCompletionSem, &yieldRequired); - - // Yield to the next runnable task, but only if the FreeRTOS scheduler has been started. - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED && yieldRequired == pdTRUE) - { - portYIELD_FROM_ISR(yieldRequired); - } - -#else // defined(SOFTDEVICE_PRESENT) || !SOFTDEVICE_PRESENT - - // When NOT using the Nodic SoftDevice, HandleFDSEvent() is called in a non-interrupt - // context. Therefore, use xSemaphoreGive() to signal completion. - xSemaphoreGive(sAsyncOpCompletionSem); - -#endif // !(defined(SOFTDEVICE_PRESENT) || !SOFTDEVICE_PRESENT) -} - -void NRF5Config::RunConfigUnitTest() -{ - CHIP_ERROR err; - - // Run common unit test - ::chip::DeviceLayer::Internal::RunConfigUnitTest(); - - // NRF Config Test 1 -- Force GC - { - const static uint8_t kTestData[] = { - 0xD5, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x30, 0x01, 0x08, 0x79, 0x55, 0x9F, 0x15, 0x1F, 0x66, 0x3D, 0x8F, 0x24, - 0x02, 0x05, 0x37, 0x03, 0x27, 0x13, 0x02, 0x00, 0x00, 0xEE, 0xEE, 0x30, 0xB4, 0x18, 0x18, 0x26, 0x04, 0x80, 0x41, - 0x1B, 0x23, 0x26, 0x05, 0x7F, 0xFF, 0xFF, 0x52, 0x37, 0x06, 0x27, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0xB4, - 0x18, 0x18, 0x24, 0x07, 0x02, 0x26, 0x08, 0x25, 0x00, 0x5A, 0x23, 0x30, 0x0A, 0x39, 0x04, 0x9E, 0xC7, 0x77, 0xC5, - 0xA4, 0x13, 0x31, 0xF7, 0x72, 0x2E, 0x27, 0xC2, 0x86, 0x3D, 0xC5, 0x2E, 0xD5, 0xD2, 0x3C, 0xCF, 0x7E, 0x06, 0xE3, - 0x48, 0x53, 0x87, 0xE8, 0x4D, 0xB0, 0x27, 0x07, 0x58, 0x4A, 0x38, 0xB4, 0xF3, 0xB2, 0x47, 0x94, 0x45, 0x58, 0x65, - 0x80, 0x08, 0x17, 0x6B, 0x8E, 0x4F, 0x07, 0x41, 0xA3, 0x3D, 0x5D, 0xCE, 0x76, 0x86, 0x35, 0x83, 0x29, 0x01, 0x18, - 0x35, 0x82, 0x29, 0x01, 0x24, 0x02, 0x05, 0x18, 0x35, 0x84, 0x29, 0x01, 0x36, 0x02, 0x04, 0x02, 0x04, 0x01, 0x18, - 0x18, 0x35, 0x81, 0x30, 0x02, 0x08, 0x42, 0xBD, 0x2C, 0x6B, 0x5B, 0x3A, 0x18, 0x16, 0x18, 0x35, 0x80, 0x30, 0x02, - 0x08, 0x44, 0xE3, 0x40, 0x38, 0xA9, 0xD4, 0xB5, 0xA7, 0x18, 0x35, 0x0C, 0x30, 0x01, 0x19, 0x00, 0xA6, 0x5D, 0x54, - 0xF5, 0xAE, 0x5D, 0x63, 0xEB, 0x69, 0xD8, 0xDB, 0xCB, 0xE2, 0x20, 0x0C, 0xD5, 0x6F, 0x43, 0x5E, 0x96, 0xA8, 0x54, - 0xB2, 0x74, 0x30, 0x02, 0x19, 0x00, 0xE0, 0x37, 0x02, 0x8B, 0xB3, 0x04, 0x06, 0xDD, 0xBD, 0x28, 0xAA, 0xC4, 0xF1, - 0xFF, 0xFB, 0xB1, 0xD4, 0x1C, 0x78, 0x40, 0xDA, 0x2C, 0xD8, 0x40, 0x18, 0x18, - }; - uint8_t buf[512]; - size_t dataLen; - - for (int i = 0; i < 100; i++) - { - err = WriteConfigValueBin(kConfigKey_MfrDeviceCert, kTestData, sizeof(kTestData)); - VerifyOrDie(err == CHIP_NO_ERROR); - - vTaskDelay(pdMS_TO_TICKS(50)); - } - - err = ReadConfigValueBin(kConfigKey_MfrDeviceCert, buf, sizeof(buf), dataLen); - VerifyOrDie(err == CHIP_NO_ERROR); - - VerifyOrDie(dataLen == sizeof(kTestData)); - VerifyOrDie(memcmp(buf, kTestData, dataLen) == 0); - } -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/nRF5Config.h b/src/platform/nRF5/nRF5Config.h deleted file mode 100644 index 052119c5b4b450..00000000000000 --- a/src/platform/nRF5/nRF5Config.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019-2020 Google LLC. - * Copyright (c) 2018 Nest Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Utilities for accessing persisted device configuration on - * platforms based on the Nordic nRF5 SDK. - */ - -#pragma once - -#include - -#include "FreeRTOS.h" -#include "fds.h" -#include "semphr.h" - -#include - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -constexpr inline uint32_t NRF5ConfigKey(uint16_t fileId, uint16_t recordId) -{ - return static_cast(fileId) << 16 | recordId; -} - -/** - * Provides functions and definitions for accessing persisted device configuration - * on platforms based on the Nordic nRF5 SDK. - * - * This implementation uses the Nordic Flash Data Storage (FDS) library as the - * underlying storage layer. - * - * NOTE: This class is designed to be mixed-in to the concrete subclass of the - * GenericConfigurationManagerImpl<> template. When used this way, the class - * naturally provides implementations for the delegated members referenced by - * the template class (e.g. the ReadConfigValue() method). - */ -class NRF5Config -{ -public: - // *** CAUTION ***: Changing the FDS file or record ids of these values will *break* existing devices. - - // Limits/definitions imposed by the Nordic SDK - static constexpr uint16_t kFDSFileIdMin = 0x0000; /**< Minimum value that can be used for a FDS file id (per Nordic SDK) */ - static constexpr uint16_t kFDSFileIdMax = 0xBFFF; /**< Maximum value that can be used for a FDS file id (per Nordic SDK) */ - static constexpr uint16_t kFDSRecordKeyMin = - 0x0001; /**< Minimum value that can be used for a FDS record key (per Nordic SDK) */ - static constexpr uint16_t kFDSRecordKeyMax = - 0xBFFF; /**< Maximum value that can be used for a FDS record key (per Nordic SDK) */ - - // FDS file ids used by the CHIP Device Layer - static constexpr uint16_t kFileId_ChipFactory = 0x235A; /**< FDS file containing persistent config values set at manufacturing - * time. Retained during factory reset. */ - static constexpr uint16_t kFileId_ChipConfig = 0x235B; /**< FDS file containing dynamic config values set at runtime. - * Cleared during factory reset. */ - static constexpr uint16_t kFileId_ChipCounter = 0x235C; /**< FDS file containing dynamic counter values set at runtime. - * Retained during factory reset. */ - - // API data type used to represent the combination of a FDS file id and record key. - using Key = uint32_t; - - // Key definitions for well-known configuration values. - static constexpr Key kConfigKey_SerialNum = NRF5ConfigKey(kFileId_ChipFactory, 0x0001); - static constexpr Key kConfigKey_MfrDeviceId = NRF5ConfigKey(kFileId_ChipFactory, 0x0002); - static constexpr Key kConfigKey_MfrDeviceCert = NRF5ConfigKey(kFileId_ChipFactory, 0x0003); - static constexpr Key kConfigKey_MfrDevicePrivateKey = NRF5ConfigKey(kFileId_ChipFactory, 0x0004); - static constexpr Key kConfigKey_ManufacturingDate = NRF5ConfigKey(kFileId_ChipFactory, 0x0005); - static constexpr Key kConfigKey_SetupPinCode = NRF5ConfigKey(kFileId_ChipFactory, 0x0006); - static constexpr Key kConfigKey_FabricId = NRF5ConfigKey(kFileId_ChipConfig, 0x0007); - static constexpr Key kConfigKey_ServiceConfig = NRF5ConfigKey(kFileId_ChipConfig, 0x0008); - static constexpr Key kConfigKey_PairedAccountId = NRF5ConfigKey(kFileId_ChipConfig, 0x0009); - static constexpr Key kConfigKey_ServiceId = NRF5ConfigKey(kFileId_ChipConfig, 0x000A); - static constexpr Key kConfigKey_FabricSecret = NRF5ConfigKey(kFileId_ChipConfig, 0x000B); - static constexpr Key kConfigKey_LastUsedEpochKeyId = NRF5ConfigKey(kFileId_ChipConfig, 0x000C); - static constexpr Key kConfigKey_FailSafeArmed = NRF5ConfigKey(kFileId_ChipConfig, 0x000D); - static constexpr Key kConfigKey_GroupKey = NRF5ConfigKey(kFileId_ChipConfig, 0x000E); - static constexpr Key kConfigKey_ProductRevision = NRF5ConfigKey(kFileId_ChipFactory, 0x000F); - static constexpr Key kConfigKey_MfrDeviceICACerts = NRF5ConfigKey(kFileId_ChipFactory, 0x0010); - static constexpr Key kConfigKey_OperationalDeviceId = NRF5ConfigKey(kFileId_ChipConfig, 0x0011); - static constexpr Key kConfigKey_OperationalDeviceCert = NRF5ConfigKey(kFileId_ChipConfig, 0x0012); - static constexpr Key kConfigKey_OperationalDeviceICACerts = NRF5ConfigKey(kFileId_ChipConfig, 0x0013); - static constexpr Key kConfigKey_OperationalDevicePrivateKey = NRF5ConfigKey(kFileId_ChipConfig, 0x0014); - static constexpr Key kConfigKey_SetupDiscriminator = NRF5ConfigKey(kFileId_ChipFactory, 0x0015); - - // Range of FDS record keys used to store CHIP persisted counter values. - static constexpr uint16_t kPersistedCounterRecordKeyBase = kFDSRecordKeyMin; - /**< Base record key for records containing CHIP persisted counter values. - * The CHIP counter id is added to this value to form the FDS record key.*/ - static constexpr uint16_t kPersistedCounterRecordKeyMax = kFDSRecordKeyMax; - /**< Max record key for records containing CHIP persisted counter values. */ - - static CHIP_ERROR Init(void); - - // Configuration methods used by the GenericConfigurationManagerImpl<> template. - static CHIP_ERROR ReadConfigValue(Key key, bool & val); - static CHIP_ERROR ReadConfigValue(Key key, uint32_t & val); - static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val); - static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen); - static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen); - static CHIP_ERROR WriteConfigValue(Key key, bool val); - static CHIP_ERROR WriteConfigValue(Key key, uint32_t val); - static CHIP_ERROR WriteConfigValue(Key key, uint64_t val); - static CHIP_ERROR WriteConfigValueStr(Key key, const char * str); - static CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen); - static CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen); - static CHIP_ERROR ClearConfigValue(Key key); - static bool ConfigValueExists(Key key); - static CHIP_ERROR FactoryResetConfig(void); - - static void RunConfigUnitTest(void); - -protected: - struct FDSAsyncOp - { - enum - { - kAddRecord = 0, - kUpdateRecord, - kAddOrUpdateRecord, - kDeleteRecord, - kDeleteRecordByKey, - kDeleteFile, - kGC, - kInit, - kWaitQueueSpaceAvailable - }; - - fds_record_desc_t RecordDesc; - const uint8_t * RecordData; - uint32_t RecordDataLengthWords; - ret_code_t Result; - uint16_t FileId; - uint16_t RecordKey; - uint8_t OpType; - - inline FDSAsyncOp(uint8_t opType) : OpType(opType) {} - }; - - using ForEachRecordFunct = std::function; - - static constexpr uint16_t kFDSWordSize = 4; - - static FDSAsyncOp * volatile sActiveAsyncOp; - static SemaphoreHandle_t sAsyncOpCompletionSem; - - static constexpr uint16_t GetFileId(uint32_t key); - static constexpr uint16_t GetRecordKey(uint32_t key); - static CHIP_ERROR OpenRecord(NRF5Config::Key key, fds_record_desc_t & recDesc, fds_flash_record_t & rec); - static CHIP_ERROR ForEachRecord(uint16_t fileId, uint16_t recordKey, ForEachRecordFunct funct); - static CHIP_ERROR DoAsyncFDSOp(FDSAsyncOp & asyncOp); - static constexpr uint16_t FDSWords(size_t s); - -private: - static void HandleFDSEvent(const fds_evt_t * fdsEvent); - static CHIP_ERROR MapFDSError(ret_code_t fdsRes); -}; - -/** - * Extract an FDS file id from a Key value. - */ -inline constexpr uint16_t NRF5Config::GetFileId(Key key) -{ - return static_cast(key >> 16); -} - -/** - * Extract an FDS record key from a Key value. - */ -inline constexpr uint16_t NRF5Config::GetRecordKey(Key key) -{ - return static_cast(key); -} - -/** - * Number of FDS words needed to hold a given size object. - */ -inline constexpr uint16_t NRF5Config::FDSWords(size_t s) -{ - // TODO: This cast does not seem safe from overflow. - // https://github.com/project-chip/connectedhomeip/issues/2570 - return static_cast((s + (kFDSWordSize - 1)) / kFDSWordSize); -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/nRF5Utils.cpp b/src/platform/nRF5/nRF5Utils.cpp deleted file mode 100644 index 19f661c90cf300..00000000000000 --- a/src/platform/nRF5/nRF5Utils.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Utilities for working with the Nordic nRF5 SDK. - */ - -#include -#include -#include - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -#define CHIP_DEVICE_CONFIG_NRF5_ERROR_MIN 1 -#define CHIP_DEVICE_CONFIG_NRF5_ERROR_MAX 1000000 -#define CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MIN 10000000 -#define CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MAX 10000999 -/** - * Register a text error formatter for nRF SDK errors. - */ -void RegisterNRFErrorFormatter(void) -{ - static ErrorFormatter sNRFErrorFormatter = { FormatNRFError, NULL }; - - RegisterErrorFormatter(&sNRFErrorFormatter); -} - -/** - * Given an nRF SDK error, returns a human-readable NULL-terminated C string - * describing the error. - * - * @param[in] buf Buffer into which the error string will be placed. - * @param[in] bufSize Size of the supplied buffer in bytes. - * @param[in] err The error to be described. - * - * @return true If a descriptions string was written into the supplied buffer. - * @return false If the supplied error was not an nRF SDK error. - * - */ -bool FormatNRFError(char * buf, uint16_t bufSize, int32_t err) -{ - const char * subsys = NULL; - - if (err >= CHIP_DEVICE_CONFIG_NRF5_ERROR_MIN && err <= CHIP_DEVICE_CONFIG_NRF5_ERROR_MAX) - { - subsys = "nRF"; - } - - else if (err >= CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MIN && err <= CHIP_DEVICE_CONFIG_NRF5_FDS_ERROR_MAX) - { - subsys = "nRF-FDS"; - } - - else - { - return false; - } - - FormatError(buf, bufSize, subsys, err, NULL); - - return true; -} - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/nRF5/nRF5Utils.h b/src/platform/nRF5/nRF5Utils.h deleted file mode 100644 index 04b02960dab330..00000000000000 --- a/src/platform/nRF5/nRF5Utils.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * Utilities for working with the Nordic nRF5 SDK. - */ - -#pragma once - -namespace chip { -namespace DeviceLayer { -namespace Internal { - -void RegisterNRFErrorFormatter(void); -bool FormatNRFError(char * buf, uint16_t bufSize, int32_t err); - -} // namespace Internal -} // namespace DeviceLayer -} // namespace chip diff --git a/third_party/nrf5_sdk/BUILD.gn b/third_party/nrf5_sdk/BUILD.gn deleted file mode 100644 index 96247fc8ffebe6..00000000000000 --- a/third_party/nrf5_sdk/BUILD.gn +++ /dev/null @@ -1,28 +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. - -import("//build_overrides/nrf5_sdk.gni") - -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") - -declare_args() { - # Build target to use for nRF5 SDK. Use this to set global SDK defines. - nrf5_sdk_target = "" -} - -assert(nrf5_sdk_target != "", "nrf5_sdk_target must be specified") - -group("nrf5_sdk") { - public_deps = [ nrf5_sdk_target ] -} diff --git a/third_party/nrf5_sdk/nrf5_executable.gni b/third_party/nrf5_sdk/nrf5_executable.gni deleted file mode 100644 index 7a83d38bf02c95..00000000000000 --- a/third_party/nrf5_sdk/nrf5_executable.gni +++ /dev/null @@ -1,54 +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. - -import("//build/toolchain/flashable_executable.gni") - -template("nrf5_executable") { - objcopy_image_name = invoker.output_name + ".hex" - objcopy_image_format = "ihex" - objcopy = "arm-none-eabi-objcopy" - - # Copy flashing dependencies, including the softdevice image, to the output - # directory, so that the output is collectively self-contained; this allows - # flashing to work reliably even if the build and flashing steps take place - # on different machines or in different containers. - - flashing_runtime_target = target_name + ".flashing_runtime" - softdevice_dir = "${invoker.nrf5_sdk_root}/components/softdevice/s140/hex" - softdevice_file = "s140_nrf52_${invoker.nrf5_sdk_version}_softdevice.hex" - copy(flashing_runtime_target) { - sources = [ - "${chip_root}/scripts/flashing/firmware_utils.py", - "${chip_root}/scripts/flashing/nrf5_firmware_utils.py", - "${softdevice_dir}/${softdevice_file}", - ] - outputs = [ "${root_out_dir}/{{source_file_part}}" ] - } - - flashing_script_generator = - "${chip_root}/scripts/flashing/gen_flashing_script.py" - flashing_script_name = invoker.output_name + ".flash.py" - flashing_options = [ - "nrf5", - "--softdevice", - rebase_path("${root_out_dir}/${softdevice_file}", - root_out_dir, - root_build_dir), - ] - - flashable_executable(target_name) { - forward_variables_from(invoker, "*") - data_deps = [ ":${flashing_runtime_target}" ] - } -} diff --git a/third_party/nrf5_sdk/nrf5_sdk.gni b/third_party/nrf5_sdk/nrf5_sdk.gni deleted file mode 100644 index fa643d25258a71..00000000000000 --- a/third_party/nrf5_sdk/nrf5_sdk.gni +++ /dev/null @@ -1,439 +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. - -import("//build_overrides/jlink.gni") -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -declare_args() { - # Location of the nRF5 SDK. - nrf5_sdk_root = getenv("NRF5_SDK_ROOT") - nrf5_sdk_version = "7.0.1" -} - -assert(nrf5_sdk_root != "", "nrf5_sdk_root must be specified") - -# Defines an nRF SDK build target. -# -# Parameters: -# nrf5_sdk_root - The location of the nRF SDK. -# sources - Extra source files to build. -template("nrf5_sdk") { - if (defined(invoker.nrf5_sdk_root)) { - nrf5_sdk_root = invoker.nrf5_sdk_root - } - - assert(nrf5_sdk_root != "", "nrf5_sdk_root must be specified") - - sdk_target_name = target_name - - config("${sdk_target_name}_config") { - include_dirs = [] - if (defined(invoker.include_dirs)) { - include_dirs += invoker.include_dirs - } - - # We want to treat SDK headers as system headers, so that warnings in those - # headers are not fatal. Therefore don't add them directly to include_dirs; - # we will add them to cflags below instead. - _sdk_include_dirs = [ - "${nrf5_sdk_root}/components", - "${nrf5_sdk_root}/components/boards", - "${nrf5_sdk_root}/components/ble/ble_advertising", - "${nrf5_sdk_root}/components/ble/common", - "${nrf5_sdk_root}/components/ble/nrf_ble_gatt", - "${nrf5_sdk_root}/components/libraries/atomic", - "${nrf5_sdk_root}/components/libraries/atomic_fifo", - "${nrf5_sdk_root}/components/libraries/balloc", - "${nrf5_sdk_root}/components/libraries/bsp", - "${nrf5_sdk_root}/components/libraries/button", - "${nrf5_sdk_root}/components/libraries/crc16", - "${nrf5_sdk_root}/components/libraries/delay", - "${nrf5_sdk_root}/components/libraries/experimental_section_vars", - "${nrf5_sdk_root}/components/libraries/fds", - "${nrf5_sdk_root}/components/libraries/fifo", - "${nrf5_sdk_root}/components/libraries/fstorage", - "${nrf5_sdk_root}/components/libraries/log", - "${nrf5_sdk_root}/components/libraries/log/src", - "${nrf5_sdk_root}/components/libraries/memobj", - "${nrf5_sdk_root}/components/libraries/mem_manager", - "${nrf5_sdk_root}/components/libraries/mutex", - "${nrf5_sdk_root}/components/libraries/queue", - "${nrf5_sdk_root}/components/libraries/usbd", - "${nrf5_sdk_root}/components/libraries/usbd/class/cdc", - "${nrf5_sdk_root}/components/libraries/ringbuf", - "${nrf5_sdk_root}/components/libraries/bootloader/dfu", - "${nrf5_sdk_root}/components/libraries/stack_info", - "${nrf5_sdk_root}/components/libraries/strerror", - "${nrf5_sdk_root}/components/libraries/timer", - "${nrf5_sdk_root}/components/libraries/util", - "${nrf5_sdk_root}/components/softdevice/common", - "${nrf5_sdk_root}/components/softdevice/s140/headers", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf52", - "${nrf5_sdk_root}/components/softdevice/mbr/nrf52840/headers", - "${nrf5_sdk_root}/components/toolchain/cmsis/include", - "${nrf5_sdk_root}/config/nrf52840/config", - "${nrf5_sdk_root}/external/fprintf", - "${nrf5_sdk_root}/external/freertos/config", - "${nrf5_sdk_root}/external/freertos/portable/CMSIS/nrf52", - "${nrf5_sdk_root}/external/freertos/portable/GCC/nrf52", - "${nrf5_sdk_root}/external/freertos/source/include", - "${nrf5_sdk_root}/external/openthread/nrf_security/config", - "${nrf5_sdk_root}/external/openthread/nrf_security/include", - "${nrf5_sdk_root}/external/openthread/nrf_security/mbedtls_plat_config", - "${nrf5_sdk_root}/external/openthread/nrf_security/nrf_cc310_plat/include", - "${nrf5_sdk_root}/integration/nrfx", - "${nrf5_sdk_root}/integration/nrfx/legacy", - "${nrf5_sdk_root}/modules/nrfx", - "${nrf5_sdk_root}/modules/nrfx/drivers/include", - "${nrf5_sdk_root}/modules/nrfx/hal", - "${nrf5_sdk_root}/modules/nrfx/mdk", - ] - - lib_dirs = [ "${nrf5_sdk_root}/modules/nrfx/mdk" ] - - libs = [ - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedcrypto_glue.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedcrypto_glue.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedcrypto_glue_cc310.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedcrypto_glue_vanilla.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedcrypto_cc310_backend.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedcrypto_vanilla_backend.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedtls_base_vanilla.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedtls_tls_vanilla.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libmbedtls_x509_vanilla.a", - "${nrf5_sdk_root}/external/openthread/nrf_security/lib/libnrf_cc310_platform_0.9.1.a", - ] - - defines = [ - "NRF52840_XXAA", - "BOARD_PCA10056", - "BSP_DEFINES_ONLY", - "CONFIG_GPIO_AS_PINRESET", - "FLOAT_ABI_HARD", - "__HEAP_SIZE=40960", - "__STACK_SIZE=8192", - "PRINTF_DISABLE_SUPPORT_EXPONENTIAL", - "S140", - "ENABLE_FEM", - "FREERTOS", - "MBEDTLS_CONFIG_FILE=\"nrf-config.h\"", - "MBEDTLS_USER_CONFIG_FILE=\"nrf52840-mbedtls-config.h\"", - "MULTIPROTOCOL_802154_CONFIG_PRESENT", - "NRFX_PRS_ENABLED=0", - "NRF_SD_BLE_API_VERSION=7", - "SOFTDEVICE_PRESENT=1", - ] - if (defined(invoker.defines)) { - defines += invoker.defines - } - - cflags = [ - "-Wno-array-bounds", - "-Wno-unused-function", - ] - - # Now add our "system-header" include dirs - foreach(include_dir, _sdk_include_dirs) { - cflags += [ "-isystem" + rebase_path(include_dir, root_build_dir) ] - } - } - - # TODO - Break up this monolith and make it configurable. - source_set(sdk_target_name) { - forward_variables_from(invoker, "*") - - if (!defined(sources)) { - sources = [] - } - - sources += [ - "${nrf5_sdk_root}/components/ble/common/ble_advdata.c", - "${nrf5_sdk_root}/components/ble/common/ble_advdata.h", - "${nrf5_sdk_root}/components/ble/common/ble_srv_common.c", - "${nrf5_sdk_root}/components/ble/common/ble_srv_common.h", - "${nrf5_sdk_root}/components/ble/nrf_ble_gatt/nrf_ble_gatt.c", - "${nrf5_sdk_root}/components/ble/nrf_ble_gatt/nrf_ble_gatt.h", - "${nrf5_sdk_root}/components/boards/boards.c", - "${nrf5_sdk_root}/components/boards/boards.h", - "${nrf5_sdk_root}/components/boards/pca10056.h", - "${nrf5_sdk_root}/components/libraries/atomic/nrf_atomic.c", - "${nrf5_sdk_root}/components/libraries/atomic/nrf_atomic.h", - "${nrf5_sdk_root}/components/libraries/atomic/nrf_atomic_internal.h", - "${nrf5_sdk_root}/components/libraries/atomic_fifo/nrf_atfifo.c", - "${nrf5_sdk_root}/components/libraries/atomic_fifo/nrf_atfifo.h", - "${nrf5_sdk_root}/components/libraries/atomic_fifo/nrf_atfifo_internal.h", - "${nrf5_sdk_root}/components/libraries/balloc/nrf_balloc.c", - "${nrf5_sdk_root}/components/libraries/balloc/nrf_balloc.h", - "${nrf5_sdk_root}/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.h", - "${nrf5_sdk_root}/components/libraries/button/app_button.c", - "${nrf5_sdk_root}/components/libraries/button/app_button.h", - "${nrf5_sdk_root}/components/libraries/crc16/crc16.c", - "${nrf5_sdk_root}/components/libraries/delay/nrf_delay.h", - "${nrf5_sdk_root}/components/libraries/experimental_section_vars/nrf_section.h", - "${nrf5_sdk_root}/components/libraries/experimental_section_vars/nrf_section_iter.c", - "${nrf5_sdk_root}/components/libraries/experimental_section_vars/nrf_section_iter.h", - "${nrf5_sdk_root}/components/libraries/fds/fds.c", - "${nrf5_sdk_root}/components/libraries/fds/fds.h", - "${nrf5_sdk_root}/components/libraries/fds/fds_internal_defs.h", - "${nrf5_sdk_root}/components/libraries/fifo/app_fifo.c", - "${nrf5_sdk_root}/components/libraries/fifo/app_fifo.h", - "${nrf5_sdk_root}/components/libraries/fstorage/nrf_fstorage.c", - "${nrf5_sdk_root}/components/libraries/fstorage/nrf_fstorage.h", - "${nrf5_sdk_root}/components/libraries/fstorage/nrf_fstorage_sd.c", - "${nrf5_sdk_root}/components/libraries/fstorage/nrf_fstorage_sd.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_backend_interface.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_backend_rtt.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_backend_uart.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_ctrl.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_default_backends.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_instance.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_str_formatter.h", - "${nrf5_sdk_root}/components/libraries/log/nrf_log_types.h", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_backend_rtt.c", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_backend_serial.c", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_backend_serial.h", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_ctrl_internal.h", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_default_backends.c", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_frontend.c", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_internal.h", - "${nrf5_sdk_root}/components/libraries/log/src/nrf_log_str_formatter.c", - "${nrf5_sdk_root}/components/libraries/mem_manager/mem_manager.c", - "${nrf5_sdk_root}/components/libraries/mem_manager/mem_manager.h", - "${nrf5_sdk_root}/components/libraries/memobj/nrf_memobj.c", - "${nrf5_sdk_root}/components/libraries/memobj/nrf_memobj.h", - "${nrf5_sdk_root}/components/libraries/queue/nrf_queue.c", - "${nrf5_sdk_root}/components/libraries/queue/nrf_queue.h", - "${nrf5_sdk_root}/components/libraries/ringbuf/nrf_ringbuf.c", - "${nrf5_sdk_root}/components/libraries/ringbuf/nrf_ringbuf.h", - "${nrf5_sdk_root}/components/libraries/strerror/nrf_strerror.c", - "${nrf5_sdk_root}/components/libraries/strerror/nrf_strerror.h", - "${nrf5_sdk_root}/components/libraries/timer/app_timer.h", - "${nrf5_sdk_root}/components/libraries/timer/app_timer_freertos.c", - "${nrf5_sdk_root}/components/libraries/uart/app_uart_fifo.c", - "${nrf5_sdk_root}/components/libraries/uart/retarget.c", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_class_base.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_core.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_descriptor.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_langid.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_request.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_serial_num.h", - "${nrf5_sdk_root}/components/libraries/usbd/app_usbd_types.h", - "${nrf5_sdk_root}/components/libraries/usbd/class/cdc/acm/app_usbd_cdc_acm.h", - "${nrf5_sdk_root}/components/libraries/usbd/class/cdc/acm/app_usbd_cdc_acm_internal.h", - "${nrf5_sdk_root}/components/libraries/usbd/class/cdc/app_usbd_cdc_desc.h", - "${nrf5_sdk_root}/components/libraries/usbd/class/cdc/app_usbd_cdc_types.h", - "${nrf5_sdk_root}/components/libraries/util/app_error.c", - "${nrf5_sdk_root}/components/libraries/util/app_error.h", - "${nrf5_sdk_root}/components/libraries/util/app_error_handler_gcc.c", - "${nrf5_sdk_root}/components/libraries/util/app_error_weak.c", - "${nrf5_sdk_root}/components/libraries/util/app_error_weak.h", - "${nrf5_sdk_root}/components/libraries/util/app_util.h", - "${nrf5_sdk_root}/components/libraries/util/app_util_platform.c", - "${nrf5_sdk_root}/components/libraries/util/app_util_platform.h", - "${nrf5_sdk_root}/components/libraries/util/nordic_common.h", - "${nrf5_sdk_root}/components/libraries/util/nrf_assert.c", - "${nrf5_sdk_root}/components/libraries/util/nrf_assert.h", - "${nrf5_sdk_root}/components/libraries/util/nrf_bitmask.h", - "${nrf5_sdk_root}/components/libraries/util/sdk_common.h", - "${nrf5_sdk_root}/components/libraries/util/sdk_errors.h", - "${nrf5_sdk_root}/components/libraries/util/sdk_macros.h", - "${nrf5_sdk_root}/components/libraries/util/sdk_os.h", - "${nrf5_sdk_root}/components/libraries/util/sdk_resources.h", - "${nrf5_sdk_root}/components/softdevice/common/nrf_sdh.c", - "${nrf5_sdk_root}/components/softdevice/common/nrf_sdh.h", - "${nrf5_sdk_root}/components/softdevice/common/nrf_sdh_ble.c", - "${nrf5_sdk_root}/components/softdevice/common/nrf_sdh_ble.h", - "${nrf5_sdk_root}/components/softdevice/common/nrf_sdh_soc.c", - "${nrf5_sdk_root}/components/softdevice/common/nrf_sdh_soc.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_err.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_gap.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_gatt.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_gattc.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_gatts.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_hci.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_l2cap.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_ranges.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/ble_types.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf52/nrf_mbr.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_error.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_error_sdm.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_error_soc.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_nvic.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_sd_def.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_sdm.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_soc.h", - "${nrf5_sdk_root}/components/softdevice/s140/headers/nrf_svc.h", - "${nrf5_sdk_root}/components/toolchain/cmsis/include/cmsis_gcc.h", - "${nrf5_sdk_root}/components/toolchain/cmsis/include/core_cm4.h", - "${nrf5_sdk_root}/components/toolchain/cmsis/include/core_cmFunc.h", - "${nrf5_sdk_root}/components/toolchain/cmsis/include/core_cmInstr.h", - "${nrf5_sdk_root}/components/toolchain/cmsis/include/core_cmSimd.h", - "${nrf5_sdk_root}/config/nrf52840/config/sdk_config.h", - "${nrf5_sdk_root}/external/fprintf/nrf_fprintf.c", - "${nrf5_sdk_root}/external/fprintf/nrf_fprintf.h", - "${nrf5_sdk_root}/external/fprintf/nrf_fprintf_format.c", - "${nrf5_sdk_root}/external/fprintf/nrf_fprintf_format.h", - "${nrf5_sdk_root}/external/freertos/portable/CMSIS/nrf52/port_cmsis.c", - "${nrf5_sdk_root}/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c", - "${nrf5_sdk_root}/external/freertos/portable/CMSIS/nrf52/portmacro_cmsis.h", - "${nrf5_sdk_root}/external/freertos/portable/GCC/nrf52/port.c", - "${nrf5_sdk_root}/external/freertos/portable/GCC/nrf52/portmacro.h", - "${nrf5_sdk_root}/external/freertos/source/croutine.c", - "${nrf5_sdk_root}/external/freertos/source/event_groups.c", - "${nrf5_sdk_root}/external/freertos/source/include/FreeRTOS.h", - "${nrf5_sdk_root}/external/freertos/source/include/croutine.h", - "${nrf5_sdk_root}/external/freertos/source/include/deprecated_definitions.h", - "${nrf5_sdk_root}/external/freertos/source/include/event_groups.h", - "${nrf5_sdk_root}/external/freertos/source/include/list.h", - "${nrf5_sdk_root}/external/freertos/source/include/mpu_wrappers.h", - "${nrf5_sdk_root}/external/freertos/source/include/portable.h", - "${nrf5_sdk_root}/external/freertos/source/include/projdefs.h", - "${nrf5_sdk_root}/external/freertos/source/include/queue.h", - "${nrf5_sdk_root}/external/freertos/source/include/semphr.h", - "${nrf5_sdk_root}/external/freertos/source/include/stack_macros.h", - "${nrf5_sdk_root}/external/freertos/source/include/stream_buffer.h", - "${nrf5_sdk_root}/external/freertos/source/include/task.h", - "${nrf5_sdk_root}/external/freertos/source/include/timers.h", - "${nrf5_sdk_root}/external/freertos/source/list.c", - "${nrf5_sdk_root}/external/freertos/source/portable/MemMang/heap_3.c", - "${nrf5_sdk_root}/external/freertos/source/queue.c", - "${nrf5_sdk_root}/external/freertos/source/stream_buffer.c", - "${nrf5_sdk_root}/external/freertos/source/tasks.c", - "${nrf5_sdk_root}/external/freertos/source/timers.c", - "${nrf5_sdk_root}/external/openthread/nrf_security/config/nrf-config.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/aes.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/aes_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/asn1.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/bignum.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ccm.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ccm_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/certs.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/check_config.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/cipher.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/cmac.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/cmac_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ctr_drbg.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/debug.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/dhm.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/dhm_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ecdh.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ecdsa.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ecp.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ecp_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/entropy.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/entropy_poll.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/error.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/hkdf.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/md.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/net_sockets.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/pem.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/pk.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/pkcs5.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/platform.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/platform_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/platform_util.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/sha256.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/sha256_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ssl.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ssl_ciphersuites.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/ssl_cookie.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/threading.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/threading_alt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/x509.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/x509_crl.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/include/mbedtls/x509_crt.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/mbedtls_plat_config/nrf52840-mbedtls-config.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/nrf_cc310_plat/include/nrf_cc310_platform_abort.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/nrf_cc310_plat/include/nrf_cc310_platform_defines.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/nrf_cc310_plat/include/nrf_cc310_platform_mutex.h", - "${nrf5_sdk_root}/external/openthread/nrf_security/nrf_cc310_plat/src/nrf_cc310_platform_abort_freertos.c", - "${nrf5_sdk_root}/external/openthread/nrf_security/nrf_cc310_plat/src/nrf_cc310_platform_mutex_freertos.c", - "${nrf5_sdk_root}/integration/nrfx/legacy/apply_old_config.h", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_clock.c", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_clock.h", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_gpiote.h", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_power.h", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_rng.c", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_uart.c", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_uart.h", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_usbd.h", - "${nrf5_sdk_root}/integration/nrfx/legacy/nrf_drv_usbd_errata.h", - "${nrf5_sdk_root}/integration/nrfx/nrfx_config.h", - "${nrf5_sdk_root}/integration/nrfx/nrfx_glue.h", - "${nrf5_sdk_root}/integration/nrfx/nrfx_log.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/include/nrfx_clock.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/include/nrfx_gpiote.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/include/nrfx_power.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/include/nrfx_power_clock.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/include/nrfx_spis.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/include/nrfx_usbd.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/nrfx_common.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/nrfx_errors.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/nrfx_clock.c", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/nrfx_gpiote.c", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/nrfx_power.c", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/nrfx_uart.c", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/nrfx_uarte.c", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/nrfx_usbd_errata.h", - "${nrf5_sdk_root}/modules/nrfx/drivers/src/prs/nrfx_prs.c", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_clock.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_egu.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_gpio.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_gpiote.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_power.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_ppi.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_radio.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_rtc.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_spis.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_temp.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_timer.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_uart.h", - "${nrf5_sdk_root}/modules/nrfx/hal/nrf_usbd.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/compiler_abstraction.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/gcc_startup_nrf52840.S", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf51_to_nrf52840.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf52840.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf52840_bitfields.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf52840_peripherals.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf52_to_nrf52840.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/nrf_peripherals.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/system_nrf.h", - "${nrf5_sdk_root}/modules/nrfx/mdk/system_nrf52840.c", - "${nrf5_sdk_root}/modules/nrfx/mdk/system_nrf52840.h", - "${nrf5_sdk_root}/modules/nrfx/nrfx.h", - "${nrf5_sdk_root}/modules/nrfx/soc/nrfx_atomic.h", - "${nrf5_sdk_root}/modules/nrfx/soc/nrfx_coredep.h", - "${nrf5_sdk_root}/modules/nrfx/soc/nrfx_irqs.h", - "${nrf5_sdk_root}/modules/nrfx/soc/nrfx_irqs_nrf52840.h", - ] - - public_deps = [ - "${openthread_root}/include/openthread:openthread_config", - "${segger_rtt_root}:segger_rtt", - "${segger_rtt_root}:segger_rtt_printf", - "${segger_rtt_root}:segger_rtt_syscalls", - ] - - if (!defined(public_configs)) { - public_configs = [] - } - - public_configs += [ ":${sdk_target_name}_config" ] - } -} diff --git a/third_party/openthread/platforms/nrf528xx/BUILD.gn b/third_party/openthread/platforms/nrf528xx/BUILD.gn deleted file mode 100644 index ef69f88c7fd7cb..00000000000000 --- a/third_party/openthread/platforms/nrf528xx/BUILD.gn +++ /dev/null @@ -1,201 +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. - -import("//build_overrides/nrf5_sdk.gni") -import("//build_overrides/openthread.gni") - -import("${nrf5_sdk_build_root}/nrf5_sdk.gni") - -# TODO(spang): Clean this up. We're mixing the vanilla Nordic SDK with forked -# SDK code from OpenThread. See use_openthread_radio_driver below. - -nrf528xx_sdk_common = [ - "${openthread_root}/examples/platforms/nrf528xx/src/misc.c", - "${openthread_root}/examples/platforms/nrf528xx/src/radio.c", - "${openthread_root}/examples/platforms/nrf528xx/src/alarm.c", - "${openthread_root}/examples/platforms/nrf528xx/src/diag.c", - "${openthread_root}/examples/platforms/nrf528xx/src/entropy.c", - "${openthread_root}/examples/platforms/nrf528xx/src/fem.c", - "${openthread_root}/examples/platforms/nrf528xx/src/flash.c", - "${openthread_root}/examples/platforms/nrf528xx/src/logging.c", - "${openthread_root}/examples/platforms/nrf528xx/src/system.c", - "${openthread_root}/examples/platforms/nrf528xx/src/temp.c", - "${openthread_root}/examples/platforms/nrf528xx/src/platform-fem.h", - "${openthread_root}/examples/platforms/nrf528xx/src/platform-nrf5.h", -] - -copy("copy_nrf52840_headers") { - sources = [ - "${openthread_root}/examples/platforms/nrf528xx/src/platform-softdevice.h", - ] - - outputs = - [ "${root_gen_dir}/include/openthread/platform/{{source_file_part}}" ] -} - -static_library("libopenthread-nrf52840-softdevice-sdk") { - sources = nrf528xx_sdk_common - sources += [ - "${openthread_root}/examples/platforms/nrf528xx/src/flash_sd.c", - "${openthread_root}/examples/platforms/nrf528xx/src/platform-softdevice.h", - "${openthread_root}/examples/platforms/nrf528xx/src/softdevice.c", - "${openthread_root}/examples/platforms/nrf528xx/src/softdevice.h", - ] - public_deps = [ - ":copy_nrf52840_headers", - ":libnordicsemi_nrf52840_radio_driver_softdevice", - ":libopenthread-nrf52840-transport", - "${nrf5_sdk_build_root}:nrf5_sdk", - "..:libopenthread-platform", - "..:libopenthread-platform-utils", - ] - cflags = [ "-Wno-unused-but-set-variable" ] -} - -config("libopenthread-nrf52840-transport_config") { - defines = [ "UART_AS_SERIAL_TRANSPORT=1" ] -} - -static_library("libopenthread-nrf52840-transport") { - sources = [ - "${openthread_root}/examples/platforms/nrf528xx/src/platform-nrf5-transport.h", - "${openthread_root}/examples/platforms/nrf528xx/src/transport/spi-slave.c", - "${openthread_root}/examples/platforms/nrf528xx/src/transport/transport-drivers.h", - "${openthread_root}/examples/platforms/nrf528xx/src/transport/transport.c", - "${openthread_root}/examples/platforms/nrf528xx/src/transport/uart.c", - "${openthread_root}/examples/platforms/nrf528xx/src/transport/usb-cdc-uart.c", - ] - - public_configs = [ ":libopenthread-nrf52840-transport_config" ] - - public_deps = [ - ":libnordicsemi_nrf52840", - "${nrf5_sdk_build_root}:nrf5_sdk", - "${openthread_root}/src/core:libopenthread_core_headers", - "..:libopenthread-platform", - "..:libopenthread-platform-utils", - ] -} - -declare_args() { - # Use the OpenThread copy of the 802.15.4 radio driver. - use_openthread_radio_driver = true -} - -if (use_openthread_radio_driver) { - nrf528xx_radio_driver_src = - "${openthread_root}/third_party/NordicSemiconductor/drivers/radio" -} else { - nrf528xx_radio_driver_src = - "${nrf5_sdk_root}/external/nRF-IEEE-802.15.4-radio-driver/src" -} - -nrf528xx_radio_driver_common_sources = [ - "${nrf528xx_radio_driver_src}/fal/nrf_802154_fal.c", - "${nrf528xx_radio_driver_src}/fem/three_pin_gpio/nrf_fem_three_pin_gpio.c", - "${nrf528xx_radio_driver_src}/mac_features/ack_generator/nrf_802154_ack_data.c", - "${nrf528xx_radio_driver_src}/mac_features/ack_generator/nrf_802154_ack_generator.c", - "${nrf528xx_radio_driver_src}/mac_features/ack_generator/nrf_802154_enh_ack_generator.c", - "${nrf528xx_radio_driver_src}/mac_features/ack_generator/nrf_802154_imm_ack_generator.c", - "${nrf528xx_radio_driver_src}/mac_features/nrf_802154_csma_ca.c", - "${nrf528xx_radio_driver_src}/mac_features/nrf_802154_delayed_trx.c", - "${nrf528xx_radio_driver_src}/mac_features/nrf_802154_filter.c", - "${nrf528xx_radio_driver_src}/mac_features/nrf_802154_frame_parser.c", - "${nrf528xx_radio_driver_src}/mac_features/nrf_802154_precise_ack_timeout.c", - "${nrf528xx_radio_driver_src}/nrf_802154.c", - "${nrf528xx_radio_driver_src}/nrf_802154_core.c", - "${nrf528xx_radio_driver_src}/nrf_802154_core_hooks.c", - "${nrf528xx_radio_driver_src}/nrf_802154_critical_section.c", - "${nrf528xx_radio_driver_src}/nrf_802154_debug.c", - "${nrf528xx_radio_driver_src}/nrf_802154_pib.c", - "${nrf528xx_radio_driver_src}/nrf_802154_rssi.c", - "${nrf528xx_radio_driver_src}/nrf_802154_rx_buffer.c", - "${nrf528xx_radio_driver_src}/nrf_802154_timer_coord.c", - "${nrf528xx_radio_driver_src}/platform/clock/nrf_802154_clock_sdk.c", - "${nrf528xx_radio_driver_src}/platform/coex/nrf_802154_wifi_coex_none.c", - "${nrf528xx_radio_driver_src}/platform/hp_timer/nrf_802154_hp_timer.c", - "${nrf528xx_radio_driver_src}/rsch/nrf_802154_rsch.c", - "${nrf528xx_radio_driver_src}/rsch/nrf_802154_rsch_crit_sect.c", - "${nrf528xx_radio_driver_src}/timer_scheduler/nrf_802154_timer_sched.c", - "${nrf5_sdk_root}/examples/multiprotocol/app_utils/multiprotocol_802154_config.c", - "${nrf5_sdk_root}/examples/multiprotocol/app_utils/multiprotocol_802154_config.h", -] - -nrf528xx_radio_driver_softdevice_sources = [ - "${nrf528xx_radio_driver_src}/nrf_802154_notification_swi.c", - "${nrf528xx_radio_driver_src}/nrf_802154_priority_drop_swi.c", - "${nrf528xx_radio_driver_src}/nrf_802154_request_swi.c", - "${nrf528xx_radio_driver_src}/nrf_802154_swi.c", - "${nrf528xx_radio_driver_src}/rsch/raal/softdevice/nrf_raal_softdevice.c", -] - -config("libnordicsemi_nrf52840_config") { - defines = [ "NRF_802154_PROJECT_CONFIG=\"platform-config.h\"" ] - - include_dirs = [ - "${openthread_root}/examples/platforms/nrf528xx/src", - "${openthread_root}/examples/platforms/nrf528xx/nrf52840", - ] -} - -source_set("openthread_core_config_nrf52840") { - sources = [ - "${openthread_root}/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config-check.h", - "${openthread_root}/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h", - ] - - public_configs = [ ":libnordicsemi_nrf52840_config" ] -} - -source_set("libnordicsemi_nrf52840") { - sources = [ - "${openthread_root}/examples/platforms/nrf528xx/nrf52840/platform-config.h", - "${openthread_root}/examples/platforms/nrf528xx/nrf52840/transport-config.h", - ] - - public_configs = [ ":libnordicsemi_nrf52840_config" ] -} - -config("nrf528xx_radio_driver_config") { - include_dirs = [ - "${nrf528xx_radio_driver_src}", - "${nrf528xx_radio_driver_src}/fem", - "${nrf528xx_radio_driver_src}/fem/three_pin_gpio", - "${nrf528xx_radio_driver_src}/rsch/raal", - "${nrf528xx_radio_driver_src}/rsch/raal/softdevice", - "${nrf528xx_radio_driver_src}/platform/temperature", - "${nrf528xx_radio_driver_src}/platform/lp_timer", - "${nrf5_sdk_root}/examples/multiprotocol/app_utils", - ] -} - -config("libnordicsemi_softdevice_config") { - defines = [ "RAAL_SOFTDEVICE=1" ] -} - -static_library("libnordicsemi_nrf52840_radio_driver_softdevice") { - sources = nrf528xx_radio_driver_common_sources + - nrf528xx_radio_driver_softdevice_sources - - public_configs = [ - ":nrf528xx_radio_driver_config", - ":libnordicsemi_softdevice_config", - ] - - public_deps = [ - ":libnordicsemi_nrf52840", - "${nrf5_sdk_build_root}:nrf5_sdk", - "${openthread_root}/src/core:libopenthread_core_headers", - ] -}