From cc1356036a3a7d3e2df569f41e628cb47a47640a Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Tue, 29 Jun 2021 16:58:47 +0100 Subject: [PATCH] Add Mbed os port (#7926) * Add Mbed OS into chip platforms. The platform supports the following features: - Bluetooth - WiFi - Mdns - Key/Value store The integration with network is made with the POSIX socket API * Add Mbed os third party repo * Add mbed os target config/build files * Update pigweed environment for Mbed OS * Integrate Mbed OS into chip build system * Delay MDNS server start on Mbed OS * Disable Mdns operations in WatchableEventManagerfor mbed os * Force InterfaceAddressIterator::GetPrefixLength() to 64 on Mbed OS. * Add Mbed OS shell streamer * Add Mbed OS SystemMutex implementation * Add script to build Mbed OS example * Update devcontainer to flash and debug mbed boards * Add workflow to build Mbed OS examples * Add VSCode task to build Mbed OS examples * Add Mbed OS lock app example. Note: Bluetooth autostart as there is not enough physical button on the board. This will be addressed by a subsequent update that enable capacitive button. * Add vscode debug configuration for mbed os examples --- .devcontainer/Dockerfile | 4 +- .devcontainer/devcontainer.json | 6 +- .github/workflows/examples-mbed.yaml | 82 ++ .gitignore | 1 + .gitmodules | 12 + .vscode/extensions.json | 9 + .vscode/launch.json | 120 ++ .vscode/tasks.json | 67 + config/mbed/CHIPProjectConfig.h | 28 + config/mbed/CMakeLists.txt | 277 +++++ config/mbed/chip-gn/.gn | 33 + config/mbed/chip-gn/BUILD.gn | 64 + config/mbed/chip-gn/args.gni | 32 + config/mbed/chip-gn/build | 1 + config/mbed/chip-gn/build_overrides | 1 + config/mbed/chip-gn/mbedtls/BUILD.gn | 40 + .../mbed/chip-gn/third_party/connectedhomeip | 1 + config/mbed/chip-gn/toolchain/BUILD.gn | 32 + config/mbed/mbed-util.cmake | 139 +++ config/mbed/mbedtls/chip_mbedtls_config.h | 43 + config/mbed/scripts/CY8CPROTO_062_4343W.tcl | 4 + config/mbed/scripts/DISCO_L475VG_IOT01A.tcl | 5 + examples/lock-app/mbed/.gitignore | 5 + examples/lock-app/mbed/CMakeLists.txt | 128 ++ examples/lock-app/mbed/config.in | 5 + examples/lock-app/mbed/main/AppTask.cpp | 420 +++++++ .../lock-app/mbed/main/BoltLockManager.cpp | 181 +++ examples/lock-app/mbed/main/ZclCallbacks.cpp | 68 ++ .../lock-app/mbed/main/include/AppEvent.h | 58 + examples/lock-app/mbed/main/include/AppTask.h | 73 ++ .../mbed/main/include/BoltLockManager.h | 81 ++ .../mbed/main/include/CHIPProjectConfig.h | 38 + examples/lock-app/mbed/main/main.cpp | 82 ++ examples/lock-app/mbed/mbed-os.lib | 1 + examples/lock-app/mbed/mbed_app.json | 83 ++ examples/lock-app/mbed/wifi-ism43362.lib | 1 + examples/platform/mbed/util/LEDWidget.cpp | 69 ++ .../platform/mbed/util/include/LEDWidget.h | 39 + scripts/constraints.txt | 44 +- scripts/examples/mbed_example.sh | 145 +++ scripts/python.json | 5 + scripts/requirements.mbed.txt | 2 + scripts/requirements.txt | 3 + src/app/server/Server.cpp | 4 +- src/crypto/crypto.gni | 2 +- src/inet/InetInterface.cpp | 6 + src/lib/core/core.gni | 3 +- src/lib/shell/BUILD.gn | 4 + src/lib/shell/streamer_mbed.cpp | 63 + src/lwip/BUILD.gn | 7 +- src/lwip/lwip.gni | 2 +- src/platform/BUILD.gn | 23 + src/platform/device.gni | 10 +- src/platform/mbed/BLEManagerImpl.cpp | 1075 +++++++++++++++++ src/platform/mbed/BLEManagerImpl.h | 176 +++ src/platform/mbed/BUILD.gn | 4 + src/platform/mbed/BlePlatformConfig.h | 44 + src/platform/mbed/CHIPDevicePlatformConfig.h | 48 + src/platform/mbed/CHIPDevicePlatformEvent.h | 88 ++ src/platform/mbed/CHIPPlatformConfig.h | 129 ++ .../mbed/ConfigurationManagerImpl.cpp | 129 ++ src/platform/mbed/ConfigurationManagerImpl.h | 103 ++ src/platform/mbed/ConnectivityManagerImpl.cpp | 422 +++++++ src/platform/mbed/ConnectivityManagerImpl.h | 164 +++ .../DeviceNetworkProvisioningDelegateImpl.cpp | 41 + .../DeviceNetworkProvisioningDelegateImpl.h | 43 + src/platform/mbed/InetPlatformConfig.h | 50 + .../mbed/KeyValueStoreManagerImpl.cpp | 112 ++ src/platform/mbed/KeyValueStoreManagerImpl.h | 77 ++ src/platform/mbed/Logging.cpp | 38 + src/platform/mbed/MbedConfig.cpp | 332 +++++ src/platform/mbed/MbedConfig.h | 107 ++ src/platform/mbed/MbedEventTimeout.cpp | 17 + src/platform/mbed/MbedEventTimeout.h | 45 + src/platform/mbed/PlatformManagerImpl.cpp | 287 +++++ src/platform/mbed/PlatformManagerImpl.h | 141 +++ src/platform/mbed/SystemPlatformConfig.h | 59 + src/platform/mbed/SystemTimeSupport.cpp | 129 ++ src/platform/mbed/arch.c | 76 ++ src/system/BUILD.gn | 2 + src/system/SystemConfig.h | 50 +- src/system/SystemMutex.h | 27 + src/system/WatchableSocketSelect.cpp | 4 +- src/system/system.gni | 12 +- third_party/mbed-os-posix-socket/repo | 1 + third_party/mbed-os/repo | 1 + third_party/wifi-ism43362/repo | 1 + 87 files changed, 6659 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/examples-mbed.yaml create mode 100644 .vscode/extensions.json create mode 100644 config/mbed/CHIPProjectConfig.h create mode 100644 config/mbed/CMakeLists.txt create mode 100644 config/mbed/chip-gn/.gn create mode 100644 config/mbed/chip-gn/BUILD.gn create mode 100644 config/mbed/chip-gn/args.gni create mode 120000 config/mbed/chip-gn/build create mode 120000 config/mbed/chip-gn/build_overrides create mode 100644 config/mbed/chip-gn/mbedtls/BUILD.gn create mode 120000 config/mbed/chip-gn/third_party/connectedhomeip create mode 100644 config/mbed/chip-gn/toolchain/BUILD.gn create mode 100644 config/mbed/mbed-util.cmake create mode 100644 config/mbed/mbedtls/chip_mbedtls_config.h create mode 100644 config/mbed/scripts/CY8CPROTO_062_4343W.tcl create mode 100644 config/mbed/scripts/DISCO_L475VG_IOT01A.tcl create mode 100644 examples/lock-app/mbed/.gitignore create mode 100644 examples/lock-app/mbed/CMakeLists.txt create mode 100644 examples/lock-app/mbed/config.in create mode 100644 examples/lock-app/mbed/main/AppTask.cpp create mode 100644 examples/lock-app/mbed/main/BoltLockManager.cpp create mode 100644 examples/lock-app/mbed/main/ZclCallbacks.cpp create mode 100644 examples/lock-app/mbed/main/include/AppEvent.h create mode 100644 examples/lock-app/mbed/main/include/AppTask.h create mode 100644 examples/lock-app/mbed/main/include/BoltLockManager.h create mode 100644 examples/lock-app/mbed/main/include/CHIPProjectConfig.h create mode 100644 examples/lock-app/mbed/main/main.cpp create mode 100644 examples/lock-app/mbed/mbed-os.lib create mode 100644 examples/lock-app/mbed/mbed_app.json create mode 100644 examples/lock-app/mbed/wifi-ism43362.lib create mode 100644 examples/platform/mbed/util/LEDWidget.cpp create mode 100644 examples/platform/mbed/util/include/LEDWidget.h create mode 100755 scripts/examples/mbed_example.sh create mode 100644 scripts/requirements.mbed.txt create mode 100644 src/lib/shell/streamer_mbed.cpp create mode 100644 src/platform/mbed/BLEManagerImpl.cpp create mode 100644 src/platform/mbed/BLEManagerImpl.h create mode 100644 src/platform/mbed/BUILD.gn create mode 100644 src/platform/mbed/BlePlatformConfig.h create mode 100644 src/platform/mbed/CHIPDevicePlatformConfig.h create mode 100644 src/platform/mbed/CHIPDevicePlatformEvent.h create mode 100644 src/platform/mbed/CHIPPlatformConfig.h create mode 100644 src/platform/mbed/ConfigurationManagerImpl.cpp create mode 100644 src/platform/mbed/ConfigurationManagerImpl.h create mode 100644 src/platform/mbed/ConnectivityManagerImpl.cpp create mode 100644 src/platform/mbed/ConnectivityManagerImpl.h create mode 100644 src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.cpp create mode 100644 src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.h create mode 100644 src/platform/mbed/InetPlatformConfig.h create mode 100644 src/platform/mbed/KeyValueStoreManagerImpl.cpp create mode 100644 src/platform/mbed/KeyValueStoreManagerImpl.h create mode 100644 src/platform/mbed/Logging.cpp create mode 100644 src/platform/mbed/MbedConfig.cpp create mode 100644 src/platform/mbed/MbedConfig.h create mode 100644 src/platform/mbed/MbedEventTimeout.cpp create mode 100644 src/platform/mbed/MbedEventTimeout.h create mode 100644 src/platform/mbed/PlatformManagerImpl.cpp create mode 100644 src/platform/mbed/PlatformManagerImpl.h create mode 100644 src/platform/mbed/SystemPlatformConfig.h create mode 100644 src/platform/mbed/SystemTimeSupport.cpp create mode 100644 src/platform/mbed/arch.c create mode 160000 third_party/mbed-os-posix-socket/repo create mode 160000 third_party/mbed-os/repo create mode 160000 third_party/wifi-ism43362/repo diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 489a5596bdda70..c33b5913d62d1c 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -34,7 +34,9 @@ RUN apt-get -fy install git vim emacs sudo \ build-essential cmake cppcheck valgrind \ wget curl telnet \ docker.io \ - iputils-ping net-tools + iputils-ping net-tools \ + libncurses5 + RUN groupadd -g $USER_GID $USERNAME RUN useradd -s /bin/bash -u $USER_UID -g $USER_GID -G docker -m $USERNAME RUN echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 08dfc59833061f..616a7dcd8afe7b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,7 +4,11 @@ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", - "--network=host" + "--network=host", + "-v", + "/dev/bus/usb:/dev/bus/usb:ro", + "--device-cgroup-rule=a 189:* rmw", + "--add-host=host.docker.internal:host-gateway" ], "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" diff --git a/.github/workflows/examples-mbed.yaml b/.github/workflows/examples-mbed.yaml new file mode 100644 index 00000000000000..16fe097907e695 --- /dev/null +++ b/.github/workflows/examples-mbed.yaml @@ -0,0 +1,82 @@ +# 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 - Mbed OS + +on: + push: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.event.number) || (github.event_name == 'workflow_dispatch' && github.run_number) || github.sha }} + cancel-in-progress: true + +jobs: + mbedos: + strategy: + fail-fast: False + matrix: + EXAMPLE_APP: [lock-app] + EXAMPLE_TARGET: [CY8CPROTO_062_4343W] + + name: "${{matrix.EXAMPLE_APP}}: ${{matrix.EXAMPLE_TARGET}}" + + env: + BUILD_TYPE: mbedos + EXAMPLE_PROFILE: release + + runs-on: ubuntu-latest + + container: + image: connectedhomeip/chip-build-mbed-os:latest + volumes: + - "/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: Build example + run: scripts/examples/mbed_example.sh -a=${{matrix.EXAMPLE_APP}} -b=${{matrix.EXAMPLE_TARGET}} -p=$EXAMPLE_PROFILE + + - name: Copy aside build products + run: | + mkdir -p example_binaries/$BUILD_TYPE-build/ + cp examples/${{matrix.EXAMPLE_APP}}/mbed/build-${{matrix.EXAMPLE_TARGET}}/$EXAMPLE_PROFILE/chip-mbed-${{matrix.EXAMPLE_APP}}-example.hex \ + example_binaries/$BUILD_TYPE-build/${{matrix.EXAMPLE_APP}}_${{matrix.EXAMPLE_TARGET}}_$EXAMPLE_PROFILE.hex + + - 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: Copy aside binaries + run: | + cp -r example_binaries/$BUILD_TYPE-build/ /tmp/output_binaries/ + + - name: Uploading Binaries + uses: actions/upload-artifact@v1 + with: + name: + ${{ env.BUILD_TYPE }}-${{matrix.EXAMPLE_APP}}-example-${{matrix.EXAMPLE_TARGET}}-${{ env.EXAMPLE_PROFILE}}-build-${{ + steps.outsuffix.outputs.value }} + path: /tmp/output_binaries/${{ env.BUILD_TYPE }}-build/${{matrix.EXAMPLE_APP}}_${{matrix.EXAMPLE_TARGET}}_${{ env.EXAMPLE_PROFILE }}.hex diff --git a/.gitignore b/.gitignore index 4763b87e5de0bb..9d591e9e9e4dd7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ !.vscode/tasks.json !.vscode/launch.json !.vscode/settings.json +!.vscode/extensions.json # Platforms .DS_Store diff --git a/.gitmodules b/.gitmodules index b5ba2319ba366a..f88af6f330c793 100644 --- a/.gitmodules +++ b/.gitmodules @@ -83,3 +83,15 @@ [submodule "third_party/openthread/ot-efr32"] path = third_party/openthread/ot-efr32 url = https://github.com/openthread/ot-efr32.git +[submodule "third_party/mbed-os/repo"] + path = third_party/mbed-os/repo + url = https://github.com/ARMmbed/mbed-os.git + branch = feature-chip +[submodule "third_party/wifi-ism43362/repo"] + path = third_party/wifi-ism43362/repo + url = https://github.com/ATmobica/wifi-ism43362.git + branch = master +[submodule "third_party/mbed-os-posix-socket/repo"] + path = third_party/mbed-os-posix-socket/repo + url = https://github.com/ARMmbed/mbed-os-posix-socket.git + branch = main diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000000000..d92e0983873689 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": ["marus25.cortex-debug"], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index 833bc6c15d8bea..3965083ba2a8ce 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -83,6 +83,126 @@ "ignoreFailures": true } ] + }, + + { + "name": "Debug Mbed CY8CPROTO_062_4343W", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}/examples/${input:mbedApp}/mbed", + "executable": "./build-CY8CPROTO_062_4343W/${input:mbedDebugProfile}/chip-mbed-${input:mbedApp}-example", + "servertype": "openocd", + "searchDir": [ + "${workspaceRoot}/config/mbed/scripts", + "${env:OPENOCD_PATH/scripts}" + ], + "configFiles": ["CY8CPROTO_062_4343W.tcl"], + "overrideLaunchCommands": [ + "-enable-pretty-printing", + "monitor program {./build-CY8CPROTO_062_4343W/${input:mbedDebugProfile}/chip-mbed-${input:mbedApp}-example.hex}", + "monitor reset run", + "monitor sleep 200", + "monitor psoc6 reset_halt sysresetreq" + ], + "numberOfProcessors": 2, + "targetProcessor": 1, // Set to 0 for the CM0+, set to 1 for the CM4 + "overrideRestartCommands": [ + "monitor reset init", + "monitor reset run", + "monitor sleep 200", + "monitor psoc6 reset_halt sysresetreq" + ], + "runToMain": true, // if true, program will halt at main. Not used for a restart + "showDevDebugOutput": false // When set to true, displays output of GDB. + }, + + { + "name": "Debug Mbed CY8CPROTO_062_4343W [remote]", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}/examples/${input:mbedApp}/mbed", + "executable": "./build-CY8CPROTO_062_4343W/${input:mbedDebugProfile}/chip-mbed-${input:mbedApp}-example", + "servertype": "external", + "gdbTarget": "host.docker.internal:3334", //port 3333 for the CM0+, 3334 for the CM4 + "overrideLaunchCommands": [ + "-enable-pretty-printing", + "monitor reset halt", + "load ./build-CY8CPROTO_062_4343W/${input:mbedDebugProfile}/chip-mbed-${input:mbedApp}-example.hex", + "monitor reset run", + "monitor sleep 200", + "monitor psoc6 reset_halt sysresetreq" + ], + "overrideRestartCommands": [ + "monitor reset init", + "monitor reset run", + "monitor sleep 200", + "monitor psoc6 reset_halt sysresetreq" + ], + "runToMain": true, // if true, program will halt at main. Not used for a restart + "showDevDebugOutput": false // When set to true, displays output of GDB. + }, + + { + "name": "Flash Mbed CY8CPROTO_062_4343W", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}/examples/${input:mbedApp}/mbed", + "executable": "./build-CY8CPROTO_062_4343W/${input:mbedFlashProfile}/chip-mbed-${input:mbedApp}-example", + "servertype": "openocd", + "searchDir": [ + "${workspaceRoot}/config/mbed/scripts", + "${env:OPENOCD_PATH/scripts}" + ], + "configFiles": ["CY8CPROTO_062_4343W.tcl"], + "overrideLaunchCommands": [ + "monitor reset halt", + "monitor program {./build-CY8CPROTO_062_4343W/${input:mbedFlashProfile}/chip-mbed-${input:mbedApp}-example.hex}", + "monitor reset run", + "quit" + ], + "numberOfProcessors": 2, + "targetProcessor": 1, // Set to 0 for the CM0+, set to 1 for the CM4 + "showDevDebugOutput": false // When set to true, displays output of GDB. + }, + + { + "name": "Flash Mbed CY8CPROTO_062_4343W [remote]", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}/examples/${input:mbedApp}/mbed", + "executable": "./build-CY8CPROTO_062_4343W/${input:mbedFlashProfile}/chip-mbed-${input:mbedApp}-example.hex", + "servertype": "external", + "gdbTarget": "host.docker.internal:3334", //port 3333 for the CM0+, 3334 for the CM4 + "overrideLaunchCommands": [ + "monitor reset halt", + "load ./build-CY8CPROTO_062_4343W/${input:mbedFlashProfile}/chip-mbed-${input:mbedApp}-example.hex", + "monitor reset run", + "quit" + ], + "showDevDebugOutput": false // When set to true, displays output of GDB. + } + ], + "inputs": [ + { + "type": "pickString", + "id": "mbedDebugProfile", + "description": "What mbed profile do you want to debug?", + "options": ["debug", "develop"], + "default": "debug" + }, + { + "type": "pickString", + "id": "mbedFlashProfile", + "description": "What mbed profile do you want to flash?", + "options": ["release", "debug", "develop"], + "default": "release" + }, + { + "type": "pickString", + "id": "mbedApp", + "description": "What mbed application do you want to use?", + "options": ["lock-app"], + "default": "shell" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b36d01ea8539f5..d4a03ab8a0b578 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -289,6 +289,73 @@ "${workspaceFolder}/examples/lighting-app/telink/build/tlsr9518adk80d" ] } + }, + { + "label": "Run Mbed Application", + "type": "shell", + "command": "scripts/examples/mbed_example.sh", + "args": [ + "-c=${input:mbedCommand}", + "-a=${input:mbedApp}", + "-b=${input:mbedTarget}", + "-p=${input:mbedProfile}" + ], + "group": "build", + "problemMatcher": { + "base": "$gcc", + "fileLocation": [ + "relative", + "${workspaceFolder}/examples/${input:mbedApp}/mbed/build" + ] + } + }, + { + "label": "Run Mbed Unit Tests", + "type": "shell", + "command": "scripts/tests/mbed_tests.sh", + "args": [ + "-c=${input:mbedCommand}", + "-b=${input:mbedTarget}", + "-p=${input:mbedProfile}" + ], + "group": "build", + "problemMatcher": { + "base": "$gcc", + "fileLocation": [ + "relative", + "${workspaceFolder}/src/test_driver/mbed/build" + ] + } + } + ], + "inputs": [ + { + "type": "pickString", + "id": "mbedCommand", + "description": "What do you want to do?", + "options": ["build", "flash", "build-flash"], + "default": "build" + }, + { + "type": "pickString", + "id": "mbedApp", + "description": "What mbed application do you want to use?", + "options": ["lock-app"], + "default": "shell" + }, + { + "type": "pickString", + "id": "mbedTarget", + "description": "What mbed target do you want to use?", + "options": ["CY8CPROTO_062_4343W"], + "default": "CY8CPROTO_062_4343W" + }, + { + "type": "pickString", + "id": "mbedProfile", + "description": "What mbed profile do you want to use?", + "options": ["develop", "release", "debug"], + "default": "develop" } ] } diff --git a/config/mbed/CHIPProjectConfig.h b/config/mbed/CHIPProjectConfig.h new file mode 100644 index 00000000000000..fea8f05c9672c5 --- /dev/null +++ b/config/mbed/CHIPProjectConfig.h @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Project-specific default configuration overrides + */ + +#pragma once + +// ====== Project-specific Configuration Overrides Defaults ===== + +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 diff --git a/config/mbed/CMakeLists.txt b/config/mbed/CMakeLists.txt new file mode 100644 index 00000000000000..9b520fef3fe793 --- /dev/null +++ b/config/mbed/CMakeLists.txt @@ -0,0 +1,277 @@ +# +# 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 +# CMake sub-project defining 'chip' target which represents CHIP library +# and other optional libraries like unit tests, built with 'mbed' +# platform. +# Since CHIP doesn't provide native CMake support, ExternalProject +# module is used to build the required artifacts with GN meta-build +# system. +# + +include(ExternalProject) +include(mbed-util.cmake) + +# ============================================================================== +# Declare configuration variables and define constants +# ============================================================================== +# C/C++ compiler flags passed to CHIP build system +list(APPEND CHIP_CFLAGS) + +# C compiler flags passed to CHIP build system +list(APPEND CHIP_CFLAGS_C) + +# C++ compiler flags passed to CHIP build system +list(APPEND CHIP_CFLAGS_CC) + +# CHIP libraries that the application should be linked with +list(APPEND CHIP_LIBRARIES) + +# GN meta-build system arguments in the form of 'key1 = value1\nkey2 = value2...' string +string(APPEND CHIP_GN_ARGS) + +# C/C++ compiler flags which should not be forwarded to CHIP +# build system (e.g. because CHIP configures them on its own) +set(CHIP_CFLAG_EXCLUDES + "-fno-asynchronous-unwind-tables" + "-fno-common" + "-fno-defer-pop" + "-fno-reorder-functions" + "-ffunction-sections" + "-fdata-sections" + "-g*" + "-O*" + "-W*" +) + +# ============================================================================== +# Helper macros +# ============================================================================== + +macro(chip_gn_arg_string ARG STRING) + string(APPEND CHIP_GN_ARGS "${ARG} = \"${STRING}\"\n") +endmacro() + +macro(chip_gn_arg_bool ARG BOOLEAN) + if (${BOOLEAN}) + string(APPEND CHIP_GN_ARGS "${ARG} = true\n") + else() + string(APPEND CHIP_GN_ARGS "${ARG} = false\n") + endif() +endmacro() + +macro(chip_gn_arg_flags ARG CFLAGS) + list(SORT CFLAGS) + string(APPEND CHIP_GN_ARGS "${ARG} = [${CFLAGS}]\n") +endmacro() + +macro(chip_gn_arg_lang_flags ARG CFLAGS) + list(SORT CFLAGS) + list(SORT CHIP_CFLAG_EXCLUDES) + set(CFLAG_EXCLUDES "[") + foreach(cflag ${CHIP_CFLAG_EXCLUDES}) + string(APPEND CFLAG_EXCLUDES "\"${cflag}\", ") + endforeach() + string(APPEND CFLAG_EXCLUDES "]") + string(APPEND CHIP_GN_ARGS "${ARG} = filter_exclude(string_split(\"${CFLAGS}\"), ${CFLAG_EXCLUDES})\n") +endmacro() + +macro(mbed_interface_library_named name) + add_library(${name} INTERFACE) +endmacro() + +# ============================================================================== +# Prepare CHIP configuration based on the project configuration +# ============================================================================== +# Read configuration file and parse it content to create cmake variable +file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/config ConfigContents) +foreach(NameAndValue ${ConfigContents}) + # Strip leading spaces + string(REGEX REPLACE "^[ ]+" "" NameAndValue ${NameAndValue}) + # Find variable name + string(REGEX MATCH "^[^=]+" Name ${NameAndValue}) + # Find the value + string(REPLACE "${Name}=" "" Value ${NameAndValue}) + # Set the variable + set(${Name} "${Value}") +endforeach() + +if (NOT CHIP_ROOT) + get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../.. REALPATH) +endif() + +# Prepare compiler flags + +mbed_get_target_common_compile_flags(CHIP_CFLAGS mbed-core) +mbed_get_lang_compile_flags(CHIP_CFLAGS_C mbed-core C) +list(APPEND CHIP_CFLAGS_C ${CMAKE_C_FLAGS_INIT}) +mbed_get_lang_compile_flags(CHIP_CFLAGS_CC mbed-core CXX) +list(APPEND CHIP_CFLAGS_CC ${CMAKE_CXX_FLAGS_INIT}) + +# Add support for Mbed Posix Socket +mbed_get_target_common_compile_flags(CHIP_MBEDPOSIXSOCKET_CFLAGS mbed-os-posix-socket) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDPOSIXSOCKET_CFLAGS}) + +# Add support for Mbed BLE +mbed_get_target_common_compile_flags(CHIP_MBEDBLE_CFLAGS mbed-ble) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDBLE_CFLAGS}) + +# Add support for Mbed event +mbed_get_target_common_compile_flags(CHIP_MBEDEVENTS_CFLAGS mbed-events) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDEVENTS_CFLAGS}) + +# Add support for Mbed rtos +mbed_get_target_common_compile_flags(CHIP_MBEDRTOS_CFLAGS mbed-rtos) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDRTOS_CFLAGS}) + +# Add support for Mbed storage +mbed_get_target_common_compile_flags(CHIP_MBEDSTORAGE_CFLAGS mbed-storage-kv-global-api) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDSTORAGE_CFLAGS}) + +# Add support for Mbed Socket +mbed_get_target_common_compile_flags(CHIP_MBEDNETSOCKET_CFLAGS mbed-netsocket) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDNETSOCKET_CFLAGS}) + +if (CONFIG_CHIP_WITH_EXTERNAL_MBEDTLS) + mbed_get_target_common_compile_flags(CHIP_MBEDTLS_CFLAGS mbed-mbedtls) + list(APPEND CHIP_CFLAGS ${CHIP_MBEDTLS_CFLAGS}) +endif() + +list(APPEND CHIP_CFLAGS + \"-D__LINUX_ERRNO_EXTENSIONS__=1\" +) + +# CFLAGS are put in random order, sort them before converting them to a string +list(SORT CHIP_CFLAGS) +list(SORT CHIP_CFLAGS_C) +list(SORT CHIP_CFLAGS_CC) + +set(SEPARATOR ",") +convert_list_of_flags_to_string_of_flags(CHIP_CFLAGS CHIP_CFLAGS ${SEPARATOR}) +set(SEPARATOR " ") +convert_list_of_flags_to_string_of_flags(CHIP_CFLAGS_C CHIP_CFLAGS_C ${SEPARATOR}) +convert_list_of_flags_to_string_of_flags(CHIP_CFLAGS_CC CHIP_CFLAGS_CC ${SEPARATOR}) + +# Prepare CHIP libraries that the application should be linked with + +if (NOT CHIP_LIBRARIES) + set(CHIP_LIBRARIES -lCHIP) +endif() + +if (CONFIG_CHIP_LIB_SHELL) + list(APPEND CHIP_LIBRARIES -lCHIPShell) +endif() + +# Set up CHIP project configuration file + +set(CHIP_DEFAULT_CONFIG_FILE "<${CHIP_ROOT}/config/mbed/CHIPProjectConfig.h>") +set(CHIP_PROJECT_CONFIG ${CHIP_DEFAULT_CONFIG_FILE}) + +if (CONFIG_CHIP_PROJECT_CONFIG) + get_filename_component(CHIP_PROJECT_CONFIG + ${CONFIG_CHIP_PROJECT_CONFIG} + REALPATH + BASE_DIR ${CMAKE_SOURCE_DIR} + ) + set(CHIP_PROJECT_CONFIG "<${CHIP_PROJECT_CONFIG}>") +endif() + +if (${CMAKE_BUILD_TYPE} STREQUAL "debug") + set(CONFIG_DEBUG "y") +endif() + +# ============================================================================== +# Generate configuration for CHIP GN build system +# ============================================================================== + +chip_gn_arg_flags("target_cflags" ${CHIP_CFLAGS}) +chip_gn_arg_lang_flags("target_cflags_c" ${CHIP_CFLAGS_C}) +chip_gn_arg_lang_flags("target_cflags_cc" ${CHIP_CFLAGS_CC}) +chip_gn_arg_string("mbed_ar" ${CMAKE_AR}) +chip_gn_arg_string("mbed_cc" ${CMAKE_C_COMPILER}) +chip_gn_arg_string("mbed_cxx" ${CMAKE_CXX_COMPILER}) +chip_gn_arg_string("chip_project_config_include" "${CHIP_PROJECT_CONFIG}") +chip_gn_arg_bool ("is_debug" CONFIG_DEBUG) +chip_gn_arg_bool ("chip_build_tests" CONFIG_CHIP_BUILD_TESTS) +chip_gn_arg_bool ("chip_build_libshell" CONFIG_CHIP_LIB_SHELL) +chip_gn_arg_bool ("chip_with_platform_mbedtls" CONFIG_CHIP_WITH_EXTERNAL_MBEDTLS) +chip_gn_arg_bool ("chip_bypass_rendezvous" CONFIG_CHIP_BYPASS_RENDEZVOUS) + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/args.gn CONTENT ${CHIP_GN_ARGS}) + +# ============================================================================== +# Define 'chip-gn' target that builds CHIP library(ies) with GN build system +# ============================================================================== +ExternalProject_Add( + chip-gn + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + SOURCE_DIR ${CHIP_ROOT} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} + CONFIGURE_COMMAND gn --root=${CHIP_ROOT}/config/mbed/chip-gn gen --export-compile-commands --check --fail-on-unused-args ${CMAKE_CURRENT_BINARY_DIR} + BUILD_COMMAND ninja + INSTALL_COMMAND "" + BUILD_BYPRODUCTS ${CHIP_LIBRARIES} + CONFIGURE_ALWAYS TRUE + BUILD_ALWAYS TRUE + USES_TERMINAL_CONFIGURE TRUE + USES_TERMINAL_BUILD TRUE +) + +# ============================================================================== +# Define 'chip' target that exposes CHIP headers & libraries to the application +# ============================================================================== +mbed_interface_library_named(chip) +target_compile_definitions(chip INTERFACE CHIP_HAVE_CONFIG_H) +target_include_directories(chip INTERFACE + ${CHIP_ROOT}/src + ${CHIP_ROOT}/src/include + ${CHIP_ROOT}/src/lib + ${CHIP_ROOT}/third_party/nlassert/repo/include + ${CMAKE_CURRENT_BINARY_DIR}/gen/include +) +target_link_directories(chip INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/lib) +target_link_libraries(chip INTERFACE -Wl,--start-group ${CHIP_LIBRARIES} -Wl,--end-group) +add_dependencies(chip chip-gn) + +# ============================================================================== +# Define mbed target configuration according to CHIP component usage +# ============================================================================== +# CHIP includes path +list(APPEND CHIP_INCLUDES) + +# CHIP defines +list(APPEND CHIP_DEFINES) + + +list(APPEND CHIP_INCLUDES + ${CHIP_ROOT}/config/mbed/mbedtls + ${CHIP_ROOT}/src/platform/mbed/posix/include + ${CHIP_ROOT}/src/platform/mbed/net/include +) + +list(APPEND CHIP_DEFINES + __LINUX_ERRNO_EXTENSIONS__=1 +) + +target_include_directories(${APP_TARGET} PRIVATE + ${CHIP_INCLUDES} +) + +target_compile_definitions(${APP_TARGET} PRIVATE + ${CHIP_DEFINES} +) diff --git a/config/mbed/chip-gn/.gn b/config/mbed/chip-gn/.gn new file mode 100644 index 00000000000000..751e7454035e18 --- /dev/null +++ b/config/mbed/chip-gn/.gn @@ -0,0 +1,33 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# 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 = "mbed" + + default_configs_warnings = [ + "${build_root}/config/compiler:warnings_default", + "//:chip_custom_cflags_config", + ] + + import("//args.gni") +} diff --git a/config/mbed/chip-gn/BUILD.gn b/config/mbed/chip-gn/BUILD.gn new file mode 100644 index 00000000000000..4a6b92c302508f --- /dev/null +++ b/config/mbed/chip-gn/BUILD.gn @@ -0,0 +1,64 @@ +# 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}/build/chip/tests.gni") + +assert(current_os == "mbed") + +declare_args() { + chip_custom_build_cflags = [] +} + +config("chip_custom_cflags_config") { + cflags = chip_custom_build_cflags +} + +group("mbed") { + deps = [ "${chip_root}/src/lib" ] + + if (chip_build_tests) { + # TODO: Enable all the tests. Use the src:tests target. + # deps += [ "${chip_root}/src:tests" ] + deps += [ + "${chip_root}/src/app/tests", + "${chip_root}/src/ble/tests", + "${chip_root}/src/credentials/tests", + "${chip_root}/src/crypto/tests", + "${chip_root}/src/inet/tests", + "${chip_root}/src/lib/asn1/tests", + "${chip_root}/src/lib/core/tests", + "${chip_root}/src/lib/mdns/minimal/core/tests", + "${chip_root}/src/lib/mdns/minimal/records/tests", + "${chip_root}/src/lib/mdns/minimal/responders/tests", + "${chip_root}/src/lib/mdns/minimal/tests", + + # "${chip_root}/src/lib/support/tests", + "${chip_root}/src/messaging/tests", + "${chip_root}/src/platform/tests", + "${chip_root}/src/protocols/bdx/tests", + "${chip_root}/src/setup_payload/tests", + "${chip_root}/src/system/tests", + + # "${chip_root}/src/transport/raw/tests", + "${chip_root}/src/transport/retransmit/tests", + "${chip_root}/src/transport/tests", + ] + } +} + +group("default") { + deps = [ ":mbed" ] +} diff --git a/config/mbed/chip-gn/args.gni b/config/mbed/chip-gn/args.gni new file mode 100644 index 00000000000000..90cccd4ae9c0c8 --- /dev/null +++ b/config/mbed/chip-gn/args.gni @@ -0,0 +1,32 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +chip_device_platform = "mbed" + +chip_project_config_include = "" +chip_system_project_config_include = "" +chip_device_project_config_include = "" + +chip_inet_config_enable_raw_endpoint = true +chip_inet_config_enable_udp_endpoint = true +chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_dns_resolver = true +chip_inet_config_enable_async_dns_sockets = false + +chip_custom_build_cflags = [] + +custom_toolchain = "//toolchain:mbed" +mbedtls_target = "//mbedtls:mbedtls" diff --git a/config/mbed/chip-gn/build b/config/mbed/chip-gn/build new file mode 120000 index 00000000000000..44735d58664596 --- /dev/null +++ b/config/mbed/chip-gn/build @@ -0,0 +1 @@ +../../../build \ No newline at end of file diff --git a/config/mbed/chip-gn/build_overrides b/config/mbed/chip-gn/build_overrides new file mode 120000 index 00000000000000..5140c246d723bf --- /dev/null +++ b/config/mbed/chip-gn/build_overrides @@ -0,0 +1 @@ +../../../examples/build_overrides/ \ No newline at end of file diff --git a/config/mbed/chip-gn/mbedtls/BUILD.gn b/config/mbed/chip-gn/mbedtls/BUILD.gn new file mode 100644 index 00000000000000..e513619330e6e2 --- /dev/null +++ b/config/mbed/chip-gn/mbedtls/BUILD.gn @@ -0,0 +1,40 @@ +# 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. + +# Options from standalone-chip.mk that differ from configure defaults. These +# options are used from examples/. + +import("//build_overrides/chip.gni") + +declare_args() { + chip_with_platform_mbedtls = false +} + +config("chip_mbedtls_config") { + include_dirs = [ "${chip_root}/config/mbed/mbedtls" ] +} + +if (!chip_with_platform_mbedtls) { + import("//build_overrides/mbedtls.gni") + import("${mbedtls_root}/mbedtls.gni") + + mbedtls_target("mbedtls") { + public_configs = [ ":chip_mbedtls_config" ] + } +} else { + # Mbed provides its own mbedtls, so nothing to do, just provide a target + group("mbedtls") { + public_configs = [ ":chip_mbedtls_config" ] + } +} diff --git a/config/mbed/chip-gn/third_party/connectedhomeip b/config/mbed/chip-gn/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/config/mbed/chip-gn/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/config/mbed/chip-gn/toolchain/BUILD.gn b/config/mbed/chip-gn/toolchain/BUILD.gn new file mode 100644 index 00000000000000..14e99fe9170038 --- /dev/null +++ b/config/mbed/chip-gn/toolchain/BUILD.gn @@ -0,0 +1,32 @@ +# 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/arm_gcc/arm_toolchain.gni") + +declare_args() { + mbed_ar = "" + mbed_cc = "" + mbed_cxx = "" +} + +gcc_toolchain("mbed") { + ar = mbed_ar + cc = mbed_cc + cxx = mbed_cxx + + toolchain_args = { + current_os = "mbed" + is_clang = false + } +} diff --git a/config/mbed/mbed-util.cmake b/config/mbed/mbed-util.cmake new file mode 100644 index 00000000000000..48aea01d5fde80 --- /dev/null +++ b/config/mbed/mbed-util.cmake @@ -0,0 +1,139 @@ +# +# 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 +# CMake utilities for managing and retrieving mbed build configuration +# + +# Get compilation flags for specific lang +# The flags might contains compile language generator expressions that +# look like this: +# $<$:-fno-exceptions> +# Applying a regex to extract the flag and also to find out if the language matches. +# [Args]: +# input - list of flags to parse +# output - list of flags set to specific language +function(get_flags_for_lang lang input output) + set(tmp_list "") + + list(LENGTH ${input} nb_elem) + set(index 0) + set(is_compile_lang_expression 0) + + while(${index} LESS ${nb_elem}) + list(GET ${input} ${index} value) + if(value MATCHES ":([^>]+)") + string(REGEX REPLACE "^[^:]*:" "" updated_flag ${value}) + list(APPEND tmp_list ${updated_flag}) + if(NOT value MATCHES ">$") + set(is_compile_lang_expression 1) + endif() + elseif(is_compile_lang_expression) + if(value MATCHES ">$") + set(is_compile_lang_expression 0) + endif() + string(REPLACE ">" "" updated_flag ${value}) + list(APPEND tmp_list ${updated_flag}) + endif() + math(EXPR index "${index}+1") + endwhile() + + set(${output} ${tmp_list} PARENT_SCOPE) +endfunction() + +# Get include directory of target build +# Get target property of includes directories +# For each flag add -I prefix and put it in quotation marks +# [Args]: +# target - target name +# output - output variable name +function(mbed_get_include_directories target output) + get_property(flags TARGET ${target} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND CFLAG_LIST) + foreach(flag ${flags}) + list(APPEND CFLAG_LIST "\"-isystem${flag}\"") + endforeach() + set(${output} ${CFLAG_LIST} PARENT_SCOPE) +endfunction() + +# Get compile definitions of target build +# Get target property of compile definitions +# For each flag change format, add -D prefix and put it in quotation marks +# [Args]: +# target - target name +# output - output variable name +function(mbed_get_compile_definitions target output) + get_property(flags TARGET ${target} PROPERTY INTERFACE_COMPILE_DEFINITIONS) + + list(APPEND CFLAG_LIST) + foreach(flag ${flags}) + # Replace each quote with a '\"' - format required for the GN arguments + string(REPLACE "\"" "\\\\\"" output_flag ${flag}) + list(APPEND CFLAG_LIST "\"-D${output_flag}\"") + endforeach() + set(${output} ${CFLAG_LIST} PARENT_SCOPE) +endfunction() + +# Get compile options of mbed build for specific language +# Get mbed-core property of compile options +# [Args]: +# lang - compilation languge (C, C++ or ASM) +# target - target name +# output - output variable name +function(mbed_get_compile_options_for_lang lang target output) + get_property(flags TARGET ${target} PROPERTY INTERFACE_COMPILE_OPTIONS) + get_flags_for_lang(${lang} flags output_list) + set(${output} ${output_list} PARENT_SCOPE) +endfunction() + + +# Retrieve common compilation flags specific for target +# [Args]: +# VAR - flags variable name +# TARGET - target name +function(mbed_get_target_common_compile_flags VAR TARGET) + mbed_get_include_directories(${TARGET} INCLUDES) + mbed_get_compile_definitions(${TARGET} DEFINES) + set(${VAR} ${INCLUDES} ${DEFINES} ${${VAR}} PARENT_SCOPE) +endfunction() + +# Retrieve target compiler flags for the specific language (C or CXX) +# [Args]: +# VAR - flags variable name +# TARGET - target name +# LANG - compilation languge (C, C++ or ASM) +function(mbed_get_lang_compile_flags VAR TARGET LANG) + mbed_get_compile_options_for_lang(${LANG} ${TARGET} FLAGS) + set(${VAR} ${FLAGS} ${${VAR}} PARENT_SCOPE) +endfunction() + +# Convert list of flags to string format +# [Args]: +# ptr_list_of_flags - list fo flags +# string_of_flags - output string +# separator - flags separator +function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags separator) + # Convert the list to a string so we can do string replace + # operations on it and replace the ";" list separators with a + # desirable one so the flags are spaced out + string(REPLACE ";" ${separator} locally_scoped_string_of_flags "${${ptr_list_of_flags}}") + # Removing excess spaces + string(REPLACE " " " " locally_scoped_string_of_flags "${locally_scoped_string_of_flags}") + + # Set the output variable in the parent scope + set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE) +endfunction() \ No newline at end of file diff --git a/config/mbed/mbedtls/chip_mbedtls_config.h b/config/mbed/mbedtls/chip_mbedtls_config.h new file mode 100644 index 00000000000000..83dda5fea41a51 --- /dev/null +++ b/config/mbed/mbedtls/chip_mbedtls_config.h @@ -0,0 +1,43 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * + * \brief CHIP mbedTLS configuration options for mbed platform + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef CHIP_MBEDTLS_CONFIG_H +#define CHIP_MBEDTLS_CONFIG_H + +#define MBEDTLS_X509_CSR_WRITE_C +#define MBEDTLS_X509_CREATE_C +#define MBEDTLS_PEM_WRITE_C +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_PKCS5_C +#undef MBEDTLS_NET_C +#undef MBEDTLS_TIMING_C +#undef MBEDTLS_FS_IO + +#endif /* CHIP_MBEDTLS_CONFIG_H */ diff --git a/config/mbed/scripts/CY8CPROTO_062_4343W.tcl b/config/mbed/scripts/CY8CPROTO_062_4343W.tcl new file mode 100644 index 00000000000000..fafde9c4431705 --- /dev/null +++ b/config/mbed/scripts/CY8CPROTO_062_4343W.tcl @@ -0,0 +1,4 @@ +source [find interface/kitprog3.cfg] +source [find target/psoc6_2m.cfg] +${TARGET}.cm4 configure -rtos auto -rtos-wipe-on-reset-halt 1 +psoc6 sflash_restrictions 1 \ No newline at end of file diff --git a/config/mbed/scripts/DISCO_L475VG_IOT01A.tcl b/config/mbed/scripts/DISCO_L475VG_IOT01A.tcl new file mode 100644 index 00000000000000..1fc3db0f46ee90 --- /dev/null +++ b/config/mbed/scripts/DISCO_L475VG_IOT01A.tcl @@ -0,0 +1,5 @@ +source [find interface/stlink.cfg] +transport select hla_swd +set CHIPNAME STM32L475 +source [find target/stm32l4x.cfg] +reset_config srst_only srst_nogate \ No newline at end of file diff --git a/examples/lock-app/mbed/.gitignore b/examples/lock-app/mbed/.gitignore new file mode 100644 index 00000000000000..aa40e98ae380dc --- /dev/null +++ b/examples/lock-app/mbed/.gitignore @@ -0,0 +1,5 @@ +cmake_build/ +build-*/ +mbed-os +wifi-ism43362 +mbed-os-posix-socket diff --git a/examples/lock-app/mbed/CMakeLists.txt b/examples/lock-app/mbed/CMakeLists.txt new file mode 100644 index 00000000000000..340c48733dafd1 --- /dev/null +++ b/examples/lock-app/mbed/CMakeLists.txt @@ -0,0 +1,128 @@ +# Copyright (c) 2021 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.19.0) + +get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../.. REALPATH) +get_filename_component(APP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/.. REALPATH) +get_filename_component(MBED_COMMON ${CHIP_ROOT}/examples/platform/mbed REALPATH) +get_filename_component(LOCK_COMMON ${CHIP_ROOT}/examples/lock-app/lock-common REALPATH) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/config.in + ${CMAKE_CURRENT_BINARY_DIR}/chip_build/config + @ONLY +) + +set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "") +set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") +set(APP_TARGET chip-mbed-lock-app-example) + +include(${MBED_PATH}/tools/cmake/app.cmake) +add_subdirectory(${MBED_PATH} ./mbed_build) + +add_subdirectory(mbed-os-posix-socket) + +if("wifi_ism43362" IN_LIST MBED_TARGET_LABELS) + add_subdirectory(wifi-ism43362) +endif() + +add_executable(${APP_TARGET}) + +target_include_directories(${APP_TARGET} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/main/include/ + ${APP_ROOT}/lock-common + ${MBED_COMMON}/util/include + ${CHIP_ROOT}/src/app + ${CHIP_ROOT}/third_party/nlio/repo/include +) + +target_sources(${APP_TARGET} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/main/AppTask.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/main/BoltLockManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/main/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/main/ZclCallbacks.cpp + ${LOCK_COMMON}/gen/attribute-size.cpp + ${APP_ROOT}/lock-common/gen/callback-stub.cpp + ${LOCK_COMMON}/gen/IMClusterCommandHandler.cpp + ${MBED_COMMON}/util/LEDWidget.cpp + ${CHIP_ROOT}/src/app/util/DataModelHandler.cpp + ${CHIP_ROOT}/src/app/reporting/reporting-default-configuration.cpp + ${CHIP_ROOT}/src/app/reporting/reporting.cpp + ${CHIP_ROOT}/src/app/util/af-event.cpp + ${CHIP_ROOT}/src/app/util/af-main-common.cpp + ${CHIP_ROOT}/src/app/util/attribute-list-byte-span.cpp + ${CHIP_ROOT}/src/app/util/attribute-size-util.cpp + ${CHIP_ROOT}/src/app/util/attribute-storage.cpp + ${CHIP_ROOT}/src/app/util/attribute-table.cpp + ${CHIP_ROOT}/src/app/util/binding-table.cpp + ${CHIP_ROOT}/src/app/util/chip-message-send.cpp + ${CHIP_ROOT}/src/app/util/client-api.cpp + ${CHIP_ROOT}/src/app/util/ember-compatibility-functions.cpp + ${CHIP_ROOT}/src/app/util/ember-print.cpp + ${CHIP_ROOT}/src/app/util/message.cpp + ${CHIP_ROOT}/src/app/util/process-cluster-message.cpp + ${CHIP_ROOT}/src/app/util/process-global-message.cpp + ${CHIP_ROOT}/src/app/util/util.cpp + ${CHIP_ROOT}/src/app/server/EchoHandler.cpp + ${CHIP_ROOT}/src/app/server/Mdns.cpp + ${CHIP_ROOT}/src/app/server/OnboardingCodesUtil.cpp + ${CHIP_ROOT}/src/app/server/RendezvousServer.cpp + ${CHIP_ROOT}/src/app/server/Server.cpp + ${CHIP_ROOT}/src/app/server/StorablePeerConnection.cpp + ${CHIP_ROOT}/src/app/clusters/basic/basic.cpp + ${CHIP_ROOT}/src/app/clusters/diagnostic-logs-server/diagnostic-logs-server.cpp + ${CHIP_ROOT}/src/app/clusters/bindings/bindings.cpp + ${CHIP_ROOT}/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp + ${CHIP_ROOT}/src/app/clusters/network-commissioning/network-commissioning-ember.cpp + ${CHIP_ROOT}/src/app/clusters/network-commissioning/network-commissioning.cpp + ${CHIP_ROOT}/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp + ${CHIP_ROOT}/src/app/clusters/on-off-server/on-off-server.cpp +) + +add_subdirectory(${CHIP_ROOT}/config/mbed ./chip_build) + +mbed_configure_app_target(${APP_TARGET}) + +mbed_set_mbed_target_linker_script(${APP_TARGET}) + +project(${APP_TARGET}) + +target_link_libraries(${APP_TARGET} + mbed-os-posix-socket + mbed-os + mbed-ble + mbed-events + mbed-netsocket + mbed-storage + mbed-storage-kv-global-api + mbed-mbedtls + mbed-mbedtls-cryptocell310 + chip +) + +if("wifi_ism43362" IN_LIST MBED_TARGET_LABELS) + target_link_libraries(${APP_TARGET} + wifi-ism43362 + ) +endif() + +if("BlueNRG_MS" IN_LIST MBED_TARGET_LABELS) + target_link_libraries(${APP_TARGET} + mbed-ble-blue_nrg + ) +endif() + +if("WHD" IN_LIST MBED_TARGET_LABELS) + target_link_libraries(${APP_TARGET} + mbed-cy_psoc6_common_network mbed-emac mbed-cy_psoc6_whd + ) +endif() + +mbed_set_post_build(${APP_TARGET}) + +option(VERBOSE_BUILD "Have a verbose build process") +if(VERBOSE_BUILD) + set(CMAKE_VERBOSE_MAKEFILE ON) +endif() diff --git a/examples/lock-app/mbed/config.in b/examples/lock-app/mbed/config.in new file mode 100644 index 00000000000000..0281e3bf37edd5 --- /dev/null +++ b/examples/lock-app/mbed/config.in @@ -0,0 +1,5 @@ +CONFIG_CHIP_BUILD_TESTS=n +CONFIG_CHIP_WITH_EXTERNAL_MBEDTLS=y +CONFIG_CHIP_WITH_LWIP=y +CONFIG_CHIP_PROJECT_CONFIG=main/include/CHIPProjectConfig.h +CONFIG_CHIP_BYPASS_RENDEZVOUS=n \ No newline at end of file diff --git a/examples/lock-app/mbed/main/AppTask.cpp b/examples/lock-app/mbed/main/AppTask.cpp new file mode 100644 index 00000000000000..14accc61987606 --- /dev/null +++ b/examples/lock-app/mbed/main/AppTask.cpp @@ -0,0 +1,420 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "BoltLockManager.h" +#include "LEDWidget.h" +#include + +// FIXME: Undefine the `sleep()` function included by the CHIPDeviceLayer.h +// from unistd.h to avoid a conflicting declaration with the `sleep()` provided +// by Mbed-OS in mbed_power_mgmt.h. +#define sleep unistd_sleep +#include +#include +#include +#undef sleep + +#include + +// ZAP -- ZCL Advanced Platform +#include +#include +#include +#include + +// mbed-os headers +#include "drivers/InterruptIn.h" +#include "drivers/Timeout.h" +#include "events/EventQueue.h" +#include "platform/Callback.h" + +#define FACTORY_RESET_TRIGGER_TIMEOUT (MBED_CONF_APP_FACTORY_RESET_TRIGGER_TIMEOUT) +#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT (MBED_CONF_APP_FACTORY_RESET_CANCEL_WINDOW_TIMEOUT) +#define LOCK_BUTTON (MBED_CONF_APP_LOCK_BUTTON) +#define FUNCTION_BUTTON (MBED_CONF_APP_FUNCTION_BUTTON) +#define BUTTON_PUSH_EVENT 1 +#define BUTTON_RELEASE_EVENT 0 + +constexpr uint32_t kPublishServicePeriodUs = 5000000; + +static LEDWidget sStatusLED(MBED_CONF_APP_SYSTEM_STATE_LED); +static LEDWidget sLockLED(MBED_CONF_APP_LOCK_STATE_LED); + +static mbed::InterruptIn sLockButton(LOCK_BUTTON); +static mbed::InterruptIn sFunctionButton(FUNCTION_BUTTON); + +static bool sIsWiFiStationProvisioned = false; +static bool sIsWiFiStationEnabled = false; +static bool sIsWiFiStationConnected = false; +static bool sIsPairedToAccount = false; +static bool sHaveBLEConnections = false; +static bool sHaveServiceConnectivity = false; + +static mbed::Timeout sFunctionTimer; + +// TODO: change EventQueue default event size +static events::EventQueue sAppEventQueue; + +using namespace ::chip::DeviceLayer; + +AppTask AppTask::sAppTask; + +int AppTask::Init() +{ + // Register the callback to init the MDNS server when connectivity is available + PlatformMgr().AddEventHandler( + [](const ChipDeviceEvent * event, intptr_t arg) { + // Restart the server whenever an ip address is renewed + if (event->Type == DeviceEventType::kInternetConnectivityChange) + { + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established || + event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + chip::app::Mdns::StartServer(); + } + } + }, + 0); + + // Initialize LEDs + sLockLED.Set(!BoltLockMgr().IsUnlocked()); + + // Initialize buttons + sLockButton.fall(mbed::callback(this, &AppTask::LockButtonPressEventHandler)); + sFunctionButton.fall(mbed::callback(this, &AppTask::FunctionButtonPressEventHandler)); + sFunctionButton.rise(mbed::callback(this, &AppTask::FunctionButtonReleaseEventHandler)); + + // Initialize lock manager + BoltLockMgr().Init(); + BoltLockMgr().SetCallbacks(ActionInitiated, ActionCompleted); + + // Start BLE advertising if needed + if (!CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART) + { + ChipLogProgress(NotSpecified, "Enabling BLE advertising."); + ConnectivityMgr().SetBLEAdvertisingEnabled(true); + } +#ifdef MBED_CONF_APP_DEVICE_NAME + ConnectivityMgr().SetBLEDeviceName(MBED_CONF_APP_DEVICE_NAME); +#endif + + chip::DeviceLayer::ConnectivityMgrImpl().StartWiFiManagement(); + + // Init ZCL Data Model and start server + InitServer(); + ConfigurationMgr().LogDeviceConfig(); + // QR code will be used with CHIP Tool + PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + + return 0; +} + +int AppTask::StartApp() +{ + int ret = Init(); + if (ret) + { + ChipLogError(NotSpecified, "AppTask.Init() failed"); + return ret; + } + + while (true) + { + sAppEventQueue.dispatch(100); + + // 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()) + { + sIsWiFiStationProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); + sIsWiFiStationEnabled = ConnectivityMgr().IsWiFiStationEnabled(); + sIsWiFiStationConnected = ConnectivityMgr().IsWiFiStationConnected(); + 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 (sIsWiFiStationProvisioned && sIsWiFiStationEnabled && sIsPairedToAccount && + (!sIsWiFiStationConnected || !isFullyConnected)) + { + sStatusLED.Blink(950, 50); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(100, 100); + } + else + { + sStatusLED.Blink(50, 950); + } + } + + sStatusLED.Animate(); + sLockLED.Animate(); + } +} + +void AppTask::LockActionEventHandler(AppEvent * aEvent) +{ + BoltLockManager::Action_t action = BoltLockManager::INVALID_ACTION; + int32_t actor = 0; + + if (aEvent->Type == AppEvent::kEventType_Lock) + { + action = static_cast(aEvent->LockEvent.Action); + actor = aEvent->LockEvent.Actor; + } + else if (aEvent->Type == AppEvent::kEventType_Button) + { + action = BoltLockMgr().IsUnlocked() ? BoltLockManager::LOCK_ACTION : BoltLockManager::UNLOCK_ACTION; + actor = AppEvent::kEventType_Button; + } + + if (action != BoltLockManager::INVALID_ACTION && !BoltLockMgr().InitiateAction(actor, action)) + ChipLogProgress(NotSpecified, "Action is already in progress or active."); +} + +void AppTask::LockButtonPressEventHandler() +{ + AppEvent button_event; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Pin = LOCK_BUTTON; + button_event.ButtonEvent.Action = BUTTON_PUSH_EVENT; + button_event.Handler = LockActionEventHandler; + sAppTask.PostEvent(&button_event); +} + +void AppTask::FunctionButtonPressEventHandler() +{ + AppEvent button_event; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Pin = FUNCTION_BUTTON; + button_event.ButtonEvent.Action = BUTTON_PUSH_EVENT; + button_event.Handler = FunctionHandler; + sAppTask.PostEvent(&button_event); +} + +void AppTask::FunctionButtonReleaseEventHandler() +{ + AppEvent button_event; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Pin = FUNCTION_BUTTON; + button_event.ButtonEvent.Action = BUTTON_RELEASE_EVENT; + button_event.Handler = FunctionHandler; + sAppTask.PostEvent(&button_event); +} + +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) + { + ChipLogProgress(NotSpecified, "Lock Action has been initiated"); + } + else if (aAction == BoltLockManager::UNLOCK_ACTION) + { + ChipLogProgress(NotSpecified, "Unlock Action has been initiated"); + } + + sLockLED.Blink(50, 50); +} + +void AppTask::ActionCompleted(BoltLockManager::Action_t aAction, int32_t aActor) +{ + // 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) + { + ChipLogProgress(NotSpecified, "Lock Action has been completed"); + sLockLED.Set(true); + } + else if (aAction == BoltLockManager::UNLOCK_ACTION) + { + ChipLogProgress(NotSpecified, "Unlock Action has been completed"); + sLockLED.Set(false); + } + + if (aActor == AppEvent::kEventType_Button) + { + sAppTask.UpdateClusterState(); + } +} + +void AppTask::CancelTimer() +{ + sFunctionTimer.detach(); + mFunctionTimerActive = false; +} + +void AppTask::StartTimer(uint32_t aTimeoutInMs) +{ + auto chronoTimeoutMs = std::chrono::duration(aTimeoutInMs); + sFunctionTimer.attach(mbed::callback(this, &AppTask::TimerEventHandler), chronoTimeoutMs); + mFunctionTimerActive = true; +} + +void AppTask::PostEvent(AppEvent * aEvent) +{ + auto handle = sAppEventQueue.call([event = *aEvent, this] { DispatchEvent(&event); }); + if (!handle) + { + ChipLogError(NotSpecified, "Failed to post event to app task event queue: Not enough memory"); + } +} + +void AppTask::DispatchEvent(const AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(const_cast(aEvent)); + } + else + { + ChipLogError(NotSpecified, "Event received with no handler. Dropping event."); + } +} + +void AppTask::TimerEventHandler() +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + // event.TimerEvent.Context = nullptr; + event.Handler = FunctionTimerEventHandler; + sAppTask.PostEvent(&event); +} + +// static +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) + { + ChipLogProgress(NotSpecified, "Factory Reset Triggered. Release button within %ums to cancel.", + FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); + + // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to + // cancel, if required. + 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); + + sStatusLED.Blink(500); + sLockLED.Blink(500); + } + else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) + { + // Set lock status LED back to show state of lock. + sLockLED.Set(!BoltLockMgr().IsUnlocked()); + + // Actually trigger Factory Reset + ChipLogProgress(NotSpecified, "Factory Reset initiated"); + sAppTask.mFunction = kFunction_NoneSelected; + ConfigurationMgr().InitiateFactoryReset(); + } +} + +void AppTask::FunctionHandler(AppEvent * aEvent) +{ + if (aEvent->ButtonEvent.Pin != 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 == BUTTON_PUSH_EVENT) + { + 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; + ChipLogError(NotSpecified, "Software Update not supported."); + } + else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) + { + // 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; + + ChipLogProgress(NotSpecified, "Factory Reset has been Canceled"); + } + } +} + +void AppTask::UpdateClusterState() +{ + uint8_t newValue = !BoltLockMgr().IsUnlocked(); + + // write the new on/off value + EmberAfStatus status = emberAfWriteAttribute(1, ZCL_ON_OFF_CLUSTER_ID, ZCL_ON_OFF_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, &newValue, + ZCL_BOOLEAN_ATTRIBUTE_TYPE); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(NotSpecified, "ZCL update failed: %lx", status); + } +} diff --git a/examples/lock-app/mbed/main/BoltLockManager.cpp b/examples/lock-app/mbed/main/BoltLockManager.cpp new file mode 100644 index 00000000000000..bb9b3b12e864ba --- /dev/null +++ b/examples/lock-app/mbed/main/BoltLockManager.cpp @@ -0,0 +1,181 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BoltLockManager.h" +#include "AppTask.h" + +#include + +// mbed-os headers +#include "drivers/Timeout.h" +#include "platform/Callback.h" + +static mbed::Timeout sLockTimer; + +BoltLockManager BoltLockManager::sLock; + +void BoltLockManager::Init() +{ + mState = kState_LockingCompleted; + mAutoLockTimerArmed = false; + mAutoRelock = false; + mAutoLockDuration = 0; +} + +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; + mCurrentActor = aActor; + new_state = kState_UnlockingInitiated; + } + else if (mState == kState_UnlockingCompleted && aAction == LOCK_ACTION) + { + action_initiated = true; + mCurrentActor = aActor; + 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(MBED_CONF_APP_ACTUATOR_MOVEMENT_PERIOD_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) +{ + auto chronoTimeoutMs = std::chrono::duration(aTimeoutMs); + sLockTimer.attach(mbed::callback(this, &BoltLockManager::TimerEventHandler), chronoTimeoutMs); +} + +void BoltLockManager::CancelTimer(void) +{ + sLockTimer.detach(); +} + +void BoltLockManager::TimerEventHandler(void) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = this; + event.Handler = mAutoLockTimerArmed ? AutoReLockTimerEventHandler : 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; + + ChipLogProgress(NotSpecified, "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, lock->mCurrentActor); + } + + if (lock->mAutoRelock && actionCompleted == UNLOCK_ACTION) + { + // Start the timer for auto relock + lock->StartTimer(lock->mAutoLockDuration * 1000); + + lock->mAutoLockTimerArmed = true; + + ChipLogProgress(NotSpecified, "Auto Re-lock enabled. Will be triggered in %u seconds", lock->mAutoLockDuration); + } + } +} diff --git a/examples/lock-app/mbed/main/ZclCallbacks.cpp b/examples/lock-app/mbed/main/ZclCallbacks.cpp new file mode 100644 index 00000000000000..2badf2490fd6b4 --- /dev/null +++ b/examples/lock-app/mbed/main/ZclCallbacks.cpp @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "AppTask.h" +#include "BoltLockManager.h" + +#include +#include +#include +#include +#include + +using namespace ::chip; + +void emberAfPostAttributeChangeCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId, uint8_t mask, + uint16_t manufacturerCode, uint8_t type, uint16_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; + } + + BoltLockMgr().InitiateAction(0, *value ? BoltLockManager::LOCK_ACTION : BoltLockManager::UNLOCK_ACTION); +} + +/** @brief OnOff Cluster Init + * + * This function is called when a specific cluster is initialized. It gives the + * application an opportunity to take care of cluster initialization procedures. + * It is called exactly once for each endpoint where cluster is present. + * + * @param endpoint Ver.: always + * + * TODO Issue #3841 + * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster + * attributes to the default value. + * The logic here expects something similar to the deprecated Plugins callback + * emberAfPluginOnOffClusterServerPostInitCallback. + * + */ +void emberAfOnOffClusterInitCallback(EndpointId endpoint) +{ + GetAppTask().UpdateClusterState(); +} diff --git a/examples/lock-app/mbed/main/include/AppEvent.h b/examples/lock-app/mbed/main/include/AppEvent.h new file mode 100644 index 00000000000000..8af36798dda000 --- /dev/null +++ b/examples/lock-app/mbed/main/include/AppEvent.h @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#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 + { + int Pin; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LockEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/lock-app/mbed/main/include/AppTask.h b/examples/lock-app/mbed/main/include/AppTask.h new file mode 100644 index 00000000000000..ad58ece17d1df6 --- /dev/null +++ b/examples/lock-app/mbed/main/include/AppTask.h @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppEvent.h" +#include "BoltLockManager.h" + +class AppTask +{ +public: + int StartApp(); + + void PostEvent(AppEvent * aEvent); + void UpdateClusterState(void); + +private: + friend AppTask & GetAppTask(void); + + int Init(); + + static void ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor); + static void ActionCompleted(BoltLockManager::Action_t aAction, int32_t aActor); + + void CancelTimer(void); + + void DispatchEvent(const AppEvent * event); + + static void FunctionTimerEventHandler(AppEvent * aEvent); + static void FunctionHandler(AppEvent * aEvent); + static void LockActionEventHandler(AppEvent * aEvent); + + void LockButtonPressEventHandler(void); + void FunctionButtonPressEventHandler(void); + void FunctionButtonReleaseEventHandler(void); + void TimerEventHandler(void); + + void StartTimer(uint32_t aTimeoutInMs); + + enum Function_t + { + kFunction_NoneSelected = 0, + kFunction_SoftwareUpdate = 0, + kFunction_FactoryReset, + + kFunction_Invalid + }; + + Function_t mFunction; + bool mFunctionTimerActive; + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/lock-app/mbed/main/include/BoltLockManager.h b/examples/lock-app/mbed/main/include/BoltLockManager.h new file mode 100644 index 00000000000000..19ea411e02eb48 --- /dev/null +++ b/examples/lock-app/mbed/main/include/BoltLockManager.h @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "AppEvent.h" + +class BoltLockManager +{ +public: + enum Action_t + { + LOCK_ACTION = 0, + UNLOCK_ACTION, + + INVALID_ACTION + }; + + enum State_t + { + kState_LockingInitiated = 0, + kState_LockingCompleted, + kState_UnlockingInitiated, + kState_UnlockingCompleted, + }; + + void 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, int32_t aActor); + 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; + int32_t mCurrentActor; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + void TimerEventHandler(void); + 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/mbed/main/include/CHIPProjectConfig.h b/examples/lock-app/mbed/main/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..d0bc1eebf060ce --- /dev/null +++ b/examples/lock-app/mbed/main/include/CHIPProjectConfig.h @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * 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 + +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 1 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 1 + +// Use a default pairing code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +// Enable log filtering. +#define CHIP_LOG_FILTERING 1 diff --git a/examples/lock-app/mbed/main/main.cpp b/examples/lock-app/mbed/main/main.cpp new file mode 100644 index 00000000000000..199a8c70ba2279 --- /dev/null +++ b/examples/lock-app/mbed/main/main.cpp @@ -0,0 +1,82 @@ +/* + * + * 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 "mbedtls/platform.h" +#include +#include +#include + +#ifdef MBED_CONF_MBED_TRACE_ENABLE +#include "mbed-trace/mbed_trace.h" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +int main() +{ + int ret = 0; + +#ifdef MBED_CONF_MBED_TRACE_ENABLE + mbed_trace_init(); + mbed_trace_include_filters_set("BSDS,NETS"); + mbed_trace_config_set(TRACE_ACTIVE_LEVEL_ALL | TRACE_MODE_COLOR); +#endif + + // note: Make sure to turn the filtering on with CHIP_LOG_FILTERING=1 + chip::Logging::SetLogFilter(chip::Logging::LogCategory::kLogCategory_Progress); + + ret = mbedtls_platform_setup(NULL); + if (ret) + { + ChipLogError(NotSpecified, "Mbed TLS platform initialization failed with error %d", ret); + goto exit; + } + + ret = chip::Platform::MemoryInit(); + if (ret != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Platform::MemoryInit() failed"); + goto exit; + } + + ChipLogProgress(NotSpecified, "Init CHIP Stack\r\n"); + ret = PlatformMgr().InitChipStack(); + if (ret != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "PlatformMgr().InitChipStack() failed"); + } + + ChipLogProgress(NotSpecified, "Starting CHIP task"); + ret = PlatformMgr().StartEventLoopTask(); + if (ret != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "PlatformMgr().StartEventLoopTask() failed"); + goto exit; + } + + ret = GetAppTask().StartApp(); + +exit: + ChipLogProgress(NotSpecified, "Exited with code %d", ret); + return ret; +} diff --git a/examples/lock-app/mbed/mbed-os.lib b/examples/lock-app/mbed/mbed-os.lib new file mode 100644 index 00000000000000..b1f64f02f1511f --- /dev/null +++ b/examples/lock-app/mbed/mbed-os.lib @@ -0,0 +1 @@ +https://github.com/ARMmbed/mbed-os#master \ No newline at end of file diff --git a/examples/lock-app/mbed/mbed_app.json b/examples/lock-app/mbed/mbed_app.json new file mode 100644 index 00000000000000..fd619d1b86429d --- /dev/null +++ b/examples/lock-app/mbed/mbed_app.json @@ -0,0 +1,83 @@ +{ + "macros": ["MBEDTLS_USER_CONFIG_FILE=\"chip_mbedtls_config.h\""], + "target_overrides": { + "*": { + "platform.stdio-baud-rate": 115200, + "lwip.ipv6-enabled": true, + "lwip.raw-socket-enabled": true, + "nsapi.default-wifi-security": "WPA_WPA2", + "nsapi.default-wifi-ssid": "\"YOUR_SSID\"", + "nsapi.default-wifi-password": "\"YOUR_PASSWORD\"", + "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", + "mbed-trace.enable": false, + "target.printf_lib": "std" + }, + "DISCO_L475VG_IOT01A": { + "target.components_add": ["wifi_ism43362", "BlueNRG_MS"], + "ism43362.provide-default": true, + "target.network-default-interface-type": "WIFI", + "target.macros_add": ["MBEDTLS_SHA1_C"], + "target.features_add": ["BLE"], + "target.extra_labels_add": ["CORDIO"], + "led-active-state": 1, + "lock-button": "USER_BUTTON", + "function-button": "NC" + }, + "CY8CPROTO_062_4343W": { + "target.network-default-interface-type": "WIFI", + "target.macros_add": [ + "MXCRYPTO_DISABLED", + "NL_ASSERT_LOG=NL_ASSERT_LOG_DEFAULT", + "NL_ASSERT_EXPECT_FLAGS=NL_ASSERT_FLAG_LOG", + "WHD_PRINT_DISABLE" + ], + "led-active-state": 1, + "system-state-led": "LED1", + "lock-state-led": "P9_6", + "lock-button": "USER_BUTTON", + "function-button": "P9_7" + } + }, + "config": { + "system-state-led": { + "help": "System status LED.", + "value": "LED1" + }, + "lock-state-led": { + "help": "Lock status LED.", + "value": "LED2" + }, + "actuator-movement-period-ms": { + "help": "Time it takes in ms for the simulated actuator to move from one state to another.", + "value": 2000 + }, + "led-active-state": { + "help": "GPIO output to turn the LED on.", + "value": 0 + }, + "lock-button": { + "help": "Lock botton pin.", + "value": "BUTTON2" + }, + "function-button": { + "help": "Function button pin.", + "value": "BUTTON1" + }, + "factory-reset-trigger-timeout": { + "help": "'function-button' press timeout to trigger a factory reset (in milliseconds).", + "value": 3000 + }, + "factory-reset-cancel-window-timeout": { + "help": "'function-button' press timeout to cancel a factory reset (in milliseconds). The total 'function-button' press time to have the factory reset actually initiated is equal to 'factory-reset-trigger-timeout' + 'factory-reset-cancel-window-timeout'.", + "value": 3000 + }, + "device-name": { + "help": "Name used for BLE advertising.", + "value": "\"CHIP-lock\"" + }, + "use-gatt-indication-ack-hack": { + "help": "Fake a TX transfer confirmation. Send a 'kCHIPoBLEIndicateConfirm' event as soon as data is sent, without waiting for the actual ACK from the GATT client. This hack has to stay until we provide a fix in the Mbed OS repo.", + "value": 1 + } + } +} diff --git a/examples/lock-app/mbed/wifi-ism43362.lib b/examples/lock-app/mbed/wifi-ism43362.lib new file mode 100644 index 00000000000000..fd1d1bba4efcf9 --- /dev/null +++ b/examples/lock-app/mbed/wifi-ism43362.lib @@ -0,0 +1 @@ +https://github.com/ATmobica/wifi-ism43362#master \ No newline at end of file diff --git a/examples/platform/mbed/util/LEDWidget.cpp b/examples/platform/mbed/util/LEDWidget.cpp new file mode 100644 index 00000000000000..784755dad797d4 --- /dev/null +++ b/examples/platform/mbed/util/LEDWidget.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LEDWidget.h" + +#include + +#ifdef MBED_CONF_APP_LED_ACTIVE_STATE +#define LED_ACTIVE_STATE (MBED_CONF_APP_LED_ACTIVE_STATE) +#else +#define LED_ACTIVE_STATE 0 +#endif + +LEDWidget::LEDWidget(PinName pin) : mLED(pin, !LED_ACTIVE_STATE), mLastChangeTimeMS(0), mBlinkOnTimeMS(0), mBlinkOffTimeMS(0) {} + +void LEDWidget::Invert(void) +{ + Set(!mLED); +} + +void LEDWidget::Set(bool state) +{ + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + mLastChangeTimeMS = 0; + mLED = state ? LED_ACTIVE_STATE : !LED_ACTIVE_STATE; +} + +void LEDWidget::Blink(uint32_t changeRateMS) +{ + Blink(changeRateMS, changeRateMS); +} + +void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) +{ + mBlinkOnTimeMS = onTimeMS; + mBlinkOffTimeMS = offTimeMS; + Animate(); +} + +void LEDWidget::Animate() +{ + if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) + { + uint64_t nowMS = chip::System::Platform::Layer::GetClock_MonotonicMS(); + uint32_t stateDurMS = (mLED == LED_ACTIVE_STATE) ? mBlinkOnTimeMS : mBlinkOffTimeMS; + + if (nowMS > mLastChangeTimeMS + stateDurMS) + { + mLED = !mLED; + mLastChangeTimeMS = nowMS; + } + } +} diff --git a/examples/platform/mbed/util/include/LEDWidget.h b/examples/platform/mbed/util/include/LEDWidget.h new file mode 100644 index 00000000000000..ebe7a80ded469c --- /dev/null +++ b/examples/platform/mbed/util/include/LEDWidget.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "drivers/DigitalOut.h" +#include "platform/platform.h" + +class LEDWidget +{ +public: + LEDWidget(PinName pin); + void Set(bool state); + void Invert(void); + void Blink(uint32_t changeRateMS); + void Blink(uint32_t onTimeMS, uint32_t offTimeMS); + void Animate(); + +private: + mbed::DigitalOut mLED; + uint64_t mLastChangeTimeMS; + uint32_t mBlinkOnTimeMS; + uint32_t mBlinkOffTimeMS; +}; diff --git a/scripts/constraints.txt b/scripts/constraints.txt index b4bf9f50291770..ee8f76b197b2ee 100644 --- a/scripts/constraints.txt +++ b/scripts/constraints.txt @@ -26,10 +26,11 @@ cffi==1.14.5 # via cryptography chardet==4.0.0 # via requests -click==8.0.1 +click==7.1.2 # via # -r requirements.esp32.txt # flask + # mbed-tools # pip-tools colorama==0.4.4 # via west @@ -68,6 +69,10 @@ gdbgui==0.13.2.0 ; platform_machine != "aarch64" # via -r requirements.esp32.txt gevent==1.5.0 # via gdbgui +gitdb==4.0.7 + # via gitpython +gitpython==3.1.14 + # via mbed-tools greenlet==1.1.0 # via gevent humanfriendly==9.2 @@ -85,13 +90,23 @@ itsdangerous==2.0.1 jedi==0.18.0 # via ipython jinja2==3.0.1 - # via flask + # via + # flask + # mbed-tools lockfile==0.12.2 # via -r requirements.txt +mako==1.1.4 + # via pdoc3 +markdown==3.3.4 + # via pdoc3 markupsafe==2.0.1 - # via jinja2 + # via + # jinja2 + # mako matplotlib-inline==0.1.2 # via ipython +mbed-tools==7.22.0 + # via -r requirements.mbed.txt mobly==1.10.1 # via -r requirements.txt numpy==1.20.3 @@ -102,6 +117,8 @@ pandas==1.2.4 ; platform_machine != "aarch64" # via -r requirements.txt parso==0.8.2 # via jedi +pdoc3==0.9.2 + # via mbed-tools pep517==0.10.0 # via pip-tools pexpect==4.8.0 @@ -116,6 +133,8 @@ portpicker==1.4.0 # via # -r requirements.txt # mobly +prettytable==0.7.2 + # via -r requirements.mbed.txt prompt-toolkit==3.0.18 # via ipython protobuf==3.17.3 @@ -123,6 +142,7 @@ protobuf==3.17.3 psutil==5.8.0 # via # -r requirements.txt + # mbed-tools # mobly ptyprocess==0.7.0 # via pexpect @@ -147,17 +167,22 @@ pyparsing==2.3.1 pyserial==3.5 # via # -r requirements.esp32.txt + # mbed-tools # mobly python-dateutil==2.8.1 # via # pandas # pykwalify +python-dotenv==0.17.1 + # via mbed-tools python-engineio==4.2.0 # via python-socketio python-socketio<5 # via flask-socketio pytz==2021.1 # via pandas +pyudev==0.22.0 + # via mbed-tools pyyaml==5.4.1 # via # mobly @@ -165,7 +190,9 @@ pyyaml==5.4.1 reedsolo==1.5.4 # via -r requirements.esp32.txt requests==2.25.1 - # via -r requirements.txt + # via + # -r requirements.txt + # mbed-tools ruamel.yaml.clib==0.2.2 # via ruamel.yaml ruamel.yaml==0.17.9 @@ -176,15 +203,24 @@ six==1.16.0 # ecdsa # protobuf # python-dateutil + # pyudev # virtualenv +smmap==4.0.0 + # via gitdb +tabulate==0.8.9 + # via mbed-tools timeout-decorator==0.5.0 # via mobly toml==0.10.2 # via pep517 +tqdm==4.61.1 + # via mbed-tools traitlets==5.0.5 # via # ipython # matplotlib-inline +typing-extensions==3.10.0.0 + # via mbed-tools urllib3==1.26.5 # via requests virtualenv==20.4.7 diff --git a/scripts/examples/mbed_example.sh b/scripts/examples/mbed_example.sh new file mode 100755 index 00000000000000..b99fcad8d396fa --- /dev/null +++ b/scripts/examples/mbed_example.sh @@ -0,0 +1,145 @@ +#!/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. +# + +cd "$(dirname "$0")"/../.. +CHIP_ROOT=$PWD +cd "$CHIP_ROOT"/examples + +SUPPORTED_TOOLCHAIN=(GCC_ARM ARM) +SUPPORTED_TARGET_BOARD=(DISCO_L475VG_IOT01A CY8CPROTO_062_4343W) +SUPPORTED_APP=(lock-app) +SUPPORTED_PROFILES=(release develop debug) +SUPPORTED_COMMAND=(build flash build-flash) + +COMMAND=build +APP=shell +TARGET_BOARD=CY8CPROTO_062_4343W +TOOLCHAIN=GCC_ARM +PROFILE=release + +for i in "$@"; do + case $i in + -a=* | --app=*) + APP="${i#*=}" + shift + ;; + -b=* | --board=*) + TARGET_BOARD="${i#*=}" + shift + ;; + -t=* | --toolchain=*) + TOOLCHAIN="${i#*=}" + shift + ;; + -p=* | --profile=*) + PROFILE="${i#*=}" + shift + ;; + -c=* | --command=*) + COMMAND="${i#*=}" + shift + ;; + *) + # unknown option + ;; + esac +done + +if [[ ! " ${SUPPORTED_COMMAND[@]} " =~ " ${COMMAND} " ]]; then + echo "ERROR: Command $COMMAND not supported" + exit 1 +fi + +if [[ ! " ${SUPPORTED_TARGET_BOARD[@]} " =~ " ${TARGET_BOARD} " ]]; then + echo "ERROR: Target $TARGET_BOARD not supported" + exit 1 +fi + +if [[ ! " ${SUPPORTED_APP[@]} " =~ " ${APP} " ]]; then + echo "ERROR: Application $APP not supported" + exit 1 +fi + +if [[ ! " ${SUPPORTED_TOOLCHAIN[@]} " =~ " ${TOOLCHAIN} " ]]; then + echo "ERROR: Toolchain $TOOLCHAIN not supported" + exit 1 +fi + +if [[ ! " ${SUPPORTED_PROFILES[@]} " =~ " ${PROFILE} " ]]; then + echo "ERROR: Profile $PROFILE not supported" + exit 1 +fi + +set -e +pwd + +# Activate Matter environment +source "$CHIP_ROOT"/scripts/activate.sh + +# Build directory setup +BUILD_DIRECTORY="$APP"/mbed/build-"$TARGET_BOARD"/"$PROFILE"/ + +if [[ "$COMMAND" == *"build"* ]]; then + echo "Build $APP app for $TARGET_BOARD target with $TOOLCHAIN toolchain and $PROFILE profile" + + # Config directory setup + MBED_CONFIG_PATH="$APP"/mbed/cmake_build/"$TARGET_BOARD"/develop/"$TOOLCHAIN"/ + + # Override Mbed OS path to development directory + MBED_OS_PATH="$CHIP_ROOT"/third_party/mbed-os/repo + + # Create symlinks to mbed-os submodule + ln -sfTr "$MBED_OS_PATH" "$APP/mbed/mbed-os" + + # Create symlinks to mbed-os-posix-socket submodule + MBED_OS_POSIX_SOCKET_PATH="$CHIP_ROOT"/third_party/mbed-os-posix-socket/repo + ln -sfTr "$MBED_OS_POSIX_SOCKET_PATH" "$APP/mbed/mbed-os-posix-socket" + + if [ "$TARGET_BOARD" == "DISCO_L475VG_IOT01A" ]; then + # Add the Mbed OS driver for the ISM43362 Wi-Fi module + WIFI_ISM43362_PATH="$CHIP_ROOT"/third_party/wifi-ism43362/repo + + # Create symlinks to WIFI-ISM43362 submodule + ln -sfTr "$WIFI_ISM43362_PATH" "$APP/mbed/wifi-ism43362" + fi + + # Generate config file for selected target, toolchain and hardware + mbed-tools configure -t "$TOOLCHAIN" -m "$TARGET_BOARD" -p "$APP"/mbed/ + + # Remove old artifacts to force linking + rm -rf "$BUILD_DIRECTORY/chip-"* + + # Create output directory and copy config file there. + mkdir -p "$BUILD_DIRECTORY" + cp -f "$MBED_CONFIG_PATH"/mbed_config.cmake "$BUILD_DIRECTORY"/mbed_config.cmake + + # Build application + cmake -S "$APP/mbed" -B "$BUILD_DIRECTORY" -GNinja -DCMAKE_BUILD_TYPE="$PROFILE" + cmake --build "$BUILD_DIRECTORY" +fi + +if [[ "$COMMAND" == *"flash"* ]]; then + + echo "Flash $APP app to $TARGET_BOARD target [$TOOLCHAIN toolchain, $PROFILE profile]" + + # Flash scripts path setup + MBED_FLASH_SCRIPTS_PATH=$CHIP_ROOT/config/mbed/scripts + + # Flash application + openocd -f "$MBED_FLASH_SCRIPTS_PATH/$TARGET_BOARD".tcl -c "program $BUILD_DIRECTORY/chip-mbed-$APP-example verify reset exit" +fi diff --git a/scripts/python.json b/scripts/python.json index 361a357c40e125..d4fb039e0a0239 100644 --- a/scripts/python.json +++ b/scripts/python.json @@ -3,5 +3,10 @@ "path": "infra/3pp/tools/cpython3/${platform}", "platforms": ["mac-amd64", "windows-amd64"], "tags": ["version:3.8.2.chromium.10"] + }, + { + "path": "fuchsia/third_party/cmake/${platform}", + "platforms": ["mac-amd64", "linux-amd64"], + "tags": ["version:3.20.20210428-g857373c"] } ] diff --git a/scripts/requirements.mbed.txt b/scripts/requirements.mbed.txt new file mode 100644 index 00000000000000..1321b17af98f1b --- /dev/null +++ b/scripts/requirements.mbed.txt @@ -0,0 +1,2 @@ +mbed-tools>=7.0.0 +prettytable==0.7.2 \ No newline at end of file diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 97ce36131da5f6..eb43a3f5bffa0d 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -4,6 +4,9 @@ virtualenv # esp-idf -r requirements.esp32.txt ; platform_machine != 'aarch64' +# mbed-os +-r requirements.mbed.txt ; platform_machine != 'aarch64' + # cirque tests requests>=2.24.0 diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index d2515294dedf0f..bee77faa3fb6f0 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -535,8 +535,8 @@ void InitServer(AppDelegate * delegate) #endif } -// ESP32 examples have a custom logic for enabling DNS-SD -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !CHIP_DEVICE_LAYER_TARGET_ESP32 +// ESP32 and Mbed OS examples have a custom logic for enabling DNS-SD +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !CHIP_DEVICE_LAYER_TARGET_ESP32 && !CHIP_DEVICE_LAYER_TARGET_MBED app::Mdns::StartServer(); #endif diff --git a/src/crypto/crypto.gni b/src/crypto/crypto.gni index 6dc5ec6bf208e0..26722677df7c46 100644 --- a/src/crypto/crypto.gni +++ b/src/crypto/crypto.gni @@ -20,7 +20,7 @@ declare_args() { if (chip_crypto == "") { if (current_os == "android" || current_os == "freertos" || - current_os == "zephyr") { + current_os == "zephyr" || current_os == "mbed") { chip_crypto = "mbedtls" } else { chip_crypto = "openssl" diff --git a/src/inet/InetInterface.cpp b/src/inet/InetInterface.cpp index 69c5a43cf44eb5..ffa1d1132dab7a 100644 --- a/src/inet/InetInterface.cpp +++ b/src/inet/InetInterface.cpp @@ -923,8 +923,14 @@ uint8_t InterfaceAddressIterator::GetPrefixLength() #if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CHIP_SYSTEM_CONFIG_USE_BSD_IFADDRS if (mCurAddr->ifa_addr->sa_family == AF_INET6) { +#if !__MBED__ struct sockaddr_in6 & netmask = *reinterpret_cast(mCurAddr->ifa_netmask); return NetmaskToPrefixLength(netmask.sin6_addr.s6_addr, 16); +#else // __MBED__ + // netmask is not available through an API for IPv6 interface in Mbed. + // Default prefix length to 64. + return 64; +#endif // !__MBED__ } if (mCurAddr->ifa_addr->sa_family == AF_INET) { diff --git a/src/lib/core/core.gni b/src/lib/core/core.gni index 15d6ea268c3757..fdd43dabb6a90c 100644 --- a/src/lib/core/core.gni +++ b/src/lib/core/core.gni @@ -47,7 +47,8 @@ declare_args() { } if (chip_target_style == "") { - if (current_os != "freertos" && current_os != "zephyr") { + if (current_os != "freertos" && current_os != "zephyr" && + current_os != "mbed") { chip_target_style = "unix" } else { chip_target_style = "embedded" diff --git a/src/lib/shell/BUILD.gn b/src/lib/shell/BUILD.gn index c085639113d792..2ff6b94d748df2 100644 --- a/src/lib/shell/BUILD.gn +++ b/src/lib/shell/BUILD.gn @@ -68,6 +68,10 @@ static_library("shell") { sources += [ "streamer_zephyr.cpp" ] } + if (current_os == "mbed") { + sources += [ "streamer_mbed.cpp" ] + } + cflags = [ "-Wconversion" ] public_deps = [ diff --git a/src/lib/shell/streamer_mbed.cpp b/src/lib/shell/streamer_mbed.cpp new file mode 100644 index 00000000000000..88c2c1bf8387e3 --- /dev/null +++ b/src/lib/shell/streamer_mbed.cpp @@ -0,0 +1,63 @@ +/* + * + * 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 + +#include +#include +#include + +namespace chip { +namespace Shell { + +#ifndef SHELL_STREAMER_APP_SPECIFIC + +int streamer_stdio_init(streamer_t * streamer) +{ + return 0; +} + +ssize_t streamer_stdio_read(streamer_t * streamer, char * buf, size_t len) +{ + return fread(buf, 1, len, stdin); +} + +ssize_t streamer_stdio_write(streamer_t * streamer, const char * buf, size_t len) +{ + return fwrite(buf, 1, len, stdout); +} + +static streamer_t streamer_stdio = { + .init_cb = streamer_stdio_init, + .read_cb = streamer_stdio_read, + .write_cb = streamer_stdio_write, +}; + +streamer_t * streamer_get() +{ + return &streamer_stdio; +} + +#endif //#ifndef SHELL_STREAMER_APP_SPECIFIC + +} // namespace Shell +} // namespace chip diff --git a/src/lwip/BUILD.gn b/src/lwip/BUILD.gn index 18521824976345..c60c1af985382b 100644 --- a/src/lwip/BUILD.gn +++ b/src/lwip/BUILD.gn @@ -30,7 +30,8 @@ if (lwip_platform == "") { assert(lwip_platform == "external" || lwip_platform == "standalone" || lwip_platform == "cc13x2_26x2" || lwip_platform == "efr32" || - lwip_platform == "k32w" || lwip_platform == "qpg6100", + lwip_platform == "k32w" || lwip_platform == "qpg6100" || + lwip_platform == "mbed", "Unsupported lwIP platform: ${lwip_platform}") if (lwip_platform != "external") { @@ -67,7 +68,7 @@ buildconfig_header("lwip_buildconfig") { } } -if (current_os == "zephyr") { +if (current_os == "zephyr" || current_os == "mbed") { group("lwip") { } } else if (lwip_platform == "external") { @@ -82,7 +83,7 @@ if (current_os == "zephyr") { config("lwip_config") { include_dirs = [ lwip_platform ] - if (lwip_platform != "standalone") { + if (lwip_platform != "standalone" && lwip_platform != "mbed") { include_dirs += [ "freertos" ] } } diff --git a/src/lwip/lwip.gni b/src/lwip/lwip.gni index 4d94a2c1954b63..89b4808af8fa5a 100644 --- a/src/lwip/lwip.gni +++ b/src/lwip/lwip.gni @@ -14,7 +14,7 @@ declare_args() { # Have the lwIP library available. - chip_with_lwip = current_os != "zephyr" + chip_with_lwip = current_os != "zephyr" && current_os != "mbed" # lwIP platform: standalone, freertos. lwip_platform = "" diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 1de3fd300ac259..4c8fd3b8f32d99 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -169,6 +169,11 @@ if (chip_device_platform != "none") { "CHIP_DEVICE_LAYER_TARGET_TELINK=1", "CHIP_DEVICE_LAYER_TARGET=telink", ] + } else if (chip_device_platform == "mbed") { + defines += [ + "CHIP_DEVICE_LAYER_TARGET_MBED=1", + "CHIP_DEVICE_LAYER_TARGET=mbed", + ] } } } else { @@ -667,6 +672,24 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "telink/ThreadStackManagerImpl.h", ] } + } else if (chip_device_platform == "mbed") { + sources += [ + "mbed/BLEManagerImpl.cpp", + "mbed/BLEManagerImpl.h", + "mbed/ConfigurationManagerImpl.cpp", + "mbed/ConnectivityManagerImpl.cpp", + "mbed/ConnectivityManagerImpl.h", + "mbed/DeviceNetworkProvisioningDelegateImpl.cpp", + "mbed/DeviceNetworkProvisioningDelegateImpl.h", + "mbed/KeyValueStoreManagerImpl.cpp", + "mbed/KeyValueStoreManagerImpl.h", + "mbed/Logging.cpp", + "mbed/MbedConfig.cpp", + "mbed/MbedEventTimeout.cpp", + "mbed/PlatformManagerImpl.cpp", + "mbed/SystemTimeSupport.cpp", + "mbed/arch.c", + ] } if (chip_enable_openthread && chip_mdns == "platform" && diff --git a/src/platform/device.gni b/src/platform/device.gni index ca6715aa6644f1..7cda71261b03c7 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -39,7 +39,8 @@ declare_args() { # Enable wifi support. chip_enable_wifi = - chip_device_platform == "linux" || chip_device_platform == "esp32" + chip_device_platform == "linux" || chip_device_platform == "esp32" || + chip_device_platform == "mbed" # Enable ble support. chip_enable_ble = chip_config_network_layer_ble @@ -48,7 +49,8 @@ declare_args() { chip_enable_nfc = false # Select DNS-SD implementation - if (chip_device_platform == "linux" || chip_device_platform == "esp32") { + if (chip_device_platform == "linux" || chip_device_platform == "esp32" || + chip_device_platform == "mbed") { chip_mdns = "minimal" } else if (chip_device_platform == "darwin" || chip_device_platform == "cc13x2_26x2") { @@ -80,6 +82,8 @@ if (chip_device_platform == "cc13x2_26x2") { _chip_device_layer = "K32W" } else if (chip_device_platform == "telink") { _chip_device_layer = "telink" +} else if (chip_device_platform == "mbed") { + _chip_device_layer = "mbed" } if (chip_device_platform != "external") { @@ -119,5 +123,5 @@ assert( chip_device_platform == "linux" || chip_device_platform == "nrfconnect" || chip_device_platform == "k32w" || chip_device_platform == "qpg6100" || - chip_device_platform == "telink", + chip_device_platform == "telink" || chip_device_platform == "mbed", "Please select a valid value for chip_device_platform") diff --git a/src/platform/mbed/BLEManagerImpl.cpp b/src/platform/mbed/BLEManagerImpl.cpp new file mode 100644 index 00000000000000..ffb66da8ed11b1 --- /dev/null +++ b/src/platform/mbed/BLEManagerImpl.cpp @@ -0,0 +1,1075 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for mbed platforms. + */ + +#include +#include + +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include + +#include +#include +#include +#include + +// Show BLE status with LEDs +#define _BLEMGRIMPL_USE_LEDS 0 + +/* Undefine the BLE_ERROR_NOT_IMPLEMENTED macro provided by CHIP's + * src/ble/BleError.h to avoid a name conflict with Mbed-OS ble_error_t + * enum value. For the enum values, see: + * mbed-os/connectivity/FEATURE_BLE/include/ble/common/blecommon.h + */ +#undef BLE_ERROR_NOT_IMPLEMENTED +// mbed-os headers +#include "ble/BLE.h" +#include "ble/Gap.h" +#include "platform/Callback.h" +#include "platform/NonCopyable.h" +#include "platform/Span.h" + +#if _BLEMGRIMPL_USE_LEDS +#include "drivers/DigitalOut.h" +#endif + +using namespace ::chip; +using namespace ::chip::Ble; +using namespace ::chip::System; + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +namespace { +const UUID ShortUUID_CHIPoBLEService(0xFFF6); +// RX = BleLayer::CHIP_BLE_CHAR_1_ID +const UUID LongUUID_CHIPoBLEChar_RX("18EE2EF5-263D-4559-959F-4F9C429F9D11"); +const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x11 } }; +// TX = BleLayer::CHIP_BLE_CHAR_2_ID +const UUID LongUUID_CHIPoBLEChar_TX("18EE2EF5-263D-4559-959F-4F9C429F9D12"); +const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x12 } }; +} // namespace + +#if _BLEMGRIMPL_USE_LEDS +#include "drivers/DigitalOut.h" +// LED1 -- toggle on every call to ble::BLE::processEvents() +// LED2 -- on when ble::BLE::init() callback completes +// LED3 -- on when advertising +mbed::DigitalOut led1(LED1, 1); +mbed::DigitalOut led2(LED2, 1); +mbed::DigitalOut led3(LED3, 1); +#endif + +class ConnectionInfo +{ +public: + struct ConnStatus + { + ble::connection_handle_t connHandle; + uint16_t attMtuSize; + }; + + ConnectionInfo() + { + for (size_t i = 0; i < kMaxConnections; i++) + { + mConnStates[i].connHandle = kInvalidHandle; + mConnStates[i].attMtuSize = 0; + } + } + + CHIP_ERROR setStatus(ble::connection_handle_t conn_handle, uint16_t mtu_size) + { + size_t new_i = kMaxConnections; + for (size_t i = 0; i < kMaxConnections; i++) + { + if (mConnStates[i].connHandle == conn_handle) + { + mConnStates[i].attMtuSize = mtu_size; + return CHIP_NO_ERROR; + } + else if (mConnStates[i].connHandle == kInvalidHandle && i < new_i) + { + new_i = i; + } + } + // Handle not found, has to be added. + if (new_i == kMaxConnections) + { + return CHIP_ERROR_NO_MEMORY; + } + mConnStates[new_i].connHandle = conn_handle; + mConnStates[new_i].attMtuSize = mtu_size; + return CHIP_NO_ERROR; + } + + CHIP_ERROR clearStatus(ble::connection_handle_t conn_handle) + { + for (size_t i = 0; i < kMaxConnections; i++) + { + if (mConnStates[i].connHandle == conn_handle) + { + mConnStates[i].connHandle = kInvalidHandle; + mConnStates[i].attMtuSize = 0; + return CHIP_NO_ERROR; + } + } + return CHIP_ERROR_INVALID_ARGUMENT; + } + + ConnStatus getStatus(ble::connection_handle_t conn_handle) const + { + for (size_t i = 0; i < kMaxConnections; i++) + { + if (mConnStates[i].connHandle == conn_handle) + { + return mConnStates[i]; + } + } + return { kInvalidHandle, 0 }; + } + + uint16_t getMTU(ble::connection_handle_t conn_handle) const { return getStatus(conn_handle).attMtuSize; } + +private: + const size_t kMaxConnections = BLE_LAYER_NUM_BLE_ENDPOINTS; + ConnStatus mConnStates[BLE_LAYER_NUM_BLE_ENDPOINTS]; + const ble::connection_handle_t kInvalidHandle = 0xf00d; +}; + +static ConnectionInfo sConnectionInfo; + +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +class GapEventHandler : private mbed::NonCopyable, public ble::Gap::EventHandler +{ + void onScanRequestReceived(const ble::ScanRequestEvent & event) + { + // Requires enable action from setScanRequestNotification(true). + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + /* Called when advertising starts. + */ + void onAdvertisingStart(const ble::AdvertisingStartEvent & event) + { +#if _BLEMGRIMPL_USE_LEDS + led3 = 0; +#endif + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + BLEManagerImpl & ble_manager = BLEMgrImpl(); + ble_manager.mFlags.Set(ble_manager.kFlag_Advertising); + ble_manager.mFlags.Clear(ble_manager.kFlag_AdvertisingRefreshNeeded); + + // Post a CHIPoBLEAdvertisingChange(Started) event. + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + chip_event.CHIPoBLEAdvertisingChange.Result = kActivity_Started; + PlatformMgrImpl().PostEvent(&chip_event); + + PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0); + } + + /* Called when advertising ends. + * + * Advertising ends when the process timeout or if it is stopped by the + * application or if the local device accepts a connection request. + */ + void onAdvertisingEnd(const ble::AdvertisingEndEvent & event) + { +#if _BLEMGRIMPL_USE_LEDS + led3 = 1; +#endif + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + BLEManagerImpl & ble_manager = BLEMgrImpl(); + ble_manager.mFlags.Set(ble_manager.kFlag_Advertising); + + // Post a CHIPoBLEAdvertisingChange(Stopped) event. + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + chip_event.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; + PlatformMgrImpl().PostEvent(&chip_event); + + if (event.isConnected()) + { + ble_manager.mFlags.Set(ble_manager.kFlag_AdvertisingRefreshNeeded); + ChipLogDetail(DeviceLayer, "Restarting advertising to allow more connections."); + } + PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0); + } + + /* Called when connection attempt ends or an advertising device has been + * connected. + */ + void onConnectionComplete(const ble::ConnectionCompleteEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + ble_error_t mbed_err = event.getStatus(); + BLEManagerImpl & ble_manager = BLEMgrImpl(); + + if (mbed_err == BLE_ERROR_NONE) + { + const ble::address_t & peer_addr = event.getPeerAddress(); + ChipLogProgress(DeviceLayer, "BLE connection established with %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", peer_addr[5], + peer_addr[4], peer_addr[3], peer_addr[2], peer_addr[1], peer_addr[0]); + ble_manager.mGAPConns++; + CHIP_ERROR err = sConnectionInfo.setStatus(event.getConnectionHandle(), BLE_GATT_MTU_SIZE_DEFAULT); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Unable to store connection status, error: %s ", ErrorStr(err)); + } + } + else + { + ChipLogError(DeviceLayer, "BLE connection failed, mbed-os error: %d", mbed_err); + } + ChipLogProgress(DeviceLayer, "Current number of connections: %" PRIu16 "/%d", ble_manager.NumConnections(), + ble_manager.kMaxConnections); + + // The connection established event is propagated when the client has subscribed to + // the TX characteristic. + } + + void onUpdateConnectionParametersRequest(const ble::UpdateConnectionParametersRequestEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onConnectionParametersUpdateComplete(const ble::ConnectionParametersUpdateCompleteEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onReadPhy(ble_error_t status, ble::connection_handle_t connectionHandle, ble::phy_t txPhy, ble::phy_t rxPhy) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onPhyUpdateComplete(ble_error_t status, ble::connection_handle_t connectionHandle, ble::phy_t txPhy, ble::phy_t rxPhy) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + /* Called when a connection has been disconnected. + */ + void onDisconnectionComplete(const ble::DisconnectionCompleteEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + const ble::disconnection_reason_t & reason = event.getReason(); + BLEManagerImpl & ble_manager = BLEMgrImpl(); + + if (ble_manager.NumConnections()) + { + ble_manager.mGAPConns--; + } + CHIP_ERROR err = sConnectionInfo.clearStatus(event.getConnectionHandle()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Unable to clear connection status, error: %s ", ErrorStr(err)); + } + + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEConnectionError; + chip_event.CHIPoBLEConnectionError.ConId = event.getConnectionHandle(); + switch (reason.value()) + { + case ble::disconnection_reason_t::REMOTE_USER_TERMINATED_CONNECTION: + chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; + break; + case ble::disconnection_reason_t::LOCAL_HOST_TERMINATED_CONNECTION: + chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_APP_CLOSED_CONNECTION; + break; + default: + chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + break; + } + PlatformMgrImpl().PostEvent(&chip_event); + + ChipLogProgress(DeviceLayer, "BLE connection terminated, mbed-os reason: %d", reason.value()); + ChipLogProgress(DeviceLayer, "Current number of connections: %" PRIu16 "/%d", ble_manager.NumConnections(), + ble_manager.kMaxConnections); + + // Force a reconfiguration of advertising in case we switched to non-connectable mode when + // the BLE connection was established. + ble_manager.mFlags.Set(ble_manager.kFlag_AdvertisingRefreshNeeded); + PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0); + } + + void onDataLengthChange(ble::connection_handle_t connectionHandle, uint16_t txSize, uint16_t rxSize) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onPrivacyEnabled() { ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); } +}; + +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +struct CHIPService : public ble::GattServer::EventHandler +{ + CHIPService() {} + CHIPService(const CHIPService &) = delete; + CHIPService & operator=(const CHIPService &) = delete; + + CHIP_ERROR init(ble::BLE & ble_interface) + { + ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); + + if (mCHIPoBLEChar_RX != nullptr || mCHIPoBLEChar_TX != nullptr) + { + return CHIP_NO_ERROR; + } + + mCHIPoBLEChar_RX = new GattCharacteristic(LongUUID_CHIPoBLEChar_RX, nullptr, 0, BLE_GATT_MTU_SIZE_DEFAULT, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); + + mCHIPoBLEChar_TX = new GattCharacteristic(LongUUID_CHIPoBLEChar_TX, nullptr, 0, BLE_GATT_MTU_SIZE_DEFAULT, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + + // Setup callback + mCHIPoBLEChar_RX->setWriteAuthorizationCallback(this, &CHIPService::onWriteAuth); + + GattCharacteristic * chipoble_gatt_characteristics[] = { mCHIPoBLEChar_RX, mCHIPoBLEChar_TX }; + auto num_characteristics = sizeof chipoble_gatt_characteristics / sizeof chipoble_gatt_characteristics[0]; + GattService chipoble_gatt_service(ShortUUID_CHIPoBLEService, chipoble_gatt_characteristics, num_characteristics); + + auto mbed_err = ble_interface.gattServer().addService(chipoble_gatt_service); + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "Unable to add GATT service, mbed-os err: %d", mbed_err); + return CHIP_ERROR_INTERNAL; + } + + // Store the attribute handles in the class so they are reused in + // callbacks to discriminate events. + mRxHandle = mCHIPoBLEChar_RX->getValueHandle(); + mTxHandle = mCHIPoBLEChar_TX->getValueHandle(); + // There is a single descriptor in the characteristic, CCCD is at index 0 + mTxCCCDHandle = mCHIPoBLEChar_TX->getDescriptor(0)->getHandle(); + ChipLogDetail(DeviceLayer, "char handles: rx=%d, tx=%d, cccd=%d", mRxHandle, mTxHandle, mTxCCCDHandle); + + ble_interface.gattServer().setEventHandler(this); + return CHIP_NO_ERROR; + } + + // Write authorization callback + void onWriteAuth(GattWriteAuthCallbackParams * params) + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params->connHandle, params->handle); + if (params->handle == mRxHandle) + { + ChipLogDetail(DeviceLayer, "Received BLE packet on RX"); + + // Allocate a buffer, copy the data. They will be passed into the event + auto buf = System::PacketBufferHandle::NewWithData(params->data, params->len); + if (buf.IsNull()) + { + params->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_REQUEST_REJECTED; + ChipLogError(DeviceLayer, "Dropping packet, not enough memory"); + return; + } + + params->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; + + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEWriteReceived; + chip_event.CHIPoBLEWriteReceived.ConId = params->connHandle; + chip_event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); + PlatformMgrImpl().PostEvent(&chip_event); + } + else + { + params->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_HANDLE; + } + } + + // overrides of GattServerEvent Handler + void onAttMtuChange(ble::connection_handle_t connectionHandle, uint16_t attMtuSize) override + { + ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); + CHIP_ERROR err = sConnectionInfo.setStatus(connectionHandle, attMtuSize); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Unable to store connection status, error: %s ", ErrorStr(err)); + } + } + + void onDataSent(const GattDataSentCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + + // FIXME: ACK hack +#if (defined(MBED_CONF_APP_USE_GATT_INDICATION_ACK_HACK) && (MBED_CONF_APP_USE_GATT_INDICATION_ACK_HACK != 0)) + onConfirmationReceived(params); +#endif + } + + void onDataWritten(const GattWriteCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.handle); + } + + void onDataRead(const GattReadCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.handle); + } + + void onShutdown(const ble::GattServer & server) override { ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); } + + void onUpdatesEnabled(const GattUpdatesEnabledCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + if (params.attHandle == mTxCCCDHandle) + { + ChipLogDetail(DeviceLayer, "Updates enabled on TX CCCD"); + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLESubscribe; + chip_event.CHIPoBLESubscribe.ConId = params.connHandle; + PlatformMgrImpl().PostEvent(&chip_event); + } + } + + void onUpdatesDisabled(const GattUpdatesDisabledCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + if (params.attHandle == mTxCCCDHandle) + { + ChipLogDetail(DeviceLayer, "Updates disabled on TX CCCD"); + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEUnsubscribe; + chip_event.CHIPoBLEUnsubscribe.ConId = params.connHandle; + PlatformMgrImpl().PostEvent(&chip_event); + } + } + + void onConfirmationReceived(const GattConfirmationReceivedCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + if (params.attHandle == mTxHandle) + { + ChipLogDetail(DeviceLayer, "Confirmation received for TX transfer"); + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; + chip_event.CHIPoBLEIndicateConfirm.ConId = params.connHandle; + PlatformMgrImpl().PostEvent(&chip_event); + } + } + + ble::attribute_handle_t getTxHandle() const { return mTxHandle; } + ble::attribute_handle_t getTxCCCDHandle() const { return mTxCCCDHandle; } + ble::attribute_handle_t getRxHandle() const { return mRxHandle; } + + GattCharacteristic * mCHIPoBLEChar_RX = nullptr; + GattCharacteristic * mCHIPoBLEChar_TX = nullptr; + ble::attribute_handle_t mRxHandle = 0; + ble::attribute_handle_t mTxCCCDHandle = 0; + ble::attribute_handle_t mTxHandle = 0; +}; + +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +class SecurityManagerEventHandler : private mbed::NonCopyable, + public ble::SecurityManager::EventHandler +{ + void pairingRequest(ble::connection_handle_t connectionHandle) override + { + ChipLogDetail(DeviceLayer, "SM %s, connHandle=%d", __FUNCTION__, connectionHandle); + ble::SecurityManager & security_mgr = ble::BLE::Instance().securityManager(); + + auto mbed_err = security_mgr.acceptPairingRequest(connectionHandle); + if (mbed_err == BLE_ERROR_NONE) + { + ChipLogProgress(DeviceLayer, "Pairing request authorized."); + } + else + { + ChipLogError(DeviceLayer, "Pairing request not authorized, mbed-os err: %d", mbed_err); + } + } + + void pairingResult(ble::connection_handle_t connectionHandle, SecurityManager::SecurityCompletionStatus_t result) override + { + ChipLogDetail(DeviceLayer, "SM %s, connHandle=%d", __FUNCTION__, connectionHandle); + if (result == SecurityManager::SEC_STATUS_SUCCESS) + { + ChipLogProgress(DeviceLayer, "Pairing successful."); + } + else + { + ChipLogError(DeviceLayer, "Pairing failed, status: 0x%X.", result); + } + } + + void linkEncryptionResult(ble::connection_handle_t connectionHandle, ble::link_encryption_t result) override + { + ChipLogDetail(DeviceLayer, "SM %s, connHandle=%d", __FUNCTION__, connectionHandle); + if (result == ble::link_encryption_t::NOT_ENCRYPTED) + { + ChipLogDetail(DeviceLayer, "Link NOT_ENCRYPTED."); + } + else if (result == ble::link_encryption_t::ENCRYPTION_IN_PROGRESS) + { + ChipLogDetail(DeviceLayer, "Link ENCRYPTION_IN_PROGRESS."); + } + else if (result == ble::link_encryption_t::ENCRYPTED) + { + ChipLogDetail(DeviceLayer, "Link ENCRYPTED."); + } + else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) + { + ChipLogDetail(DeviceLayer, "Link ENCRYPTED_WITH_MITM."); + } + else if (result == ble::link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM) + { + ChipLogDetail(DeviceLayer, "Link ENCRYPTED_WITH_SC_AND_MITM."); + } + else + { + ChipLogDetail(DeviceLayer, "Link encryption status UNKNOWN."); + } + } +}; + +BLEManagerImpl BLEManagerImpl::sInstance; +static GapEventHandler sMbedGapEventHandler; +static CHIPService sCHIPService; +static SecurityManagerEventHandler sSecurityManagerEventHandler; + +/* Initialize the mbed-os BLE subsystem. Register the BLE event processing + * callback to the system event queue. Register the BLE initialization complete + * callback that handles the rest of the setup commands. Register the BLE GAP + * event handler. + */ +CHIP_ERROR BLEManagerImpl::_Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + mFlags = BitFlags(CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? kFlag_AdvertisingEnabled : 0); + mGAPConns = 0; + + ble::BLE & ble_interface = ble::BLE::Instance(); + + ble_interface.gap().setEventHandler(&sMbedGapEventHandler); + err = sCHIPService.init(ble_interface); + SuccessOrExit(err); + + ble_interface.onEventsToProcess(FunctionPointerWithContext{ + [](ble::BLE::OnEventsToProcessCallbackContext * context) { PlatformMgr().ScheduleWork(DoBLEProcessing, 0); } }); + + mbed_err = ble_interface.init([](ble::BLE::InitializationCompleteCallbackContext * context) { + BLEMgrImpl().HandleInitComplete(context->error == BLE_ERROR_NONE); + }); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + +exit: + return err; +} + +/* Process all the events from the mbed-os BLE subsystem. + */ +void BLEManagerImpl::DoBLEProcessing(intptr_t arg) +{ +#if _BLEMGRIMPL_USE_LEDS + led1 = !led1; +#endif + ble::BLE::Instance().processEvents(); +} + +/* This is the mbed-os BLE subsystem init complete callback. Initialize the + * BLELayer and update the state based on the flags. + */ +void BLEManagerImpl::HandleInitComplete(bool no_error) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::Gap & gap = ble::BLE::Instance().gap(); + ble::SecurityManager & security_mgr = ble::BLE::Instance().securityManager(); + ble::own_address_type_t addr_type; + ble::address_t addr; + + VerifyOrExit(no_error, err = CHIP_ERROR_INTERNAL); + + gap.getAddress(addr_type, addr); + ChipLogDetail(DeviceLayer, "Device address: %02X:%02X:%02X:%02X:%02X:%02X", addr[5], addr[4], addr[3], addr[2], addr[1], + addr[0]); + + mbed_err = security_mgr.init( + /*bool enableBonding */ false, + /*bool requireMITM */ true, + /*SecurityIOCapabilities_t iocaps*/ SecurityManager::IO_CAPS_NONE, + /*const Passkey_t passkey */ nullptr, + /*bool signing */ true, + /*const char *dbFilepath */ nullptr); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = security_mgr.setPairingRequestAuthorisation(true); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + security_mgr.setSecurityManagerEventHandler(&sSecurityManagerEventHandler); + + err = BleLayer::Init(this, this, &SystemLayer); + SuccessOrExit(err); + PlatformMgr().ScheduleWork(DriveBLEState, 0); +#if _BLEMGRIMPL_USE_LEDS + led2 = 0; +#endif + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "BLEManager init error: %s ", ErrorStr(err)); + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service."); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } +} + +void BLEManagerImpl::DriveBLEState(intptr_t arg) +{ + BLEMgrImpl().DriveBLEState(); +} + +/* Update the advertising state based on the flags. + */ +void BLEManagerImpl::DriveBLEState() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Perform any initialization actions that must occur after the CHIP task is running. + if (!mFlags.Has(kFlag_AsyncInitCompleted)) + { + mFlags.Set(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()) + { + mFlags.Clear(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 && + mFlags.Has(kFlag_AdvertisingEnabled) +#if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION + // and no connections are active... + && (_NumConnections() == 0) +#endif + ) + { + // Start/re-start advertising if not already advertising, or if the + // advertising state needs to be refreshed. + if (!mFlags.Has(kFlag_Advertising) || mFlags.Has(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; + } +} + +CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) +{ + switch (mode) + { + case BLEAdvertisingMode::kFastAdvertising: + mFlags.Set(Flags::kFlag_FastAdvertisingEnabled, true); + break; + case BLEAdvertisingMode::kSlowAdvertising: + mFlags.Set(Flags::kFlag_AdvertisingEnabled, false); + break; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + mFlags.Set(Flags::kFlag_AdvertisingRefreshNeeded); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; +} + +/* Build the advertising data and start advertising. + */ +CHIP_ERROR BLEManagerImpl::StartAdvertising(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::Gap & gap = ble::BLE::Instance().gap(); + ble::AdvertisingDataBuilder adv_data_builder(mAdvertisingDataBuffer); + + ChipBLEDeviceIdentificationInfo dev_id_info; + + // Advertise CONNECTABLE if we haven't reached the maximum number of connections. + uint16_t num_conns = _NumConnections(); + bool connectable = (num_conns < kMaxConnections); + ble::advertising_type_t adv_type = + connectable ? ble::advertising_type_t::CONNECTABLE_UNDIRECTED : ble::advertising_type_t::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. + ble::adv_interval_t adv_interval = (num_conns == 0 && !ConfigurationMgr().IsFullyProvisioned()) + ? ble::adv_interval_t(CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX) + : ble::adv_interval_t(CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX); + // minInterval and maxInterval are equal for CHIP. + ble::AdvertisingParameters adv_params(adv_type, adv_interval, adv_interval); + + // Restart advertising if already active. + if (gap.isAdvertisingActive(ble::LEGACY_ADVERTISING_HANDLE)) + { + mbed_err = gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + ChipLogDetail(DeviceLayer, "Advertising already active. Restarting."); + } + + mbed_err = gap.setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_params); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = + adv_data_builder.setFlags(ble::adv_data_flags_t::BREDR_NOT_SUPPORTED | ble::adv_data_flags_t::LE_GENERAL_DISCOVERABLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + if (!mFlags.Has(kFlag_UseCustomDeviceName)) + { + uint16_t discriminator; + SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator)); + memset(mDeviceName, 0, kMaxDeviceNameLength); + snprintf(mDeviceName, kMaxDeviceNameLength, "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); + } + mbed_err = adv_data_builder.setName(mDeviceName); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + dev_id_info.Init(); + SuccessOrExit(ConfigurationMgr().GetBLEDeviceIdentificationInfo(dev_id_info)); + mbed_err = adv_data_builder.setServiceData( + ShortUUID_CHIPoBLEService, mbed::make_Span(reinterpret_cast(&dev_id_info), sizeof dev_id_info)); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = gap.setAdvertisingPayload(ble::LEGACY_ADVERTISING_HANDLE, adv_data_builder.getAdvertisingData()); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + adv_data_builder.clear(); + adv_data_builder.setLocalServiceList(mbed::make_Span(&ShortUUID_CHIPoBLEService, 1)); + mbed_err = gap.setAdvertisingScanResponse(ble::LEGACY_ADVERTISING_HANDLE, adv_data_builder.getAdvertisingData()); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = gap.startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + ChipLogDetail(DeviceLayer, "Advertising started, type: 0x%x (%sconnectable), interval: [%lu:%lu] ms, device name: %s)", + adv_params.getType().value(), connectable ? "" : "non-", adv_params.getMinPrimaryInterval().valueInMs(), + adv_params.getMaxPrimaryInterval().valueInMs(), mDeviceName); + +exit: + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "StartAdvertising mbed-os error: %d", mbed_err); + } + return err; +} + +CHIP_ERROR BLEManagerImpl::StopAdvertising(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::Gap & gap = ble::BLE::Instance().gap(); + + if (!gap.isAdvertisingActive(ble::LEGACY_ADVERTISING_HANDLE)) + { + ChipLogDetail(DeviceLayer, "No need to stop. Advertising inactive."); + return err; + } + mbed_err = gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + +exit: + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "StopAdvertising mbed-os error: %d", mbed_err); + } + 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 (mFlags.Has(kFlag_AdvertisingEnabled) != val) + { + ChipLogDetail(DeviceLayer, "SetAdvertisingEnabled(%s)", val ? "true" : "false"); + + mFlags.Set(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 (mFlags.Has(kFlag_FastAdvertisingEnabled) != val) + { + ChipLogDetail(DeviceLayer, "SetFastAdvertisingEnabled(%s)", val ? "true" : "false"); + + mFlags.Set(kFlag_FastAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(strlen(mDeviceName) < bufSize, err = CHIP_ERROR_BUFFER_TOO_SMALL); + strcpy(buf, mDeviceName); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (deviceName != nullptr && deviceName[0] != '\0') + { + VerifyOrExit(strlen(deviceName) < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); + strcpy(mDeviceName, deviceName); + mFlags.Set(kFlag_UseCustomDeviceName); + ChipLogDetail(DeviceLayer, "Device name set to: %s", deviceName); + } + else + { + mDeviceName[0] = '\0'; + mFlags.Clear(kFlag_UseCustomDeviceName); + } + +exit: + return err; +} + +uint16_t BLEManagerImpl::_NumConnections(void) +{ + return mGAPConns; +} + +void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLESubscribe: { + ChipDeviceEvent connEstEvent; + + ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLESubscribe"); + HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgrImpl().PostEvent(&connEstEvent); + } + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: { + ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEUnsubscribe"); + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + } + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: { + ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived"); + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + } + break; + + case DeviceEventType::kCHIPoBLEConnectionError: { + ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEConnectionError"); + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + } + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: { + ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEIndicateConfirm"); + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + } + break; + + default: + ChipLogDetail(DeviceLayer, "_OnPlatformEvent default: event->Type = 0x%x", event->Type); + break; + } +} + +void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) +{ + // no-op +} + +bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) +{ + ChipLogProgress(DeviceLayer, "Closing BLE GATT connection, connHandle=%d", conId); + + ble::Gap & gap = ble::BLE::Instance().gap(); + + ble_error_t mbed_err = gap.disconnect(conId, ble::local_disconnection_reason_t::USER_TERMINATION); + return mbed_err == BLE_ERROR_NONE; +} + +uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const +{ + return sConnectionInfo.getMTU(conId); +} + +bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogDetail(DeviceLayer, "BlePlatformDelegate %s", __FUNCTION__); + + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::GattServer & gatt_server = ble::BLE::Instance().gattServer(); + ble::attribute_handle_t att_handle; + + // No need to do anything fancy here. Only 3 handles are used in this impl. + if (UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX)) + { + att_handle = sCHIPService.getTxHandle(); + } + else if (UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_RX)) + { + // TODO does this make sense? + att_handle = sCHIPService.getRxHandle(); + } + else + { + // TODO handle error with chipConnection::SendMessage as described + // in the BlePlatformDelegate.h. + ChipLogError(DeviceLayer, "Send indication failed, invalid charID."); + return false; + } + + ChipLogDetail(DeviceLayer, + "Sending indication for CHIPoBLE characteristic " + "(connHandle=%d, attHandle=%d, data_len=%" PRIu16 ")", + conId, att_handle, pBuf->DataLength()); + + mbed_err = gatt_server.write(att_handle, pBuf->Start(), pBuf->DataLength(), false); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + +exit: + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "Send indication failed, mbed-os error: %d", mbed_err); + } + return err == CHIP_NO_ERROR; +} + +bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, + const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/mbed/BLEManagerImpl.h b/src/platform/mbed/BLEManagerImpl.h new file mode 100644 index 00000000000000..0c02bad5bf42bf --- /dev/null +++ b/src/platform/mbed/BLEManagerImpl.h @@ -0,0 +1,176 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for the Mbed platform. + */ + +#pragma once + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +class GapEventHandler; +class CHIPService; + +using namespace chip::Ble; + +/** + * Concrete implementation of the BLEManager singleton object for the Mbed platform. + */ +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; + + // ===== Members that implement the BLEManager internal interface. + + CHIP_ERROR _Init(void); + CHIPoBLEServiceMode _GetCHIPoBLEServiceMode(void); + CHIP_ERROR _SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val); + bool _IsAdvertisingEnabled(void); + CHIP_ERROR _SetAdvertisingMode(BLEAdvertisingMode mode); + 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 ChipBleUUID * svcId, const ChipBleUUID * charId); + bool UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId); + bool CloseConnection(BLE_CONNECTION_OBJECT conId); + uint16_t GetMTU(BLE_CONNECTION_OBJECT conId) const; + bool SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf); + bool SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf); + bool SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf); + bool SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, const ChipBleUUID * svcId, + const ChipBleUUID * charId); + + // ===== Members that implement virtual methods on BleApplicationDelegate. + + void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId); + + // ===== Members for internal use by the following friends. + + friend BLEManager & BLEMgr(void); + friend BLEManagerImpl & BLEMgrImpl(void); + friend class GapEventHandler; + friend class CHIPService; + + static BLEManagerImpl sInstance; + + // ===== Private members reserved for use by this class only. + + enum Flags : uint16_t + { + 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 configuration/state in BLE layer needs to be updated. */ + kFlag_DeviceNameSet = 0x0020, + kFlag_UseCustomDeviceName = 0x0040, /**< The application has configured a custom BLE device name. */ + }; + + enum : size_t + { + kMaxConnections = BLE_LAYER_NUM_BLE_ENDPOINTS, + kMaxDeviceNameLength = 16, + kAdvertisingDataSize = 0x1F, // mbed-os ble::LEGACY_ADVERTISING_MAX_SIZE + }; + + CHIPoBLEServiceMode mServiceMode; + BitFlags mFlags; + uint16_t mGAPConns; + char mDeviceName[kMaxDeviceNameLength + 1]; + uint8_t mAdvertisingDataBuffer[kAdvertisingDataSize]; + + static void DoBLEProcessing(intptr_t arg); + void HandleInitComplete(bool no_error); + static void DriveBLEState(intptr_t arg); + void DriveBLEState(void); + CHIP_ERROR StartAdvertising(void); + CHIP_ERROR StopAdvertising(void); +}; + +/** + * Returns a reference to the public interface of the BLEManager singleton object. + * + * Internal components should use this to access features of the BLEManager object + * that are common to all platforms. + */ +inline BLEManager & BLEMgr(void) +{ + return BLEManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the BLEManager singleton object. + * + * Internal components can use this to gain access to features of the BLEManager + * that are specific to the Mbed platform. + */ +inline BLEManagerImpl & BLEMgrImpl(void) +{ + return BLEManagerImpl::sInstance; +} + +inline BleLayer * BLEManagerImpl::_GetBleLayer() +{ + return this; +} + +inline BLEManager::CHIPoBLEServiceMode BLEManagerImpl::_GetCHIPoBLEServiceMode(void) +{ + return mServiceMode; +} + +inline bool BLEManagerImpl::_IsAdvertisingEnabled(void) +{ + return mFlags.Has(Flags::kFlag_AdvertisingEnabled); +} + +inline bool BLEManagerImpl::_IsFastAdvertisingEnabled(void) +{ + return mFlags.Has(Flags::kFlag_FastAdvertisingEnabled); +} + +inline bool BLEManagerImpl::_IsAdvertising(void) +{ + return mFlags.Has(Flags::kFlag_Advertising); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/mbed/BUILD.gn b/src/platform/mbed/BUILD.gn new file mode 100644 index 00000000000000..414dfca3556537 --- /dev/null +++ b/src/platform/mbed/BUILD.gn @@ -0,0 +1,4 @@ +import("//build_overrides/chip.gni") +import("${chip_root}/src/platform/device.gni") + +assert(chip_device_platform == "mbed") diff --git a/src/platform/mbed/BlePlatformConfig.h b/src/platform/mbed/BlePlatformConfig.h new file mode 100644 index 00000000000000..03e25d5214c7a0 --- /dev/null +++ b/src/platform/mbed/BlePlatformConfig.h @@ -0,0 +1,44 @@ +/* + * + * 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 mbed platforms. + * + */ + +#pragma once + +// ==================== Platform Adaptations ==================== + +#define BLE_CONNECTION_OBJECT uintptr_t +#define BLE_CONNECTION_UNINITIALIZED ((uintptr_t) -1) +#define BLE_MAX_RECEIVE_WINDOW_SIZE 5 + +#define BLE_CONFIG_ERROR_TYPE int32_t +#define BLE_CONFIG_ERROR_FORMAT PRId32 + +#define BLE_CONFIG_NO_ERROR 0 +#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/mbed/CHIPDevicePlatformConfig.h b/src/platform/mbed/CHIPDevicePlatformConfig.h new file mode 100644 index 00000000000000..6423767e5109c6 --- /dev/null +++ b/src/platform/mbed/CHIPDevicePlatformConfig.h @@ -0,0 +1,48 @@ +/* + * + * 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 + * Platform-specific configuration overrides for the chip Device Layer + * on mbed platform. + */ + +#pragma once + +// ==================== Platform Adaptations ==================== + +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD 0 +#define CHIP_DEVICE_CONFIG_THREAD_FTD 0 + +#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 + +#define CHIP_DEVICE_CONFIG_ENABLE_MDNS 1 + +#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE +#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE 8192 +#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE + +// ========== Platform-specific Configuration Overrides ========= + +#define CHIP_DEVICE_CONFIG_LOG_PROVISIONING_HASH 0 diff --git a/src/platform/mbed/CHIPDevicePlatformEvent.h b/src/platform/mbed/CHIPDevicePlatformEvent.h new file mode 100644 index 00000000000000..4a5f85ad105d3e --- /dev/null +++ b/src/platform/mbed/CHIPDevicePlatformEvent.h @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Defines platform-specific event types and data for the chip + * Device Layer on mbed platforms. + */ + +#pragma once + +#include + +namespace chip { +namespace System { +class PacketBuffer; +} // namespace System +} // namespace chip + +namespace chip { +namespace DeviceLayer { + +namespace DeviceEventType { + +/** + * Enumerates Zephyr platform-specific event types that are visible to the application. + */ +enum PublicPlatformSpecificEventTypes +{ + /* None currently defined */ +}; + +/** + * Enumerates mbed platform-specific event types that are internal to the chip Device Layer. + */ +enum InternalPlatformSpecificEventTypes +{ + +}; + +} // namespace DeviceEventType + +struct BleConnEventType +{ +}; + +struct BleCCCWriteEventType +{ +}; + +struct BleC1WriteEventType +{ +}; + +struct BleC2IndDoneEventType +{ +}; + +/** + * Represents platform-specific event information for Zephyr platforms. + */ +struct ChipDevicePlatformEvent final +{ + union + { + BleConnEventType BleConnEvent; + BleCCCWriteEventType BleCCCWriteEvent; + BleC1WriteEventType BleC1WriteEvent; + BleC2IndDoneEventType BleC2IndDoneEvent; + }; +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/CHIPPlatformConfig.h b/src/platform/mbed/CHIPPlatformConfig.h new file mode 100644 index 00000000000000..91f96beef874e4 --- /dev/null +++ b/src/platform/mbed/CHIPPlatformConfig.h @@ -0,0 +1,129 @@ +/* + * + * 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 + * mbed platforms. + */ + +#pragma once + +#include + +// ==================== General Platform Adaptations ==================== + +#define CHIP_CONFIG_ERROR_TYPE int32_t +#define CHIP_CONFIG_NO_ERROR 0 +#define CHIP_CONFIG_ERROR_MIN 4000000 +#define CHIP_CONFIG_ERROR_MAX 4000999 + +#define ASN1_CONFIG_ERROR_TYPE int32_t +#define ASN1_CONFIG_NO_ERROR 0 +#define ASN1_CONFIG_ERROR_MIN 5000000 +#define ASN1_CONFIG_ERROR_MAX 5000999 + +#define ChipDie() abort() + +#define CHIP_CONFIG_PERSISTED_STORAGE_KEY_TYPE const char * +#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 + +// FIXME: EFR32 set to MBED-TLS (But this is third-party repo in CHIP, not SDK) + +#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 + +// FIXME: EFR32 currently set to CHIP (Does this use Entropy.cpp ?) + +#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_MAX_INTERFACES +#define CHIP_CONFIG_MAX_INTERFACES 4 +#endif // CHIP_CONFIG_MAX_INTERFACES + +#ifndef CHIP_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS +#define CHIP_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS 4 +#endif // CHIP_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS + +// ==================== 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/mbed/ConfigurationManagerImpl.cpp b/src/platform/mbed/ConfigurationManagerImpl.cpp new file mode 100644 index 00000000000000..b81657523bb70a --- /dev/null +++ b/src/platform/mbed/ConfigurationManagerImpl.cpp @@ -0,0 +1,129 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides the implementation of the Device Layer ConfigurationManager object + * for mbed platforms. + */ +/* this file behaves like a config.h, comes first */ + +// FIXME: Undefine the `sleep()` function included by the CHIPDeviceLayer.h +// from unistd.h to avoid a conflicting declaration with the `sleep()` provided +// by Mbed-OS in mbed_power_mgmt.h. +#define sleep unistd_sleep +#include +#undef sleep + +#include + +#include + +// mbed-os headers +#include "platform/mbed_power_mgmt.h" + +namespace chip { +namespace DeviceLayer { + +using namespace ::chip::DeviceLayer::Internal; + +/** Singleton instance of the ConfigurationManager implementation object. + */ +ConfigurationManagerImpl ConfigurationManagerImpl::sInstance; + +CHIP_ERROR ConfigurationManagerImpl::_Init() +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConfigurationManagerImpl::_GetPrimaryWiFiMACAddress(uint8_t * buf) +{ + auto interface = WiFiInterface::get_default_instance(); + if (interface) + { + auto * mac_address = interface->get_mac_address(); + if (mac_address) + { + int last = -1; + int rc = + sscanf(mac_address, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n", buf + 5, buf + 4, buf + 3, buf + 2, buf + 1, buf + 0, &last); + if (rc != NSAPI_MAC_BYTES || last != (NSAPI_MAC_SIZE - 1)) + { + ChipLogError(DeviceLayer, "Failed to extract the MAC address: %s, rc = %d, last = %d", mac_address, rc, last); + return CHIP_ERROR_INTERNAL; + } + else + { + ChipLogError(DeviceLayer, "Extract the MAC address: %s", mac_address); + return CHIP_NO_ERROR; + } + } + else + { + ChipLogError(DeviceLayer, "Failed to extract the MAC address: nothing returned by the interface"); + return CHIP_ERROR_INTERNAL; + } + } + else + { + ChipLogError(DeviceLayer, "Failed to extract the MAC address: interface not available"); + return CHIP_ERROR_INTERNAL; + } +} + +bool ConfigurationManagerImpl::_CanFactoryReset() +{ + return true; +} + +void ConfigurationManagerImpl::_InitiateFactoryReset(void) +{ + PlatformMgr().ScheduleWork(DoFactoryReset); +} + +CHIP_ERROR ConfigurationManagerImpl::_ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value) +{ + CHIP_ERROR err = ReadConfigValue(key, value); + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + return err; +} + +CHIP_ERROR ConfigurationManagerImpl::_WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value) +{ + return WriteCounter(key, value); +} + +void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) +{ + ChipLogProgress(DeviceLayer, "Performing factory reset"); + const CHIP_ERROR err = FactoryResetConfig(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "FactoryResetConfig() failed: %s", ErrorStr(err)); + } + + // Restart the system. + ChipLogProgress(DeviceLayer, "System restarting"); + system_reset(); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/ConfigurationManagerImpl.h b/src/platform/mbed/ConfigurationManagerImpl.h new file mode 100644 index 00000000000000..74c33c1e2f510c --- /dev/null +++ b/src/platform/mbed/ConfigurationManagerImpl.h @@ -0,0 +1,103 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides an implementation of the ConfigurationManager object + * for mbed platforms. + */ + +#pragma once + +#include +#include + +// Forward declare test method that run the tests. +int cmd_device_test_config(int argc, char ** argv); + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the ConfigurationManager singleton object for the Zephyr platform. + */ +class ConfigurationManagerImpl final : public ConfigurationManager, + public Internal::GenericConfigurationManagerImpl, + private Internal::MbedConfig +{ + // 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); + + // ===== Members for internal use by the following friends (testing in shell application) + friend int ::cmd_device_test_config(int argc, char ** argv); + using MbedConfig::RunConfigUnitTest; +}; + +/** + * 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 nRF Connect SDK platform. + */ +inline ConfigurationManagerImpl & ConfigurationMgrImpl(void) +{ + return ConfigurationManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/ConnectivityManagerImpl.cpp b/src/platform/mbed/ConnectivityManagerImpl.cpp new file mode 100644 index 00000000000000..9062fcf168eaa8 --- /dev/null +++ b/src/platform/mbed/ConnectivityManagerImpl.cpp @@ -0,0 +1,422 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* this file behaves like a config.h, comes first */ + +#include "netsocket/WiFiInterface.h" +#include + +#include +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include +#endif +#include + +#include +#include +#include + +#include + +#if !CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +#error "WiFi Station support must be enabled when building for mbed" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer::Internal; + +namespace chip { +namespace DeviceLayer { + +ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; + +ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode(void) +{ + return mWiFiStationMode; +} + +bool ConnectivityManagerImpl::_IsWiFiStationEnabled(void) +{ + return GetWiFiStationMode() == kWiFiStationMode_Enabled; +} + +bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled(void) +{ + return mWiFiStationMode == kWiFiStationMode_ApplicationControlled; +} + +CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(WiFiStationMode val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(val != kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); + + if (mWiFiStationMode != val) + { + ChipLogDetail(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode), + WiFiStationModeToStr(val)); + } + + mWiFiStationMode = val; + +exit: + return err; +} + +bool ConnectivityManagerImpl::_IsWiFiStationConnected(void) +{ + return mWiFiStationState == kWiFiStationState_Connected; +} + +bool ConnectivityManagerImpl::_IsWiFiStationProvisioned(void) +{ + return mIsProvisioned; +} + +CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +// ==================== ConnectivityManager Platform Internal Methods ==================== + +CHIP_ERROR ConnectivityManagerImpl::_Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + mWiFiStationMode = kWiFiStationMode_NotSupported; + mWiFiStationState = kWiFiStationState_NotConnected; + mIsProvisioned = false; + mIp4Address = IPAddress::Any; + mIp6Address = IPAddress::Any; + mWiFiAPMode = kWiFiAPMode_NotSupported; + mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL; + mWiFiAPIdleTimeoutMS = CHIP_DEVICE_CONFIG_WIFI_AP_IDLE_TIMEOUT; + mSecurityType = NSAPI_SECURITY_WPA_WPA2; + + NetworkInterface * net_if = NetworkInterface::get_default_instance(); + if (net_if == nullptr) + { + ChipLogError(DeviceLayer, "No network interface available"); + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + if (net_if->wifiInterface() != nullptr) + { + mWifiInterface = net_if->wifiInterface(); + mWiFiStationMode = kWiFiStationMode_Enabled; + + // TODO: Add to user documentation that add_event_listener must be used + // To add more listener to the interface + mWifiInterface->add_event_listener([this](nsapi_event_t event, intptr_t data) { + PlatformMgrImpl().mQueue.call([this, event, data] { + PlatformMgr().LockChipStack(); + OnInterfaceEvent(event, data); + PlatformMgr().UnlockChipStack(); + }); + }); + + mWifiInterface->set_blocking(false); + } + return err; +} + +CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationReconnectIntervalMS(uint32_t val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + if (mWiFiStationReconnectIntervalMS != val) + { + ChipLogProgress(DeviceLayer, "WiFi station reconnect interval MS change: %lu -> %lu", mWiFiStationReconnectIntervalMS, val); + } + + mWiFiStationReconnectIntervalMS = val; + + return err; +} + +void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + // This is for internal use, state change is handled by platform middleware +} + +void ConnectivityManagerImpl::_ProcessInterfaceChange(nsapi_connection_status_t new_status) +{ + switch (new_status) + { + case NSAPI_STATUS_LOCAL_UP: + ChipLogDetail(DeviceLayer, "Connection status - LOCAL_UP"); + OnStationConnected(); + break; + case NSAPI_STATUS_GLOBAL_UP: + ChipLogDetail(DeviceLayer, "Connection status - GLOBAL_UP"); + OnStationConnected(); + break; + case NSAPI_STATUS_DISCONNECTED: + ChipLogDetail(DeviceLayer, "Connection status - DISCONNECTED"); + OnStationDisconnected(); + break; + case NSAPI_STATUS_CONNECTING: + ChipLogDetail(DeviceLayer, "Connection status - CONNECTING"); + OnStationConnecting(); + break; + default: + ChipLogDetail(DeviceLayer, "Unknown connection status: 0x%08X", new_status); + break; + } +} + +void ConnectivityManagerImpl::OnInterfaceEvent(nsapi_event_t event, intptr_t data) +{ + if (event == NSAPI_EVENT_CONNECTION_STATUS_CHANGE) + { + _ProcessInterfaceChange((nsapi_connection_status_t) data); + } +} + +CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, const char * key) +{ + // Validate the interface is available + if (!mWifiInterface) + { + ChipLogError(DeviceLayer, "WiFi interface not supported"); + return CHIP_ERROR_INCORRECT_STATE; + } + + // Set WiFi credentials + auto error = mWifiInterface->set_credentials(ssid, key, mSecurityType); + if (error) + { + ChipLogError(DeviceLayer, "Set WiFi credentials failed %d", error); + return CHIP_ERROR_INTERNAL; + } + + mIsProvisioned = true; + + PlatformMgr().ScheduleWork(OnWifiStationChange, 0); + + return CHIP_NO_ERROR; +} + +void ConnectivityManagerImpl::_ClearWiFiStationProvision(void) +{ + // Validate the interface is available + if (!mWifiInterface) + { + ChipLogError(DeviceLayer, "WiFi interface not supported"); + return; + } + + // Reset credentials + auto error = mWifiInterface->set_credentials("ssid", NULL, NSAPI_SECURITY_NONE); + if (error) + { + ChipLogError(DeviceLayer, "Reset WiFi credentials failed %d", error); + return; + } + + mIsProvisioned = false; + + PlatformMgr().ScheduleWork(OnWifiStationChange, 0); +} + +CHIP_ERROR ConnectivityManagerImpl::OnStationConnected() +{ + // Update WiFi station state and propagate it if necessary + if (mWiFiStationState != kWiFiStationState_Connected) + { + mWiFiStationState = kWiFiStationState_Connected; + ChipDeviceEvent event; + event.Type = DeviceEventType::kWiFiConnectivityChange; + event.WiFiConnectivityChange.Result = kConnectivity_Established; + PlatformMgr().PostEvent(&event); + ChipLogProgress(DeviceLayer, "Event - StationConnected"); + } + + // Update IPv4 address + SocketAddress address; + auto error = mWifiInterface->get_ip_address(&address); + if (error) + { + if (mIp4Address != IPAddress::Any) + { + // Unnexpected change, forward to the application + mIp4Address = IPAddress::Any; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_Lost; + event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; + PlatformMgr().PostEvent(&event); + ChipLogError(DeviceLayer, "Unnexpected loss of Ip4 address"); + } + } + else + { + IPAddress addr; + if (IPAddress::FromString(address.get_ip_address(), addr) && addr != mIp4Address) + { + mIp4Address = addr; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_Established; + event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; + PlatformMgr().PostEvent(&event); + ChipLogProgress(DeviceLayer, "New Ip4 address set: %s", address.get_ip_address()); + } + } + + // Update IPv6 address + error = mWifiInterface->get_ipv6_link_local_address(&address); + if (error) + { + if (mIp6Address != IPAddress::Any) + { + // Unnexpected change, forward to the application + mIp6Address = IPAddress::Any; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; + event.InternetConnectivityChange.IPv6 = kConnectivity_Lost; + PlatformMgr().PostEvent(&event); + ChipLogError(DeviceLayer, "Unnexpected loss of Ip6 address"); + } + } + else + { + IPAddress addr; + if (IPAddress::FromString(address.get_ip_address(), addr) && addr != mIp6Address) + { + mIp6Address = addr; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; + event.InternetConnectivityChange.IPv6 = kConnectivity_Established; + PlatformMgr().PostEvent(&event); + ChipLogProgress(DeviceLayer, "New Ip6 address set %s", address.get_ip_address()); + } + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConnectivityManagerImpl::OnStationDisconnected() +{ + ChipLogDetail(DeviceLayer, "OnStationDisconnected"); + + // Update WiFi station state and propagate it if necessary + if (mWiFiStationState != kWiFiStationState_NotConnected) + { + mWiFiStationState = kWiFiStationState_NotConnected; + ChipDeviceEvent event; + event.Type = DeviceEventType::kWiFiConnectivityChange; + event.WiFiConnectivityChange.Result = kConnectivity_Lost; + PlatformMgr().PostEvent(&event); + ChipLogProgress(DeviceLayer, "Event - StationDisconnected"); + } + + // Update IPv4 address + if (mIp4Address != IPAddress::Any) + { + // Unnexpected change, forward to the application + mIp4Address = IPAddress::Any; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_Lost; + event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; + PlatformMgr().PostEvent(&event); + ChipLogError(DeviceLayer, "Loss of Ip4 address"); + } + + if (mIp6Address != IPAddress::Any) + { + // Unnexpected change, forward to the application + mIp6Address = IPAddress::Any; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; + event.InternetConnectivityChange.IPv6 = kConnectivity_Lost; + PlatformMgr().PostEvent(&event); + ChipLogError(DeviceLayer, "Loss of Ip6 address"); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConnectivityManagerImpl::OnStationConnecting() +{ + ChipLogDetail(DeviceLayer, "OnStationConnecting"); + + // Update WiFi station state and propagate it if necessary + if (mWiFiStationState != kWiFiStationState_Connected) + { + mWiFiStationState = kWiFiStationState_Connecting; + } + return CHIP_NO_ERROR; +} + +void ConnectivityManagerImpl::ExecuteStationChange() +{ + nsapi_error_t error; + if ((mWiFiStationMode == kWiFiStationMode_Enabled) && IsWiFiStationProvisioned() && + mWiFiStationState != kWiFiStationState_Connected) + { + // Connect the interface with network + error = mWifiInterface->connect(); + if (error) + { + ChipLogError(DeviceLayer, "Network connection failed %d", error); + } + } + + if ((mWiFiStationMode == kWiFiStationMode_Enabled) && !IsWiFiStationProvisioned() && + mWiFiStationState == kWiFiStationState_Connected) + { + // Connect the interface with network + error = mWifiInterface->disconnect(); + if (error) + { + ChipLogError(DeviceLayer, "Network disconnect failed %d", error); + } + } +} + +void ConnectivityManagerImpl::OnWifiStationChange(intptr_t arg) +{ + sInstance.ExecuteStationChange(); +} + +const char * ConnectivityManagerImpl::status2str(nsapi_connection_status_t status) +{ + switch (status) + { + case NSAPI_STATUS_LOCAL_UP: + return "Network local UP"; + case NSAPI_STATUS_GLOBAL_UP: + return "Network global UP"; + case NSAPI_STATUS_DISCONNECTED: + return "Network disconnected"; + case NSAPI_STATUS_CONNECTING: + return "Network connecting"; + default: + return "Unknown"; + } +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/ConnectivityManagerImpl.h b/src/platform/mbed/ConnectivityManagerImpl.h new file mode 100644 index 00000000000000..78eb065113e94a --- /dev/null +++ b/src/platform/mbed/ConnectivityManagerImpl.h @@ -0,0 +1,164 @@ +/* + * + * 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 +#include +#include +#include +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include +#else +#include +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#else +#include +#endif +#include +#include +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the ConnectivityManager singleton object for mbed platforms. + */ +class ConnectivityManagerImpl final : public ConnectivityManager, + public Internal::GenericConnectivityManagerImpl, + public Internal::GenericConnectivityManagerImpl_WiFi, + +#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 + +{ + // Allow the ConnectivityManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class ConnectivityManager; + +public: + CHIP_ERROR ProvisionWiFiNetwork(const char * ssid, const char * key); + void StartWiFiManagement() {} + +private: + // ===== Members that implement the ConnectivityManager abstract interface. + bool _HaveIPv4InternetConnectivity(void); + bool _HaveIPv6InternetConnectivity(void); + bool _HaveServiceConnectivity(void); + CHIP_ERROR _Init(void); + void _ProcessInterfaceChange(nsapi_connection_status_t new_status); + void OnInterfaceEvent(nsapi_event_t event, intptr_t data); + WiFiStationMode _GetWiFiStationMode(void); + CHIP_ERROR _SetWiFiStationMode(WiFiStationMode val); + + WiFiAPMode _GetWiFiAPMode(void); + + uint32_t _GetWiFiStationReconnectIntervalMS(void); + CHIP_ERROR _SetWiFiStationReconnectIntervalMS(uint32_t val); + bool _IsWiFiStationConnected(void); + bool _IsWiFiStationEnabled(void); + bool _IsWiFiStationProvisioned(void); + void _ClearWiFiStationProvision(void); + bool _IsWiFiStationApplicationControlled(void); + CHIP_ERROR _SetWiFiAPMode(WiFiAPMode val); + void _OnPlatformEvent(const ChipDeviceEvent * event); + + CHIP_ERROR OnStationConnected(); + CHIP_ERROR OnStationDisconnected(); + CHIP_ERROR OnStationConnecting(); + const char * status2str(nsapi_connection_status_t sec); + ::chip::DeviceLayer::Internal::WiFiAuthSecurityType NsapiToNetworkSecurity(nsapi_security_t nsapi_security); + + void ExecuteStationChange(void); + static void OnWifiStationChange(intptr_t arg); + // ===== Members for internal use by the following friends. + + friend ConnectivityManager & ConnectivityMgr(void); + friend ConnectivityManagerImpl & ConnectivityMgrImpl(void); + + static ConnectivityManagerImpl sInstance; + WiFiStationMode mWiFiStationMode = kWiFiStationMode_NotSupported; + WiFiStationState mWiFiStationState = kWiFiStationState_NotConnected; + WiFiAPMode mWiFiAPMode = kWiFiAPMode_NotSupported; + uint32_t mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL; + uint32_t mWiFiAPIdleTimeoutMS = CHIP_DEVICE_CONFIG_WIFI_AP_IDLE_TIMEOUT; + WiFiInterface * mWifiInterface = nullptr; + nsapi_security_t mSecurityType = NSAPI_SECURITY_WPA_WPA2; + bool mIsProvisioned = false; + Inet::IPAddress mIp4Address = Inet::IPAddress::Any; + Inet::IPAddress mIp6Address = Inet::IPAddress::Any; +}; + +inline ConnectivityManager::WiFiAPMode ConnectivityManagerImpl::_GetWiFiAPMode(void) +{ + return mWiFiAPMode; +} + +inline uint32_t ConnectivityManagerImpl::_GetWiFiStationReconnectIntervalMS(void) +{ + return mWiFiStationReconnectIntervalMS; +} +inline bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity(void) +{ + return mWiFiStationState == kWiFiStationState_Connected && mIp4Address != Inet::IPAddress::Any; +} + +inline bool ConnectivityManagerImpl::_HaveIPv6InternetConnectivity(void) +{ + return mWiFiStationState == kWiFiStationState_Connected && mIp6Address != Inet::IPAddress::Any; +} + +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 mbed platform. + */ +inline ConnectivityManagerImpl & ConnectivityMgrImpl(void) +{ + return ConnectivityManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.cpp b/src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.cpp new file mode 100644 index 00000000000000..1f0f0ae2960ee8 --- /dev/null +++ b/src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.cpp @@ -0,0 +1,41 @@ +/* + * + * 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 "DeviceNetworkProvisioningDelegateImpl.h" + +namespace chip { +namespace DeviceLayer { + +CHIP_ERROR DeviceNetworkProvisioningDelegateImpl::_ProvisionWiFiNetwork(const char * ssid, const char * key) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + ChipLogProgress(NetworkProvisioning, "MbedNetworkProvisioningDelegate: SSID: %s", ssid); + err = ConnectivityMgrImpl().ProvisionWiFiNetwork(ssid, key); + if (err != CHIP_NO_ERROR) + { + ChipLogError(NetworkProvisioning, "Failed to connect to WiFi network: %s", chip::ErrorStr(err)); + } + + return err; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.h b/src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.h new file mode 100644 index 00000000000000..6e89a78e2110b2 --- /dev/null +++ b/src/platform/mbed/DeviceNetworkProvisioningDelegateImpl.h @@ -0,0 +1,43 @@ +/* + * + * 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 +{ +private: + friend class GenericDeviceNetworkProvisioningDelegateImpl; + + CHIP_ERROR _ProvisionWiFiNetwork(const char * ssid, const char * passwd); + CHIP_ERROR _ProvisionThreadNetwork(ByteSpan threadData) { return CHIP_ERROR_NOT_IMPLEMENTED; } +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/InetPlatformConfig.h b/src/platform/mbed/InetPlatformConfig.h new file mode 100644 index 00000000000000..01759cf2e41b46 --- /dev/null +++ b/src/platform/mbed/InetPlatformConfig.h @@ -0,0 +1,50 @@ +/* + * + * 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 Inet + * Layer on mbed platforms. + * + */ + +#pragma once + +#include + +// ==================== Platform Adaptations ==================== + +#define INET_CONFIG_ERROR_TYPE int32_t +#define INET_CONFIG_NO_ERROR 0 +#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 + +#define INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT 0 +#define HAVE_SO_BINDTODEVICE 1 diff --git a/src/platform/mbed/KeyValueStoreManagerImpl.cpp b/src/platform/mbed/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..db93b2d67d39f3 --- /dev/null +++ b/src/platform/mbed/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,112 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for Mbed OS + */ + +#include +#include + +#include "MbedConfig.h" +#include "support/CHIPMem.h" +#include + +using chip::DeviceLayer::Internal::MbedConfig; + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +static const char prefix[] = "/kv/chip-kvs-"; + +class KeyBuilder +{ +public: + KeyBuilder(const char * key) + { + auto ret = snprintf(buffer, sizeof(buffer), "%s%s", prefix, key); + valid = (ret > 0) && ((size_t) ret <= (sizeof(buffer) - 1)); + } + + const char * str() const { return valid ? buffer : nullptr; } + +private: + char buffer[100]; + bool valid; +}; + +// NOTE: Currently this platform does not support partial and offset reads +// these will return CHIP_ERROR_NOT_IMPLEMENTED. +CHIP_ERROR +KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, size_t offset) +{ + if (offset > 0) + { + // Offset and partial reads are not supported. + // Support can be added in the future if this is needed. + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + KeyBuilder key_builder(key); + if (!key_builder.str()) + { + return CHIP_ERROR_PERSISTED_STORAGE_FAILED; + } + + auto err = MbedConfig::ReadConfigValueBin(key_builder.str(), reinterpret_cast(value), value_size, *read_bytes_size); + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) +{ + KeyBuilder key_builder(key); + if (!key_builder.str()) + { + return CHIP_ERROR_PERSISTED_STORAGE_FAILED; + } + + auto err = MbedConfig::ClearConfigValue(key_builder.str()); + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + return err; +} + +CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size) +{ + KeyBuilder key_builder(key); + if (!key_builder.str()) + { + return CHIP_ERROR_PERSISTED_STORAGE_FAILED; + } + + return MbedConfig::WriteConfigValueBin(key_builder.str(), reinterpret_cast(value), value_size); +} + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/KeyValueStoreManagerImpl.h b/src/platform/mbed/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..465db696ae0ede --- /dev/null +++ b/src/platform/mbed/KeyValueStoreManagerImpl.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for Mbed + */ + +#pragma once + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +class KeyValueStoreManagerImpl final : public KeyValueStoreManager +{ + // Allow the KeyValueStoreManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class KeyValueStoreManager; + +public: + // NOTE: Currently this platform does not support partial and offset reads + // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0); + + CHIP_ERROR _Delete(const char * key); + + CHIP_ERROR _Put(const char * key, const void * value, size_t value_size); + +private: + // ===== Members for internal use by the following friends. + friend KeyValueStoreManager & KeyValueStoreMgr(); + friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + + static KeyValueStoreManagerImpl sInstance; +}; + +/** + * Returns the public interface of the KeyValueStoreManager singleton object. + * + * Chip applications should use this to access features of the KeyValueStoreManager object + * that are common to all platforms. + */ +inline KeyValueStoreManager & KeyValueStoreMgr(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the KeyValueStoreManager singleton object. + * + * Chip applications can use this to gain access to features of the KeyValueStoreManager + * that are specific to the Mbed platform. + */ +inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/Logging.cpp b/src/platform/mbed/Logging.cpp new file mode 100644 index 00000000000000..fd693ce53d8079 --- /dev/null +++ b/src/platform/mbed/Logging.cpp @@ -0,0 +1,38 @@ +/* See Project CHIP LICENSE file for licensing information. */ + +#include + +#include + +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() {} + +} // namespace DeviceLayer + +namespace Logging { +namespace Platform { + +/** + * CHIP log output functions. + */ +void LogV(const char * module, uint8_t category, const char * msg, va_list v) +{ + printf("CHIP:%s: ", module); + vprintf(msg, v); + printf("\n"); + + // Let the application know that a log message has been emitted. + DeviceLayer::OnLogOutput(); +} + +} // namespace Platform +} // namespace Logging +} // namespace chip diff --git a/src/platform/mbed/MbedConfig.cpp b/src/platform/mbed/MbedConfig.cpp new file mode 100644 index 00000000000000..bb519cbf79033e --- /dev/null +++ b/src/platform/mbed/MbedConfig.cpp @@ -0,0 +1,332 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019-2020 Google LLC. + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Utilities for interacting with the the ESP32 "NVS" key-value store. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include + +#include +#include +#include +#include +#include + +#include "kvstore_global_api/kvstore_global_api.h" +#include "platform/mbed_error.h" + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +// *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices. + +// Note: An external mbed parameter could be useful so an application can put +// chip NVS values in a single place +#define CHIP_CONFIG_KV_STORE_PARTITION "/kv/" + +// NVS namespaces used to store device configuration information. +#define CHIP_CONFIG_FACTORY_PREFIX "chip-factory-" +#define CHIP_CONFIG_CONFIG_PREFIX "chip-config-" +#define CHIP_CONFIG_COUNTER_PREFIX "chip-counters-" + +#define FACTORY_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_FACTORY_PREFIX key +#define CONFIG_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_CONFIG_PREFIX key + +const char MbedConfig::kConfigNamespace_ChipFactory[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_FACTORY_PREFIX; +const char MbedConfig::kConfigNamespace_ChipConfig[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_CONFIG_PREFIX; +const char MbedConfig::kConfigNamespace_ChipCounters[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX; + +// Keys stored in the chip-factory namespace +const MbedConfig::Key MbedConfig::kConfigKey_SerialNum = { FACTORY_KEY("serial-num") }; +const MbedConfig::Key MbedConfig::kConfigKey_MfrDeviceId = { FACTORY_KEY("device-id") }; +const MbedConfig::Key MbedConfig::kConfigKey_MfrDeviceCert = { FACTORY_KEY("device-cert") }; +const MbedConfig::Key MbedConfig::kConfigKey_MfrDeviceICACerts = { FACTORY_KEY("device-ca-certs") }; +const MbedConfig::Key MbedConfig::kConfigKey_MfrDevicePrivateKey = { FACTORY_KEY("device-key") }; +const MbedConfig::Key MbedConfig::kConfigKey_ProductRevision = { FACTORY_KEY("product-rev") }; +const MbedConfig::Key MbedConfig::kConfigKey_ManufacturingDate = { FACTORY_KEY("mfg-date") }; +const MbedConfig::Key MbedConfig::kConfigKey_SetupPinCode = { FACTORY_KEY("pin-code") }; +const MbedConfig::Key MbedConfig::kConfigKey_SetupDiscriminator = { FACTORY_KEY("discriminator") }; + +// Keys stored in the chip-config namespace +const MbedConfig::Key MbedConfig::kConfigKey_FabricId = { CONFIG_KEY("fabric-id") }; +const MbedConfig::Key MbedConfig::kConfigKey_ServiceConfig = { CONFIG_KEY("service-config") }; +const MbedConfig::Key MbedConfig::kConfigKey_PairedAccountId = { CONFIG_KEY("account-id") }; +const MbedConfig::Key MbedConfig::kConfigKey_ServiceId = { CONFIG_KEY("service-id") }; +const MbedConfig::Key MbedConfig::kConfigKey_GroupKeyIndex = { CONFIG_KEY("group-key-index") }; +const MbedConfig::Key MbedConfig::kConfigKey_LastUsedEpochKeyId = { CONFIG_KEY("last-ek-id") }; +const MbedConfig::Key MbedConfig::kConfigKey_FailSafeArmed = { CONFIG_KEY("fail-safe-armed") }; +const MbedConfig::Key MbedConfig::kConfigKey_WiFiStationSecType = { CONFIG_KEY("sta-sec-type") }; +const MbedConfig::Key MbedConfig::kConfigKey_OperationalDeviceId = { CONFIG_KEY("op-device-id") }; +const MbedConfig::Key MbedConfig::kConfigKey_OperationalDeviceCert = { CONFIG_KEY("op-device-cert") }; +const MbedConfig::Key MbedConfig::kConfigKey_OperationalDeviceICACerts = { CONFIG_KEY("op-device-ca-certs") }; +const MbedConfig::Key MbedConfig::kConfigKey_OperationalDevicePrivateKey = { CONFIG_KEY("op-device-key") }; +const MbedConfig::Key MbedConfig::kConfigKey_RegulatoryLocation = { CONFIG_KEY("regulatory-location") }; +const MbedConfig::Key MbedConfig::kConfigKey_CountryCode = { CONFIG_KEY("country-code") }; +const MbedConfig::Key MbedConfig::kConfigKey_Breadcrumb = { CONFIG_KEY("breadcrumb") }; + +CHIP_ERROR MbedConfig::ReadConfigValue(Key key, bool & val) +{ + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + int err = kv_get(key, reinterpret_cast(&val), sizeof(val), &actual_size); + + if (err != MBED_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR MbedConfig::ReadConfigValue(Key key, uint32_t & val) +{ + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + int err = kv_get(key, reinterpret_cast(&val), sizeof(val), &actual_size); + + if (err != MBED_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR MbedConfig::ReadConfigValue(Key key, uint64_t & val) +{ + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + int err = kv_get(key, &val, sizeof(val), &actual_size); + + if (err != MBED_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR MbedConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) +{ + CHIP_ERROR err = ReadConfigValueBin(key, reinterpret_cast(buf), bufSize, outLen); + // Note: The system expect the trailing null to be added. + if (err != CHIP_NO_ERROR) + { + return err; + } + if (outLen >= bufSize) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + buf[outLen] = 0; + return CHIP_NO_ERROR; +} + +CHIP_ERROR MbedConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +{ + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + int err = kv_get(key, reinterpret_cast(buf), bufSize, &outLen); + + if (err != MBED_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR MbedConfig::WriteConfigValue(Key key, bool val) +{ + int err = kv_set(key, reinterpret_cast(&val), sizeof(val), 0); + return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR MbedConfig::WriteConfigValue(Key key, uint32_t val) +{ + int err = kv_set(key, reinterpret_cast(&val), sizeof(val), 0); + return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR MbedConfig::WriteConfigValue(Key key, uint64_t val) +{ + int err = kv_set(key, reinterpret_cast(&val), sizeof(val), 0); + return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR MbedConfig::WriteConfigValueStr(Key key, const char * str) +{ + return WriteConfigValueBin(key, reinterpret_cast(str), strlen(str)); +} + +CHIP_ERROR MbedConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen) +{ + return WriteConfigValueBin(key, reinterpret_cast(str), strLen); +} + +CHIP_ERROR MbedConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) +{ + // Two different behavior: If the pointer is not null, the value is updated + // or create. If the pointer is null, the key is removed if it exist. + if (data != nullptr) + { + int err = kv_set(key, reinterpret_cast(data), dataLen, 0); + return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; + } + else if (ConfigValueExists(key)) + { + return ClearConfigValue(key); + } + else + { + // Nothing to do, data is null and the key does not exist. + return CHIP_NO_ERROR; + } +} + +CHIP_ERROR MbedConfig::ClearConfigValue(Key key) +{ + int err = kv_remove(key); + return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +bool MbedConfig::ConfigValueExists(Key key) +{ + kv_info_t info; + int err = kv_get_info(key, &info); + return err == MBED_SUCCESS ? true : false; +} + +CHIP_ERROR MbedConfig::FactoryResetConfig() +{ + // kv_reset is not used, we want to preserve other setting and factory + // configuration + auto err = ClearNamespace(kConfigNamespace_ChipConfig); + if (err != CHIP_NO_ERROR) + { + return err; + } + return ClearNamespace(kConfigNamespace_ChipCounters); +} + +CHIP_ERROR MbedConfig::ConstructCounterKey(Key id, char * buf, size_t bufSize) +{ + auto length = snprintf(buf, bufSize - 1, CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX "%s", id); + if (length < 0) + { + return CHIP_ERROR_INTERNAL; + } + else if ((size_t) length > (bufSize - 1)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + else + { + return CHIP_NO_ERROR; + } +} + +CHIP_ERROR MbedConfig::ReadCounter(Key counterId, uint32_t & value) +{ + char key[50] = { 0 }; + auto err = ConstructCounterKey(counterId, key, sizeof(key)); + if (err) + { + return err; + } + + return ReadConfigValue(key, value); +} + +CHIP_ERROR MbedConfig::WriteCounter(Key counterId, uint32_t value) +{ + char key[50] = { 0 }; + auto err = ConstructCounterKey(counterId, key, sizeof(key)); + if (err) + { + return err; + } + + return WriteConfigValue(key, value); +} + +CHIP_ERROR MbedConfig::ClearNamespace(const char * ns) +{ + kv_iterator_t it; + char key[50]; + int err = kv_iterator_open(&it, ns); + if (err) + { + return CHIP_ERROR_INTERNAL; + } + while (kv_iterator_next(it, key, sizeof(key)) != MBED_ERROR_ITEM_NOT_FOUND) + { + kv_remove(key); + memset(key, 0, sizeof(key)); + } + + err = kv_iterator_close(it); + return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +void MbedConfig::RunConfigUnitTest() +{ + // Run common unit test. + ::chip::DeviceLayer::Internal::RunConfigUnitTest(); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/MbedConfig.h b/src/platform/mbed/MbedConfig.h new file mode 100644 index 00000000000000..021b653c903abd --- /dev/null +++ b/src/platform/mbed/MbedConfig.h @@ -0,0 +1,107 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019-2020 Google LLC. + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Utilities for interacting with the the ESP32 "NVS" key-value store. + */ + +#pragma once + +#include +#include + +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +/** + * Provides functions and definitions for accessing device configuration information on the ESP32. + * + * This class is designed to be mixed-in to concrete implementation classes as a means to + * provide access to configuration information to generic base classes. + */ +class MbedConfig +{ +public: + using Key = const char *; + + // NVS prefix used to store device configuration information. + static const char kConfigNamespace_ChipFactory[]; + static const char kConfigNamespace_ChipConfig[]; + static const char kConfigNamespace_ChipCounters[]; + + // Key definitions for well-known keys. + static const Key kConfigKey_SerialNum; + static const Key kConfigKey_MfrDeviceId; + static const Key kConfigKey_MfrDeviceCert; + static const Key kConfigKey_MfrDeviceICACerts; + static const Key kConfigKey_MfrDevicePrivateKey; + static const Key kConfigKey_ProductRevision; + static const Key kConfigKey_ManufacturingDate; + static const Key kConfigKey_SetupPinCode; + static const Key kConfigKey_FabricId; + static const Key kConfigKey_ServiceConfig; + static const Key kConfigKey_PairedAccountId; + static const Key kConfigKey_ServiceId; + static const Key kConfigKey_FabricSecret; + static const Key kConfigKey_GroupKeyIndex; + static const Key kConfigKey_LastUsedEpochKeyId; + static const Key kConfigKey_FailSafeArmed; + static const Key kConfigKey_WiFiStationSecType; + static const Key kConfigKey_OperationalDeviceId; + static const Key kConfigKey_OperationalDeviceCert; + static const Key kConfigKey_OperationalDeviceICACerts; + static const Key kConfigKey_OperationalDevicePrivateKey; + static const Key kConfigKey_SetupDiscriminator; + static const Key kConfigKey_RegulatoryLocation; + static const Key kConfigKey_CountryCode; + static const Key kConfigKey_Breadcrumb; + + // Config value accessors. + 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(); + + // NVS Namespace helper functions. + static CHIP_ERROR ConstructCounterKey(Key id, char * buf, size_t bufSize); + static CHIP_ERROR ReadCounter(Key counterId, uint32_t & value); + static CHIP_ERROR WriteCounter(Key counterId, uint32_t value); + static CHIP_ERROR ClearNamespace(const char * ns); + + static void RunConfigUnitTest(void); +}; + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/MbedEventTimeout.cpp b/src/platform/mbed/MbedEventTimeout.cpp new file mode 100644 index 00000000000000..0e6cc92ccee453 --- /dev/null +++ b/src/platform/mbed/MbedEventTimeout.cpp @@ -0,0 +1,17 @@ +#include "MbedEventTimeout.h" +#include + +namespace chip { +namespace DeviceLayer { + +using namespace mbed; + +static Timeout mTimeout; + +void MbedEventTimeout::AttachTimeout(Callback func, std::chrono::microseconds t) +{ + mTimeout.attach(func, t); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/MbedEventTimeout.h b/src/platform/mbed/MbedEventTimeout.h new file mode 100644 index 00000000000000..945b89caeb5696 --- /dev/null +++ b/src/platform/mbed/MbedEventTimeout.h @@ -0,0 +1,45 @@ +/* mbed Microcontroller Library + * Copyright (c) 2021 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace chip { +namespace DeviceLayer { + +/** + * The special mbed timeout implementation as a separate compilation block. + * It is fix of sleep() function declaration conflict. + * sleep() is declarated in unistd.h (toolchain) and in mbed_power_mgmt.h + * which is included by Timeout.h + */ +class MbedEventTimeout +{ +public: + /** + * Attach a function to be called by the Timeout, specifying the interval in microseconds + * + * @param func pointer to the function to be called + * @param t the time between calls in micro-seconds + * + */ + static void AttachTimeout(mbed::Callback func, std::chrono::microseconds t); +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/PlatformManagerImpl.cpp b/src/platform/mbed/PlatformManagerImpl.cpp new file mode 100644 index 00000000000000..2b0384772d1134 --- /dev/null +++ b/src/platform/mbed/PlatformManagerImpl.cpp @@ -0,0 +1,287 @@ +#include + +#include "platform/internal/CHIPDeviceLayerInternal.h" + +#include +#include +#include +#include +#include +#include + +#include "MbedEventTimeout.h" + +#if CHIP_SYSTEM_CONFIG_USE_LWIP +#include +#endif + +#define DEFAULT_MIN_SLEEP_PERIOD (60 * 60 * 24 * 30) // Month [sec] + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; + +namespace chip { +namespace DeviceLayer { + +// TODO: Event and timer processing is not efficient from a memory perspective. +// Both occupy at least 24 bytes when only 4 bytes is required. +// An optimized designed could use a separate circular buffer to store events +// and register a single mbed event in the event queue to process all of them. +// A similar design can be used for timers. + +CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) +{ + // Members are initialized by the stack + if (!mInitialized) + { + // reinitialize a new thread if it was terminated earlier + mLoopTask.~Thread(); + new (&mLoopTask) rtos::Thread(osPriorityNormal, CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE, + /* memory provided */ nullptr, CHIP_DEVICE_CONFIG_CHIP_TASK_NAME); + + mChipTaskId = 0; + + // Reinitialize the EventQueue + mQueue.~EventQueue(); + new (&mQueue) events::EventQueue(event_size * CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE); + + mQueue.background( + [&](int t) { MbedEventTimeout::AttachTimeout([&] { SystemLayer.WakeIOThread(); }, std::chrono::milliseconds{ t }); }); + + // Reinitialize the Mutexes + mThisStateMutex.~Mutex(); + new (&mThisStateMutex) rtos::Mutex(); + + mChipStackMutex.~Mutex(); + new (&mChipStackMutex) rtos::Mutex(); + + // Reinitialize the condition variable + mEvenLoopStopCond.~ConditionVariable(); + new (&mEvenLoopStopCond) rtos::ConditionVariable(mThisStateMutex); + + mShouldRunEventLoop.store(false); + + mEventLoopHasStopped = false; + } + else + { + ChipLogError(DeviceLayer, "Trying to reinitialize the stack"); + return CHIP_ERROR_INCORRECT_STATE; + } + +#if CHIP_SYSTEM_CONFIG_USE_LWIP + // Initialize LwIP. + tcpip_init(NULL, NULL); +#endif + + // Call up to the base class _InitChipStack() to perform the bulk of the initialization. + auto err = GenericPlatformManagerImpl::_InitChipStack(); + SuccessOrExit(err); + mInitialized = true; + +exit: + return err; +} + +void PlatformManagerImpl::_LockChipStack() +{ + mChipStackMutex.lock(); +} + +bool PlatformManagerImpl::_TryLockChipStack() +{ + return mChipStackMutex.trylock(); +} +void PlatformManagerImpl::_UnlockChipStack() +{ + mChipStackMutex.unlock(); +} + +void PlatformManagerImpl::_PostEvent(const ChipDeviceEvent * eventPtr) +{ + auto handle = mQueue.call([event = *eventPtr, this] { + LockChipStack(); + DispatchEvent(&event); + UnlockChipStack(); + }); + + if (!handle) + { + ChipLogError(DeviceLayer, "Error posting event: Not enough memory"); + } +} + +void PlatformManagerImpl::ProcessDeviceEvents() +{ + mQueue.dispatch(0); +} + +void PlatformManagerImpl::_RunEventLoop() +{ + // Update the internal state first. + // We may run on the current thread instead of the external task + { + mbed::ScopedLock lock(mThisStateMutex); + + // That's a programmign error to run the event loop if it is already running. + // return early + if (mShouldRunEventLoop.load()) + { + ChipLogError(DeviceLayer, "Error trying to run the event loop while it is already running"); + return; + } + mShouldRunEventLoop.store(true); + + // Look if a task ID has already been assigned or not. + // If not, it means we run in the thread that called RunEventLoop + if (!mChipTaskId) + { + ChipLogDetail(DeviceLayer, "Run CHIP event loop on external thread"); + mChipTaskId = rtos::ThisThread::get_id(); + } + + mEventLoopHasStopped = false; + } + + LockChipStack(); + + ChipLogProgress(DeviceLayer, "CHIP Run event loop"); + System::WatchableEventManager & watchState = SystemLayer.WatchableEvents(); + watchState.EventLoopBegins(); + while (true) + { + watchState.PrepareEvents(); + + UnlockChipStack(); + watchState.WaitForEvents(); + LockChipStack(); + + watchState.HandleEvents(); + + ProcessDeviceEvents(); + } + watchState.EventLoopEnds(); + + UnlockChipStack(); + + // Notify threads waiting on the event loop to stop + { + mbed::ScopedLock lock(mThisStateMutex); + mEventLoopHasStopped = true; + mEvenLoopStopCond.notify_all(); + } +} + +CHIP_ERROR PlatformManagerImpl::_StartEventLoopTask() +{ + mbed::ScopedLock lock(mThisStateMutex); + + // This function start the Thread that run the chip event loop. + // If no threads are needed, the application can directly call RunEventLoop. + auto error = mLoopTask.start([this] { + ChipLogDetail(DeviceLayer, "CHIP task running"); + RunEventLoop(); + }); + + if (!error) + { + mChipTaskId = mLoopTask.get_id(); + } + else + { + ChipLogError(DeviceLayer, "Fail to start internal loop task thread"); + } + + return TranslateOsStatus(error); +} + +CHIP_ERROR PlatformManagerImpl::_StopEventLoopTask() +{ + mbed::ScopedLock lock(mThisStateMutex); + + // early return if the event loop is not running + if (!mShouldRunEventLoop.load()) + { + return CHIP_NO_ERROR; + } + + // Indicate that the event loop store + mShouldRunEventLoop.store(false); + + // Wake from select so it unblocks processing + LockChipStack(); + SystemLayer.WakeIOThread(); + UnlockChipStack(); + + osStatus err = osOK; + + // If the thread running the event loop is different from the caller + // then wait it to finish + if (mChipTaskId != rtos::ThisThread::get_id()) + { + // First it waits for the condition variable to finish + mEvenLoopStopCond.wait([this] { return mEventLoopHasStopped == true; }); + + // Then if it was running on the internal task, wait for it to finish + if (mChipTaskId == mLoopTask.get_id()) + { + err = mLoopTask.join(); + mInitialized = false; // the internal thread requires initialization again. + } + } + + mChipTaskId = 0; + return TranslateOsStatus(err); +} + +CHIP_ERROR PlatformManagerImpl::_StartChipTimer(int64_t durationMS) +{ + // Let SystemLayer.PrepareSelect() handle timers. + return CHIP_NO_ERROR; +} + +CHIP_ERROR PlatformManagerImpl::_Shutdown() +{ + // + // Call up to the base class _Shutdown() to perform the actual stack de-initialization + // and clean-up + // + return GenericPlatformManagerImpl::_Shutdown(); +} + +CHIP_ERROR PlatformManagerImpl::TranslateOsStatus(osStatus error) +{ + switch (error) + { + case osErrorNoMemory: + return CHIP_ERROR_NO_MEMORY; + + case osOK: + return CHIP_NO_ERROR; + + default: + return CHIP_ERROR_INTERNAL; + } +} + +bool PlatformManagerImpl::IsLoopActive() +{ + switch (mLoopTask.get_state()) + { + case rtos::Thread::Inactive: + case rtos::Thread::Ready: + case rtos::Thread::Deleted: + return false; + + default: + return true; + } +} + +// ===== Members for internal use by the following friends. + +PlatformManagerImpl PlatformManagerImpl::sInstance; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/PlatformManagerImpl.h b/src/platform/mbed/PlatformManagerImpl.h new file mode 100644 index 00000000000000..ad9cff5c552d3e --- /dev/null +++ b/src/platform/mbed/PlatformManagerImpl.h @@ -0,0 +1,141 @@ +/* + * + * 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 + * Provides an implementation of the PlatformManager object. + */ + +#pragma once + +#include "events/EventQueue.h" +#include "rtos/ConditionVariable.h" +#include "rtos/Mutex.h" +#include "rtos/Thread.h" + +#ifdef TARGET_MCU_STM32L4 +// [ MBED HACK ] +// We have to undefine |SUCCESS| here to prevent compilation error due to +// conflict with |ErrorStatus| enum type values defined in CMSIS/stm32l4xx.h +// which is included by mstd_atormic header. +// This problem is only related for when tests are build and nlunit-test.h is used. +#undef SUCCESS +#endif +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the PlatformManager singleton object for the nRF Connect SDK platforms. + */ +class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl +{ + // 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; +#endif + + // Members for select() loop + int mMaxFd; + fd_set mReadSet; + fd_set mWriteSet; + fd_set mErrorSet; + timeval mNextTimeout; + +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); + void _LockChipStack(); + bool _TryLockChipStack(); + void _UnlockChipStack(); + void _PostEvent(const ChipDeviceEvent * event); + void _RunEventLoop(); + CHIP_ERROR _StartEventLoopTask(); + CHIP_ERROR _StopEventLoopTask(); + CHIP_ERROR _StartChipTimer(int64_t durationMS); + CHIP_ERROR _Shutdown(); + + void ProcessDeviceEvents(); + + // ===== Members for internal use by the following friends. + + friend PlatformManager & PlatformMgr(void); + friend PlatformManagerImpl & PlatformMgrImpl(void); + friend class Internal::BLEManagerImpl; + friend class ConnectivityManagerImpl; + friend class Internal::GapEventHandler; + friend class Internal::CHIPService; + + using PlatformManager::PostEvent; + static PlatformManagerImpl sInstance; + + // ===== Members for internal use. + static CHIP_ERROR TranslateOsStatus(osStatus status); + bool IsLoopActive(); + + bool mInitialized = false; + rtos::Thread mLoopTask{ osPriorityNormal, CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE, + /* memory provided */ nullptr, CHIP_DEVICE_CONFIG_CHIP_TASK_NAME }; + osThreadId_t mChipTaskId = 0; + rtos::Mutex mThisStateMutex; + rtos::ConditionVariable mEvenLoopStopCond{ mThisStateMutex }; + rtos::Mutex mChipStackMutex; + static const size_t event_size = EVENTS_EVENT_SIZE + sizeof(void *) + sizeof(ChipDeviceEvent *); + events::EventQueue mQueue = { event_size * CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE }; + mstd::atomic mShouldRunEventLoop; + bool mEventLoopHasStopped = false; +}; + +/** + * 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 Mbed platform. + */ +inline PlatformManagerImpl & PlatformMgrImpl() +{ + return PlatformManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/mbed/SystemPlatformConfig.h b/src/platform/mbed/SystemPlatformConfig.h new file mode 100644 index 00000000000000..2d273fe4da0d0d --- /dev/null +++ b/src/platform/mbed/SystemPlatformConfig.h @@ -0,0 +1,59 @@ +/* + * + * 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 mbed Platforms. + * + */ + +#pragma once + +#include + +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_MBED_LOCKING 1 +#define CHIP_SYSTEM_CONFIG_NO_LOCKING 0 +#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 int32_t +#define CHIP_SYSTEM_CONFIG_NO_ERROR 0 +#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/mbed/SystemTimeSupport.cpp b/src/platform/mbed/SystemTimeSupport.cpp new file mode 100644 index 00000000000000..3669a88875da10 --- /dev/null +++ b/src/platform/mbed/SystemTimeSupport.cpp @@ -0,0 +1,129 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Provides implementations of the CHIP System Layer platform + * time/clock functions that are suitable for use on the Mbed-OS platform. + */ +/* this file behaves like a config.h, comes first */ +#include +#include + +#include +#include + +#include "platform/mbed_rtc_time.h" +#include + +namespace chip { +namespace System { +namespace Platform { +namespace Layer { + +// Platform-specific function for getting monotonic system time in microseconds. +// Returns elapsed time in microseconds since an arbitrary, platform-defined epoch. +uint64_t GetClock_Monotonic() +{ + return rtos::Kernel::get_ms_count() * UINT64_C(1000); +} + +// Platform-specific function for getting monotonic system time in milliseconds. +// Return elapsed time in milliseconds since an arbitrary, platform-defined epoch. +uint64_t GetClock_MonotonicMS() +{ + return rtos::Kernel::get_ms_count(); +} + +// Platform-specific function for getting high-resolution monotonic system time in microseconds. +// Returns elapsed time in microseconds since an arbitrary, platform-defined epoch. +uint64_t GetClock_MonotonicHiRes() +{ + return GetClock_Monotonic(); +} + +// Platform-specific function for getting the current real (civil) time in microsecond Unix time format, +// where |curTime| argument is the current time, expressed as Unix time scaled to microseconds. +// Returns CHIP_SYSTEM_NO_ERROR if the method succeeded. +Error GetClock_RealTime(uint64_t & curTime) +{ + struct timeval tv; + int res = gettimeofday(&tv, NULL); + if (res != 0) + { + return CHIP_SYSTEM_ERROR_UNEXPECTED_STATE; + } + if (tv.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD) + { + return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED; + } + curTime = (tv.tv_sec * UINT64_C(1000000)) + tv.tv_usec; + return CHIP_SYSTEM_NO_ERROR; +} + +// Platform-specific function for getting the current real (civil) time in millisecond Unix time +// where |curTimeMS| is the current time, expressed as Unix time scaled to milliseconds. +// Returns CHIP_SYSTEM_NO_ERROR if the method succeeded. +Error GetClock_RealTimeMS(uint64_t & curTimeMS) +{ + struct timeval tv; + int res = gettimeofday(&tv, NULL); + if (res != 0) + { + return CHIP_SYSTEM_ERROR_UNEXPECTED_STATE; + } + if (tv.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD) + { + return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED; + } + curTimeMS = (tv.tv_sec * UINT64_C(1000)) + (tv.tv_usec / 1000); + return CHIP_SYSTEM_NO_ERROR; +} + +// Platform-specific function for setting the current real (civil) time +// where |newCurTime| is the new current time, expressed as Unix time scaled to microseconds. +// Returns CHIP_SYSTEM_NO_ERROR if the method succeeded. +Error SetClock_RealTime(uint64_t newCurTime) +{ + struct timeval tv; + tv.tv_sec = static_cast(newCurTime / UINT64_C(1000000)); + tv.tv_usec = static_cast(newCurTime % UINT64_C(1000000)); + int res = settimeofday(&tv, NULL); + if (res != 0) + { + return CHIP_SYSTEM_ERROR_UNEXPECTED_STATE; + } +#if CHIP_PROGRESS_LOGGING + { + uint16_t year; + uint8_t month, dayOfMonth, hour, minute, second; + SecondsSinceEpochToCalendarTime((uint32_t) tv.tv_sec, year, month, dayOfMonth, hour, minute, second); + ChipLogProgress(DeviceLayer, + "Real time clock set to %" PRId64 " (%04" PRIu16 "/%02" PRIu8 "/%02" PRIu8 " %02" PRIu8 ":%02" PRIu8 + ":%02" PRIu8 " UTC)", + tv.tv_sec, year, month, dayOfMonth, hour, minute, second); + } +#endif // CHIP_PROGRESS_LOGGING + return CHIP_SYSTEM_NO_ERROR; +} + +} // namespace Layer +} // namespace Platform +} // namespace System +} // namespace chip diff --git a/src/platform/mbed/arch.c b/src/platform/mbed/arch.c new file mode 100644 index 00000000000000..d7798c53224bdf --- /dev/null +++ b/src/platform/mbed/arch.c @@ -0,0 +1,76 @@ +#include "platform/mbed_atomic.h" +#include "platform/mbed_thread.h" +#include "platform/mbed_toolchain.h" +#include "platform/mbed_wait_api.h" + +// TODO: Remove! +// This file is a temporary workaround until atomic integration has been solved + +static mbed_memory_order mem_order(int order) +{ + switch (order) + { + case __ATOMIC_RELAXED: + return mbed_memory_order_relaxed; + case __ATOMIC_CONSUME: + return mbed_memory_order_consume; + case __ATOMIC_ACQUIRE: + return mbed_memory_order_acquire; + case __ATOMIC_RELEASE: + return mbed_memory_order_release; + case __ATOMIC_ACQ_REL: + return mbed_memory_order_acq_rel; + case __ATOMIC_SEQ_CST: + return mbed_memory_order_seq_cst; + default: + // Should not happen! return sequential consistency in such case + MBED_ASSERT(false); + return mbed_memory_order_seq_cst; + } +} + +void __sync_synchronize() +{ + MBED_BARRIER(); +} + +unsigned int __atomic_fetch_add_4(volatile void * ptr, unsigned int val, int memorder) +{ + return core_util_atomic_fetch_add_explicit_u32((volatile uint32_t *) ptr, val, mem_order(memorder)); +} + +uint64_t __atomic_load_8(const volatile void * ptr, int memorder) +{ + return core_util_atomic_load_explicit_u64((const volatile uint64_t *) ptr, mem_order(memorder)); +} + +uint64_t __atomic_exchange_8(volatile void * ptr, uint64_t val, int memorder) +{ + return core_util_atomic_exchange_explicit_u64((volatile uint64_t *) ptr, val, mem_order(memorder)); +} + +// Note: Weak version not supported in library, the weak parameter is simply dropped. +// see https://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary +#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch" +bool __atomic_compare_exchange_8(volatile void * ptr, void * expected, unsigned long long desired, int success_memorder, + int failure_memorder) +{ + return core_util_atomic_cas_explicit_u64((volatile uint64_t *) ptr, (uint64_t *) expected, desired, mem_order(success_memorder), + mem_order(failure_memorder)); +} + +void usleep(unsigned int usec) +{ + unsigned int ms = (usec / 1000); + unsigned int us = usec % 1000; + + if (ms) + { + thread_sleep_for(ms); + } + + if (us) + { + wait_us((int) us); + } +} diff --git a/src/system/BUILD.gn b/src/system/BUILD.gn index b1c73915e28028..3695867d85c400 100644 --- a/src/system/BUILD.gn +++ b/src/system/BUILD.gn @@ -47,6 +47,7 @@ buildconfig_header("system_buildconfig") { config_device_layer = chip_device_platform != "none" chip_system_config_posix_locking = chip_system_config_locking == "posix" chip_system_config_freertos_locking = chip_system_config_locking == "freertos" + chip_system_config_mbed_locking = chip_system_config_locking == "mbed" chip_system_config_no_locking = chip_system_config_locking == "none" have_clock_gettime = chip_system_config_clock == "clock_gettime" have_clock_settime = have_clock_gettime @@ -62,6 +63,7 @@ buildconfig_header("system_buildconfig") { "CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK=false", "CHIP_SYSTEM_CONFIG_POSIX_LOCKING=${chip_system_config_posix_locking}", "CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING=${chip_system_config_freertos_locking}", + "CHIP_SYSTEM_CONFIG_MBED_LOCKING=${chip_system_config_mbed_locking}", "CHIP_SYSTEM_CONFIG_NO_LOCKING=${chip_system_config_no_locking}", "CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS=${chip_system_config_provide_statistics}", "HAVE_CLOCK_GETTIME=${have_clock_gettime}", diff --git a/src/system/SystemConfig.h b/src/system/SystemConfig.h index 16347e5f6d3a35..d6038dcfa72ac6 100644 --- a/src/system/SystemConfig.h +++ b/src/system/SystemConfig.h @@ -143,6 +143,10 @@ #define CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING INET_CONFIG_FREERTOS_LOCKING #endif // !defined(CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING) && defined(INET_CONFIG_FREERTOS_LOCKING) +#if !defined(CHIP_SYSTEM_CONFIG_MBED_LOCKING) && defined(INET_CONFIG_MBED_LOCKING) +#define CHIP_SYSTEM_CONFIG_MBED_LOCKING INET_CONFIG_MBED_LOCKING +#endif // !defined(CHIP_SYSTEM_CONFIG_MBED_LOCKING) && defined(INET_CONFIG_MBED_LOCKING) + #if !defined(CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE) && defined(INET_CONFIG_NUM_BUFS) #define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE INET_CONFIG_NUM_BUFS #endif // !defined(CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE) && defined(INET_CONFIG_NUM_BUFS) @@ -159,6 +163,13 @@ #endif /* CHIP_SYSTEM_CONFIG_ERROR_TYPE */ #if CHIP_SYSTEM_CONFIG_USE_LWIP +#ifdef TARGET_MCU_STM32L4 +// [ MBED HACK ] +// We have to undefine |SUCCESS| here to prevent compilation error due to +// conflict with |ErrorStatus| enum type values defined in CMSIS/stm32l4xx.h. +// This problem is only related for when tests are build and nlunit-test.h is used. +#undef SUCCESS +#endif #include #endif // CHIP_SYSTEM_CONFIG_USE_LWIP @@ -202,30 +213,53 @@ #define CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING 0 #endif /* CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING */ +/** + * @def CHIP_SYSTEM_CONFIG_MBED_LOCKING + * + * @brief + * Use Mbed OS locking. + * + * This should be generally asserted (1) for Mbed OS. + * + * However, if you are simulating an LwIP-based system atop POSIX threads and BSD sockets, this should also be deasserted (0). + */ +#ifndef CHIP_SYSTEM_CONFIG_MBED_LOCKING +#define CHIP_SYSTEM_CONFIG_MBED_LOCKING 0 +#endif /* CHIP_SYSTEM_CONFIG_MBED_LOCKING */ + + /** * @def CHIP_SYSTEM_CONFIG_NO_LOCKING * * @brief * Disable the use of locking within the system layer. * - * This value is mutually exclusive with CHIP_SYSTEM_CONFIG_POSIX_LOCKING and CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING. + * This value is mutually exclusive with CHIP_SYSTEM_CONFIG_POSIX_LOCKING and CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING and CHIP_SYSTEM_CONFIG_MBED_LOCKING. */ #ifndef CHIP_SYSTEM_CONFIG_NO_LOCKING #define CHIP_SYSTEM_CONFIG_NO_LOCKING 0 #endif /* CHIP_SYSTEM_CONFIG_NO_LOCKING */ -#if !(CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_NO_LOCKING) -#error "REQUIRED: CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_NO_LOCKING" -#endif // !(CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_NO_LOCKING) +#if !(CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_MBED_LOCKING || CHIP_SYSTEM_CONFIG_NO_LOCKING) +#error "REQUIRED: CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_MBED_LOCKING || CHIP_SYSTEM_CONFIG_NO_LOCKING" +#endif // !(CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_MBED_LOCKING || CHIP_SYSTEM_CONFIG_NO_LOCKING) -#if CHIP_SYSTEM_CONFIG_NO_LOCKING && (CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING) -#error "FORBIDDEN: CHIP_SYSTEM_CONFIG_NO_LOCKING && (CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING)" -#endif // CHIP_SYSTEM_CONFIG_NO_LOCKING && (CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING) +#if CHIP_SYSTEM_CONFIG_NO_LOCKING && (CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_MBED_LOCKING) +#error "FORBIDDEN: CHIP_SYSTEM_CONFIG_NO_LOCKING && (CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_MBED_LOCKING)" +#endif // CHIP_SYSTEM_CONFIG_NO_LOCKING && (CHIP_SYSTEM_CONFIG_POSIX_LOCKING || CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING || CHIP_SYSTEM_CONFIG_MBED_LOCKING) #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING #error "FORBIDDEN: CHIP_SYSTEM_CONFIG_POSIX_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING" #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING +#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING && CHIP_SYSTEM_CONFIG_MBED_LOCKING +#error "FORBIDDEN: CHIP_SYSTEM_CONFIG_POSIX_LOCKING && CHIP_SYSTEM_CONFIG_MBED_LOCKING" +#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && CHIP_SYSTEM_CONFIG_MBED_LOCKING + +#if CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING && CHIP_SYSTEM_CONFIG_MBED_LOCKING +#error "FORBIDDEN: CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING && CHIP_SYSTEM_CONFIG_MBED_LOCKING" +#endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING && CHIP_SYSTEM_CONFIG_MBED_LOCKING + #ifndef CHIP_SYSTEM_CONFIG_ERROR_TYPE /** @@ -627,7 +661,7 @@ struct LwIPEvent; * Defaults to enabled if the system is using sockets (except for Zephyr RTOS). */ #ifndef CHIP_SYSTEM_CONFIG_USE_POSIX_PIPE -#if (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) && !__ZEPHYR__ +#if (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) && !__ZEPHYR__ && !__MBED__ #define CHIP_SYSTEM_CONFIG_USE_POSIX_PIPE 1 #else #define CHIP_SYSTEM_CONFIG_USE_POSIX_PIPE 0 diff --git a/src/system/SystemMutex.h b/src/system/SystemMutex.h index 2c65971ab7d191..4eaeb1e1870fbd 100644 --- a/src/system/SystemMutex.h +++ b/src/system/SystemMutex.h @@ -50,6 +50,10 @@ #endif #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING +#if CHIP_SYSTEM_CONFIG_MBED_LOCKING +#include +#endif // CHIP_SYSTEM_CONFIG_MBED_LOCKING + namespace chip { namespace System { @@ -88,6 +92,10 @@ class DLL_EXPORT Mutex volatile int mInitialized = 0; #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING +#if CHIP_SYSTEM_CONFIG_MBED_LOCKING + rtos::Mutex mMbedMutex; +#endif // CHIP_SYSTEM_CONFIG_MBED_LOCKING + Mutex(const Mutex &) = delete; Mutex & operator=(const Mutex &) = delete; }; @@ -115,6 +123,25 @@ inline void Mutex::Unlock(void) } #endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING +#if CHIP_SYSTEM_CONFIG_MBED_LOCKING +inline Error Mutex::Init(Mutex & aMutex) +{ + // The mutex is initialized when constructed and generates + // a runtime error in case of failure. + return CHIP_SYSTEM_NO_ERROR; +} + +inline void Mutex::Lock() +{ + return mMbedMutex.lock(); +} + +inline void Mutex::Unlock(void) +{ + return mMbedMutex.unlock(); +} +#endif // CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING + } // namespace System } // namespace chip diff --git a/src/system/WatchableSocketSelect.cpp b/src/system/WatchableSocketSelect.cpp index 7276281996a5cc..0b28fd8c3d12d3 100644 --- a/src/system/WatchableSocketSelect.cpp +++ b/src/system/WatchableSocketSelect.cpp @@ -162,7 +162,7 @@ void WatchableEventManager::PrepareEventsWithTimeout(struct timeval & nextTimeou // TODO(#5556): Integrate timer platform details with WatchableEventManager. mSystemLayer->GetTimeout(nextTimeout); -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ && !__MBED__ chip::Mdns::GetMdnsTimeout(nextTimeout); #endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ @@ -200,7 +200,7 @@ void WatchableEventManager::HandleEvents() } } -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ && !__MBED__ chip::Mdns::HandleMdnsTimeout(); #endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ } diff --git a/src/system/system.gni b/src/system/system.gni index 00c2f2f50e3d3e..0775d1f94e8423 100644 --- a/src/system/system.gni +++ b/src/system/system.gni @@ -45,6 +45,8 @@ declare_args() { if (chip_system_config_locking == "") { if (current_os == "freertos") { chip_system_config_locking = "freertos" + } else if (current_os == "mbed") { + chip_system_config_locking = "mbed" } else if (chip_system_config_use_dispatch == false) { chip_system_config_locking = "posix" } else { @@ -52,10 +54,12 @@ if (chip_system_config_locking == "") { } } -assert(chip_system_config_locking == "posix" || - chip_system_config_locking == "freertos" || - chip_system_config_locking == "none", - "Please select a valid mutex implementation: posix, freertos, none") +assert( + chip_system_config_locking == "posix" || + chip_system_config_locking == "freertos" || + chip_system_config_locking == "none" || + chip_system_config_locking == "mbed", + "Please select a valid mutex implementation: posix, freertos, mbed, none") assert( chip_system_config_clock == "clock_gettime" || diff --git a/third_party/mbed-os-posix-socket/repo b/third_party/mbed-os-posix-socket/repo new file mode 160000 index 00000000000000..6f0a16a2ab82b3 --- /dev/null +++ b/third_party/mbed-os-posix-socket/repo @@ -0,0 +1 @@ +Subproject commit 6f0a16a2ab82b3f751b3e63c90129d306a755e21 diff --git a/third_party/mbed-os/repo b/third_party/mbed-os/repo new file mode 160000 index 00000000000000..5067e8f368c49d --- /dev/null +++ b/third_party/mbed-os/repo @@ -0,0 +1 @@ +Subproject commit 5067e8f368c49df544f9c7547d286be9eae9b788 diff --git a/third_party/wifi-ism43362/repo b/third_party/wifi-ism43362/repo new file mode 160000 index 00000000000000..a75d553bdc6232 --- /dev/null +++ b/third_party/wifi-ism43362/repo @@ -0,0 +1 @@ +Subproject commit a75d553bdc62322ec98634a29c2b697681dff8ec