From 2186354636a8b813d3ee42b29d305fb4cc805e43 Mon Sep 17 00:00:00 2001 From: weicheng Date: Tue, 13 Jun 2023 11:38:01 +0800 Subject: [PATCH] [ASR] add more examples (#26622) --- .github/workflows/examples-asr.yaml | 9 +- docs/guides/asr_getting_started_guide.md | 23 +- examples/all-clusters-app/asr/.gn | 29 + examples/all-clusters-app/asr/BUILD.gn | 135 +++++ examples/all-clusters-app/asr/README.md | 62 +++ examples/all-clusters-app/asr/args.gni | 27 + examples/all-clusters-app/asr/build_overrides | 1 + examples/all-clusters-app/asr/cfg.gni | 23 + .../all-clusters-app/asr/include/AppConfig.h | 60 +++ .../all-clusters-app/asr/include/AppEvent.h | 51 ++ .../all-clusters-app/asr/include/AppTask.h | 64 +++ .../asr/include/ButtonHandler.h | 53 ++ .../asr/include/CHIPProjectConfig.h | 92 ++++ .../asr/include/DeviceCallbacks.h | 47 ++ examples/all-clusters-app/asr/src/AppTask.cpp | 274 ++++++++++ .../asr/src/ButtonHandler.cpp | 117 ++++ .../asr/src/DeviceCallbacks.cpp | 276 ++++++++++ examples/all-clusters-app/asr/src/main.cpp | 86 +++ .../asr/third_party/connectedhomeip | 1 + examples/all-clusters-minimal-app/asr/.gn | 29 + .../all-clusters-minimal-app/asr/BUILD.gn | 134 +++++ .../all-clusters-minimal-app/asr/README.md | 54 ++ .../all-clusters-minimal-app/asr/args.gni | 27 + .../asr/build_overrides | 1 + examples/all-clusters-minimal-app/asr/cfg.gni | 23 + .../asr/include/AppConfig.h | 54 ++ .../asr/include/AppEvent.h | 51 ++ .../asr/include/AppTask.h | 65 +++ .../asr/include/CHIPProjectConfig.h | 92 ++++ .../asr/include/DeviceCallbacks.h | 44 ++ .../asr/src/AppTask.cpp | 230 ++++++++ .../asr/src/DeviceCallbacks.cpp | 180 +++++++ .../all-clusters-minimal-app/asr/src/main.cpp | 85 +++ .../asr/third_party/connectedhomeip | 1 + examples/bridge-app/asr/.gn | 29 + examples/bridge-app/asr/BUILD.gn | 134 +++++ examples/bridge-app/asr/README.md | 67 +++ examples/bridge-app/asr/args.gni | 27 + examples/bridge-app/asr/build_overrides | 1 + examples/bridge-app/asr/cfg.gni | 23 + examples/bridge-app/asr/include/AppConfig.h | 42 ++ examples/bridge-app/asr/include/AppTask.h | 44 ++ .../asr/include/CHIPProjectConfig.h | 118 ++++ .../bridge-app/asr/include/DeviceCallbacks.h | 42 ++ examples/bridge-app/asr/src/AppTask.cpp | 102 ++++ .../bridge-app/asr/src/DeviceCallbacks.cpp | 133 +++++ .../asr/src/bridged-actions-stub.cpp | 100 ++++ examples/bridge-app/asr/src/main.cpp | 76 +++ .../bridge-app/asr/subdevice/SubDevice.cpp | 154 ++++++ examples/bridge-app/asr/subdevice/SubDevice.h | 70 +++ .../asr/subdevice/SubDeviceManager.cpp | 269 +++++++++ .../asr/subdevice/SubDeviceManager.h | 77 +++ .../asr/subdevice/subdevice_test.cpp | 159 ++++++ .../asr/third_party/connectedhomeip | 1 + examples/light-switch-app/asr/.gn | 29 + examples/light-switch-app/asr/BUILD.gn | 136 +++++ examples/light-switch-app/asr/README.md | 52 ++ examples/light-switch-app/asr/args.gni | 27 + examples/light-switch-app/asr/build_overrides | 1 + examples/light-switch-app/asr/cfg.gni | 23 + .../light-switch-app/asr/include/AppConfig.h | 74 +++ .../light-switch-app/asr/include/AppEvent.h | 64 +++ .../light-switch-app/asr/include/AppTask.h | 88 +++ .../asr/include/BindingHandler.h | 62 +++ .../asr/include/ButtonHandler.h | 38 ++ .../asr/include/CHIPProjectConfig.h | 111 ++++ .../asr/include/DeviceCallbacks.h | 42 ++ .../light-switch-app/asr/include/LEDManager.h | 48 ++ .../asr/include/LightSwitch.h | 53 ++ examples/light-switch-app/asr/src/AppTask.cpp | 509 ++++++++++++++++++ .../asr/src/BindingHandler.cpp | 316 +++++++++++ .../asr/src/ButtonHandler.cpp | 122 +++++ .../asr/src/DeviceCallbacks.cpp | 147 +++++ .../light-switch-app/asr/src/LEDManager.cpp | 96 ++++ .../light-switch-app/asr/src/LightSwitch.cpp | 113 ++++ examples/light-switch-app/asr/src/main.cpp | 77 +++ .../asr/third_party/connectedhomeip | 1 + examples/lock-app/asr/.gn | 29 + examples/lock-app/asr/BUILD.gn | 131 +++++ examples/lock-app/asr/README.md | 56 ++ examples/lock-app/asr/args.gni | 27 + examples/lock-app/asr/build_overrides | 1 + examples/lock-app/asr/cfg.gni | 23 + examples/lock-app/asr/include/AppConfig.h | 83 +++ examples/lock-app/asr/include/AppEvent.h | 57 ++ examples/lock-app/asr/include/AppTask.h | 95 ++++ .../lock-app/asr/include/BoltLockManager.h | 84 +++ examples/lock-app/asr/include/ButtonHandler.h | 51 ++ .../lock-app/asr/include/CHIPProjectConfig.h | 112 ++++ .../lock-app/asr/include/DeviceCallbacks.h | 42 ++ examples/lock-app/asr/include/LEDManager.h | 47 ++ examples/lock-app/asr/src/AppTask.cpp | 497 +++++++++++++++++ examples/lock-app/asr/src/BoltLockManager.cpp | 225 ++++++++ examples/lock-app/asr/src/ButtonHandler.cpp | 100 ++++ examples/lock-app/asr/src/DeviceCallbacks.cpp | 162 ++++++ examples/lock-app/asr/src/LEDManager.cpp | 96 ++++ examples/lock-app/asr/src/main.cpp | 84 +++ .../lock-app/asr/third_party/connectedhomeip | 1 + examples/ota-requestor-app/asr/.gn | 29 + examples/ota-requestor-app/asr/BUILD.gn | 129 +++++ examples/ota-requestor-app/asr/README.md | 61 +++ examples/ota-requestor-app/asr/args.gni | 27 + .../ota-requestor-app/asr/build_overrides | 1 + examples/ota-requestor-app/asr/cfg.gni | 25 + .../ota-requestor-app/asr/include/AppConfig.h | 43 ++ .../ota-requestor-app/asr/include/AppTask.h | 44 ++ .../asr/include/CHIPProjectConfig.h | 109 ++++ .../asr/include/DeviceCallbacks.h | 42 ++ .../ota-requestor-app/asr/src/AppTask.cpp | 103 ++++ .../asr/src/DeviceCallbacks.cpp | 148 +++++ examples/ota-requestor-app/asr/src/main.cpp | 78 +++ .../asr/third_party/connectedhomeip | 1 + examples/temperature-measurement-app/asr/.gn | 29 + .../temperature-measurement-app/asr/BUILD.gn | 129 +++++ .../temperature-measurement-app/asr/README.md | 40 ++ .../temperature-measurement-app/asr/args.gni | 27 + .../asr/build_overrides | 1 + .../temperature-measurement-app/asr/cfg.gni | 23 + .../asr/include/AppConfig.h | 79 +++ .../asr/include/AppEvent.h | 57 ++ .../asr/include/AppTask.h | 65 +++ .../asr/include/CHIPProjectConfig.h | 109 ++++ .../asr/include/DeviceCallbacks.h | 42 ++ .../asr/src/AppTask.cpp | 104 ++++ .../asr/src/DeviceCallbacks.cpp | 143 +++++ .../asr/src/main.cpp | 84 +++ .../asr/third_party/connectedhomeip | 1 + examples/thermostat/asr/.gn | 29 + examples/thermostat/asr/BUILD.gn | 132 +++++ examples/thermostat/asr/README.md | 52 ++ examples/thermostat/asr/args.gni | 27 + examples/thermostat/asr/build_overrides | 1 + examples/thermostat/asr/cfg.gni | 23 + examples/thermostat/asr/include/AppConfig.h | 81 +++ examples/thermostat/asr/include/AppEvent.h | 71 +++ examples/thermostat/asr/include/AppTask.h | 73 +++ .../thermostat/asr/include/BindingHandler.h | 54 ++ .../thermostat/asr/include/CHIPClusters.h | 80 +++ .../asr/include/CHIPProjectConfig.h | 109 ++++ .../thermostat/asr/include/DeviceCallbacks.h | 42 ++ .../thermostat/asr/include/SensorManager.h | 46 ++ .../asr/include/TemperatureManager.h | 65 +++ examples/thermostat/asr/src/AppTask.cpp | 176 ++++++ .../thermostat/asr/src/DeviceCallbacks.cpp | 130 +++++ examples/thermostat/asr/src/SensorManager.cpp | 88 +++ .../thermostat/asr/src/TemperatureManager.cpp | 135 +++++ examples/thermostat/asr/src/main.cpp | 79 +++ .../asr/third_party/connectedhomeip | 1 + scripts/build/build/targets.py | 8 + scripts/build/builders/asr.py | 44 +- .../build/testdata/all_targets_linux_x64.txt | 2 +- 151 files changed, 11712 insertions(+), 9 deletions(-) create mode 100755 examples/all-clusters-app/asr/.gn create mode 100755 examples/all-clusters-app/asr/BUILD.gn create mode 100755 examples/all-clusters-app/asr/README.md create mode 100755 examples/all-clusters-app/asr/args.gni create mode 120000 examples/all-clusters-app/asr/build_overrides create mode 100755 examples/all-clusters-app/asr/cfg.gni create mode 100644 examples/all-clusters-app/asr/include/AppConfig.h create mode 100755 examples/all-clusters-app/asr/include/AppEvent.h create mode 100644 examples/all-clusters-app/asr/include/AppTask.h create mode 100644 examples/all-clusters-app/asr/include/ButtonHandler.h create mode 100755 examples/all-clusters-app/asr/include/CHIPProjectConfig.h create mode 100644 examples/all-clusters-app/asr/include/DeviceCallbacks.h create mode 100644 examples/all-clusters-app/asr/src/AppTask.cpp create mode 100644 examples/all-clusters-app/asr/src/ButtonHandler.cpp create mode 100644 examples/all-clusters-app/asr/src/DeviceCallbacks.cpp create mode 100644 examples/all-clusters-app/asr/src/main.cpp create mode 120000 examples/all-clusters-app/asr/third_party/connectedhomeip create mode 100755 examples/all-clusters-minimal-app/asr/.gn create mode 100755 examples/all-clusters-minimal-app/asr/BUILD.gn create mode 100755 examples/all-clusters-minimal-app/asr/README.md create mode 100755 examples/all-clusters-minimal-app/asr/args.gni create mode 120000 examples/all-clusters-minimal-app/asr/build_overrides create mode 100755 examples/all-clusters-minimal-app/asr/cfg.gni create mode 100644 examples/all-clusters-minimal-app/asr/include/AppConfig.h create mode 100755 examples/all-clusters-minimal-app/asr/include/AppEvent.h create mode 100755 examples/all-clusters-minimal-app/asr/include/AppTask.h create mode 100755 examples/all-clusters-minimal-app/asr/include/CHIPProjectConfig.h create mode 100755 examples/all-clusters-minimal-app/asr/include/DeviceCallbacks.h create mode 100644 examples/all-clusters-minimal-app/asr/src/AppTask.cpp create mode 100644 examples/all-clusters-minimal-app/asr/src/DeviceCallbacks.cpp create mode 100644 examples/all-clusters-minimal-app/asr/src/main.cpp create mode 120000 examples/all-clusters-minimal-app/asr/third_party/connectedhomeip create mode 100755 examples/bridge-app/asr/.gn create mode 100755 examples/bridge-app/asr/BUILD.gn create mode 100755 examples/bridge-app/asr/README.md create mode 100755 examples/bridge-app/asr/args.gni create mode 120000 examples/bridge-app/asr/build_overrides create mode 100755 examples/bridge-app/asr/cfg.gni create mode 100644 examples/bridge-app/asr/include/AppConfig.h create mode 100644 examples/bridge-app/asr/include/AppTask.h create mode 100755 examples/bridge-app/asr/include/CHIPProjectConfig.h create mode 100644 examples/bridge-app/asr/include/DeviceCallbacks.h create mode 100644 examples/bridge-app/asr/src/AppTask.cpp create mode 100644 examples/bridge-app/asr/src/DeviceCallbacks.cpp create mode 100755 examples/bridge-app/asr/src/bridged-actions-stub.cpp create mode 100644 examples/bridge-app/asr/src/main.cpp create mode 100644 examples/bridge-app/asr/subdevice/SubDevice.cpp create mode 100755 examples/bridge-app/asr/subdevice/SubDevice.h create mode 100644 examples/bridge-app/asr/subdevice/SubDeviceManager.cpp create mode 100644 examples/bridge-app/asr/subdevice/SubDeviceManager.h create mode 100644 examples/bridge-app/asr/subdevice/subdevice_test.cpp create mode 120000 examples/bridge-app/asr/third_party/connectedhomeip create mode 100755 examples/light-switch-app/asr/.gn create mode 100755 examples/light-switch-app/asr/BUILD.gn create mode 100755 examples/light-switch-app/asr/README.md create mode 100755 examples/light-switch-app/asr/args.gni create mode 120000 examples/light-switch-app/asr/build_overrides create mode 100755 examples/light-switch-app/asr/cfg.gni create mode 100644 examples/light-switch-app/asr/include/AppConfig.h create mode 100755 examples/light-switch-app/asr/include/AppEvent.h create mode 100755 examples/light-switch-app/asr/include/AppTask.h create mode 100755 examples/light-switch-app/asr/include/BindingHandler.h create mode 100644 examples/light-switch-app/asr/include/ButtonHandler.h create mode 100755 examples/light-switch-app/asr/include/CHIPProjectConfig.h create mode 100755 examples/light-switch-app/asr/include/DeviceCallbacks.h create mode 100644 examples/light-switch-app/asr/include/LEDManager.h create mode 100644 examples/light-switch-app/asr/include/LightSwitch.h create mode 100644 examples/light-switch-app/asr/src/AppTask.cpp create mode 100644 examples/light-switch-app/asr/src/BindingHandler.cpp create mode 100644 examples/light-switch-app/asr/src/ButtonHandler.cpp create mode 100644 examples/light-switch-app/asr/src/DeviceCallbacks.cpp create mode 100644 examples/light-switch-app/asr/src/LEDManager.cpp create mode 100644 examples/light-switch-app/asr/src/LightSwitch.cpp create mode 100644 examples/light-switch-app/asr/src/main.cpp create mode 120000 examples/light-switch-app/asr/third_party/connectedhomeip create mode 100755 examples/lock-app/asr/.gn create mode 100755 examples/lock-app/asr/BUILD.gn create mode 100755 examples/lock-app/asr/README.md create mode 100755 examples/lock-app/asr/args.gni create mode 120000 examples/lock-app/asr/build_overrides create mode 100755 examples/lock-app/asr/cfg.gni create mode 100644 examples/lock-app/asr/include/AppConfig.h create mode 100755 examples/lock-app/asr/include/AppEvent.h create mode 100755 examples/lock-app/asr/include/AppTask.h create mode 100755 examples/lock-app/asr/include/BoltLockManager.h create mode 100755 examples/lock-app/asr/include/ButtonHandler.h create mode 100755 examples/lock-app/asr/include/CHIPProjectConfig.h create mode 100755 examples/lock-app/asr/include/DeviceCallbacks.h create mode 100644 examples/lock-app/asr/include/LEDManager.h create mode 100644 examples/lock-app/asr/src/AppTask.cpp create mode 100755 examples/lock-app/asr/src/BoltLockManager.cpp create mode 100644 examples/lock-app/asr/src/ButtonHandler.cpp create mode 100644 examples/lock-app/asr/src/DeviceCallbacks.cpp create mode 100644 examples/lock-app/asr/src/LEDManager.cpp create mode 100755 examples/lock-app/asr/src/main.cpp create mode 120000 examples/lock-app/asr/third_party/connectedhomeip create mode 100755 examples/ota-requestor-app/asr/.gn create mode 100755 examples/ota-requestor-app/asr/BUILD.gn create mode 100755 examples/ota-requestor-app/asr/README.md create mode 100755 examples/ota-requestor-app/asr/args.gni create mode 120000 examples/ota-requestor-app/asr/build_overrides create mode 100755 examples/ota-requestor-app/asr/cfg.gni create mode 100644 examples/ota-requestor-app/asr/include/AppConfig.h create mode 100644 examples/ota-requestor-app/asr/include/AppTask.h create mode 100755 examples/ota-requestor-app/asr/include/CHIPProjectConfig.h create mode 100644 examples/ota-requestor-app/asr/include/DeviceCallbacks.h create mode 100644 examples/ota-requestor-app/asr/src/AppTask.cpp create mode 100644 examples/ota-requestor-app/asr/src/DeviceCallbacks.cpp create mode 100644 examples/ota-requestor-app/asr/src/main.cpp create mode 120000 examples/ota-requestor-app/asr/third_party/connectedhomeip create mode 100755 examples/temperature-measurement-app/asr/.gn create mode 100755 examples/temperature-measurement-app/asr/BUILD.gn create mode 100755 examples/temperature-measurement-app/asr/README.md create mode 100755 examples/temperature-measurement-app/asr/args.gni create mode 120000 examples/temperature-measurement-app/asr/build_overrides create mode 100755 examples/temperature-measurement-app/asr/cfg.gni create mode 100644 examples/temperature-measurement-app/asr/include/AppConfig.h create mode 100755 examples/temperature-measurement-app/asr/include/AppEvent.h create mode 100755 examples/temperature-measurement-app/asr/include/AppTask.h create mode 100755 examples/temperature-measurement-app/asr/include/CHIPProjectConfig.h create mode 100644 examples/temperature-measurement-app/asr/include/DeviceCallbacks.h create mode 100644 examples/temperature-measurement-app/asr/src/AppTask.cpp create mode 100644 examples/temperature-measurement-app/asr/src/DeviceCallbacks.cpp create mode 100755 examples/temperature-measurement-app/asr/src/main.cpp create mode 120000 examples/temperature-measurement-app/asr/third_party/connectedhomeip create mode 100755 examples/thermostat/asr/.gn create mode 100755 examples/thermostat/asr/BUILD.gn create mode 100755 examples/thermostat/asr/README.md create mode 100755 examples/thermostat/asr/args.gni create mode 120000 examples/thermostat/asr/build_overrides create mode 100755 examples/thermostat/asr/cfg.gni create mode 100644 examples/thermostat/asr/include/AppConfig.h create mode 100755 examples/thermostat/asr/include/AppEvent.h create mode 100644 examples/thermostat/asr/include/AppTask.h create mode 100644 examples/thermostat/asr/include/BindingHandler.h create mode 100644 examples/thermostat/asr/include/CHIPClusters.h create mode 100755 examples/thermostat/asr/include/CHIPProjectConfig.h create mode 100644 examples/thermostat/asr/include/DeviceCallbacks.h create mode 100644 examples/thermostat/asr/include/SensorManager.h create mode 100755 examples/thermostat/asr/include/TemperatureManager.h create mode 100644 examples/thermostat/asr/src/AppTask.cpp create mode 100644 examples/thermostat/asr/src/DeviceCallbacks.cpp create mode 100644 examples/thermostat/asr/src/SensorManager.cpp create mode 100644 examples/thermostat/asr/src/TemperatureManager.cpp create mode 100644 examples/thermostat/asr/src/main.cpp create mode 120000 examples/thermostat/asr/third_party/connectedhomeip diff --git a/.github/workflows/examples-asr.yaml b/.github/workflows/examples-asr.yaml index 7a5722cf2918c7..a8fd72fc3bfe28 100644 --- a/.github/workflows/examples-asr.yaml +++ b/.github/workflows/examples-asr.yaml @@ -64,7 +64,14 @@ jobs: run: | ./scripts/run_in_build_env.sh \ "./scripts/build/build_examples.py \ + --target asr-asr582x-all-clusters \ + --target asr-asr582x-all-clusters-minimal \ --target asr-asr582x-lighting \ - --target asr-asr582x-lighting-ota \ + --target asr-asr582x-light-switch \ + --target asr-asr582x-lock \ + --target asr-asr582x-ota-requestor \ + --target asr-asr582x-bridge \ + --target asr-asr582x-temperature-measurement \ + --target asr-asr582x-thermostat \ build \ " \ No newline at end of file diff --git a/docs/guides/asr_getting_started_guide.md b/docs/guides/asr_getting_started_guide.md index fa86dfda279328..6d6b15230faf4d 100644 --- a/docs/guides/asr_getting_started_guide.md +++ b/docs/guides/asr_getting_started_guide.md @@ -14,6 +14,7 @@ platform that uses ASR FreeRTOS SDK. - [IP mode](#ip-mode) - [Shell](#shell) - [OTA](#ota) + - [Factory](#factory) --- @@ -72,7 +73,8 @@ to speed up development. You can find them in the samples with `/asr` subfolder. `--target` when build the examples. - After building the application, `DOGO` tool is used to flash it to the - board. + board, please refer to the + [DOGO Tool User Guide](https://asriot.readthedocs.io/en/latest/ASR550X/Download-Tool/ASR_IoT_DOGO_Tool_User_Guide.html). ## Commissioning @@ -128,7 +130,18 @@ There are two commissioning modes supported by ASR platform: ## OTA -To build the example with the Matter OTA Requestor functionality, exactly the -same steps as above but add argument `-ota` when using the `build_examples.py` -script. For example: -`./scripts/build/build_examples.py --target asr-$ASR_BOARD-lighting-ota build` +1. To build the example with the Matter OTA Requestor functionality, exactly the + same steps as above but add argument `-ota` when using the + `build_examples.py` script. For example: + `./scripts/build/build_examples.py --target asr-$ASR_BOARD-lighting-ota build` +2. For more usage details, please refer to the + [OTA example](../../examples/ota-requestor-app/asr/README.md) + +## Factory + +1. To build the example with the ASR Factory Data Provider, exactly the same + steps as above but add argument `-factory` when using the `build_examples.py` + script. For example: + `./scripts/build/build_examples.py --target asr-$ASR_BOARD-lighting-factory build` +2. For more usage details, please refer to the + [Factory Tool User Guide](https://github.com/asriot/Tools/blob/main/factory_tool/README.md) diff --git a/examples/all-clusters-app/asr/.gn b/examples/all-clusters-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/all-clusters-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/all-clusters-app/asr/BUILD.gn b/examples/all-clusters-app/asr/BUILD.gn new file mode 100755 index 00000000000000..d639d658589519 --- /dev/null +++ b/examples/all-clusters-app/asr/BUILD.gn @@ -0,0 +1,135 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/all-clusters-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("all_clusters_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("clusters_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-clusters-example.out" + + sources = [ + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/ButtonHandler.cpp", + "src/DeviceCallbacks.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + deps = [ + ":all_clusters_app_sdk_sources", + "${chip_root}/examples/all-clusters-app/all-clusters-common", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/examples/all-clusters-app/all-clusters-common/include", + "${chip_root}/src", + "${chip_root}/src/lib", + "${chip_root}/src/lib/support", + "${chip_root}/src/app/util", + ] + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + output_dir = root_out_dir +} + +group("asr") { + deps = [ ":clusters_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/all-clusters-app/asr/README.md b/examples/all-clusters-app/asr/README.md new file mode 100755 index 00000000000000..287da141fc0e24 --- /dev/null +++ b/examples/all-clusters-app/asr/README.md @@ -0,0 +1,62 @@ +# Matter ASR All Clusters Example + +A prototype application that demonstrates device commissioning and cluster +control on ASR platform. + +--- + +- [Matter ASR All Clusters Example](#matter-asr-all-clusters-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Cluster Control](#cluster-control) + - [Light switch press button and light status LED](#light-switch-press-button-and-light-status-led) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-all-clusters build +``` + +## Cluster Control + +After successful commissioning, use `chip-tool` to control the board + +For example, read sensor measured value: + +``` +./chip-tool temperaturemeasurement read measured-value 1 +./chip-tool relativehumiditymeasurement read measured-value 1 +./chip-tool pressuremeasurement read measured-value 1 +``` + +Or,control the OnOff Cluster attribute: + +``` +./chip-tool onoff read on-off 1 +./chip-tool onoff on 1 +./chip-tool onoff off 1 +./chip-tool onoff toggle 1 +``` + +## Light switch press button and light status LED + +This demo uses button to test changing the light states and LED to show the +state of these changes. + +| Name | Pin | +| :----: | :---: | +| LED | PAD6 | +| BUTTON | PAD12 | diff --git a/examples/all-clusters-app/asr/args.gni b/examples/all-clusters-app/asr/args.gni new file mode 100755 index 00000000000000..66a2de849083d4 --- /dev/null +++ b/examples/all-clusters-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":all_clusters_app_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/all-clusters-app/asr/build_overrides b/examples/all-clusters-app/asr/build_overrides new file mode 120000 index 00000000000000..194ee0b812dc3d --- /dev/null +++ b/examples/all-clusters-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides/ \ No newline at end of file diff --git a/examples/all-clusters-app/asr/cfg.gni b/examples/all-clusters-app/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/all-clusters-app/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/all-clusters-app/asr/include/AppConfig.h b/examples/all-clusters-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..40abc79020f59e --- /dev/null +++ b/examples/all-clusters-app/asr/include/AppConfig.h @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2021 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. + */ + +#pragma once + +// ---- Lighting Example App Config ---- + +#define APP_TASK_NAME "APP" + +#define APP_EVENT_QUEUE_SIZE 10 +#define APP_TASK_STACK_SIZE (1024 * 4) +#define APP_WAIT_LOOP 1000 + +#define MATTER_DEVICE_NAME "ASR-Clusters" + +#define GPIO_TASK_NAME "gpio" +#define GPIO_TASK_STACK_SIZE 1024 + +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 + +#define SWITCH1_BUTTON GPIO12_INDEX +#define SWITCH2_BUTTON GPIO13_INDEX + +#define LIGHT1_LED PWM_OUTPUT_CH4 +#define LIGHT2_LED PWM_OUTPUT_CH6 + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/all-clusters-app/asr/include/AppEvent.h b/examples/all-clusters-app/asr/include/AppEvent.h new file mode 100755 index 00000000000000..2c59845f3bb577 --- /dev/null +++ b/examples/all-clusters-app/asr/include/AppEvent.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + enum AppEventTypes + { + kEventType_Button = 0, + kEventType_Timer, + kEventType_Light, + kEventType_Install, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t ButtonIdx; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/all-clusters-app/asr/include/AppTask.h b/examples/all-clusters-app/asr/include/AppTask.h new file mode 100644 index 00000000000000..184e309af5eeba --- /dev/null +++ b/examples/all-clusters-app/asr/include/AppTask.h @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include "AppEvent.h" +#include +#include +#include +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + static void AppEventHandler(AppEvent * aEvent); + void PostButtonEvent(uint8_t btnIdx, uint8_t btnAction); + void PostEvent(const AppEvent * event); + /** + * Use internally for registration of the ChipDeviceEvents + */ + static void CommonDeviceEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static AppTask sAppTask; + static void AppTimerCallback(void * params); + void DispatchEvent(AppEvent * event); + static void OnOffUpdateClusterState(void); +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/all-clusters-app/asr/include/ButtonHandler.h b/examples/all-clusters-app/asr/include/ButtonHandler.h new file mode 100644 index 00000000000000..621459d464c322 --- /dev/null +++ b/examples/all-clusters-app/asr/include/ButtonHandler.h @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppEvent.h" +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#else +#include "duet_gpio.h" +#endif + +class ButtonHandler +{ +public: + static void Init(void); + + struct KeyInformation + { + uint8_t keyDown; + uint8_t keyImPulse; + uint8_t keyReleasePulse; + }; + + static KeyInformation keyInfo; + + static ButtonHandler & GetInstance() + { + static ButtonHandler sButtonHandler; + return sButtonHandler; + } + +private: + static void GpioInit(void); +}; diff --git a/examples/all-clusters-app/asr/include/CHIPProjectConfig.h b/examples/all-clusters-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..6a81ee6517aedb --- /dev/null +++ b/examples/all-clusters-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 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 + * 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 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 +#define CHIP_CONFIG_REQUIRE_AUTH 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a version of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/all-clusters-app/asr/include/DeviceCallbacks.h b/examples/all-clusters-app/asr/include/DeviceCallbacks.h new file mode 100644 index 00000000000000..d30939cd28b424 --- /dev/null +++ b/examples/all-clusters-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg) override; + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); + void OnOnOffPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); + void OnLevelPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint16_t size, + uint8_t * value); + void OnColorPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); + void OnIdentifyPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); +}; diff --git a/examples/all-clusters-app/asr/src/AppTask.cpp b/examples/all-clusters-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..d55ef713dde3f2 --- /dev/null +++ b/examples/all-clusters-app/asr/src/AppTask.cpp @@ -0,0 +1,274 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * Copyright 2021, Cypress Semiconductor Corporation (an Infineon company) + * 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 "AppConfig.h" +#include "AppEvent.h" +#include "ButtonHandler.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDWidget.h" +#include "init_Matter.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +LEDWidget sStatusLED; +LEDWidget sLightLED; + +namespace { +lega_thread_t sAppTaskHandle; +lega_queue_t sAppEventQueue; +lega_timer_t sAppTimer; + +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +AppTask AppTask::sAppTask; + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + OSStatus status; + + status = lega_rtos_init_queue(&sAppEventQueue, "EventQueue", sizeof(AppEvent), APP_EVENT_QUEUE_SIZE); + + VerifyOrExit(status == kNoErr, err = CHIP_ERROR_NO_MEMORY); + + status = lega_rtos_init_timer(&sAppTimer, 3000, (timer_handler_t) AppTimerCallback, (void *) this); + + VerifyOrExit(status == kNoErr, err = CHIP_ERROR_NO_MEMORY); + + status = lega_rtos_create_thread(&sAppTaskHandle, 2, APP_TASK_NAME, (lega_thread_function_t) AppTaskMain, APP_TASK_STACK_SIZE, + (lega_thread_arg_t) this); + + VerifyOrExit(status == kNoErr, err = APP_ERROR_CREATE_TASK_FAILED); + +exit: + return err; +} + +CHIP_ERROR AppTask::Init() +{ + ASR_LOG("App Task started"); + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + return CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + CHIP_ERROR err = sAppTask.Init(); + + ButtonHandler::Init(); + + sLightLED.Init(LIGHT1_LED); // embedded board light + sStatusLED.Init(LIGHT2_LED); + + lega_rtos_start_timer(&sAppTimer); + + if (err != CHIP_NO_ERROR) + { + ASR_LOG("AppTask.Init() failed"); + appError(err); + } + + while (true) + { + /* Check the event queue. */ + if (lega_rtos_is_queue_empty(&sAppEventQueue)) + { + lega_rtos_delay_milliseconds(1); + continue; + } + + /* Pop one event from the event queue. */ + lega_rtos_pop_from_queue(&sAppEventQueue, &event, LEGA_WAIT_FOREVER); + + sAppTask.DispatchEvent(&event); + } +} + +void AppTask::AppEventHandler(AppEvent * aEvent) +{ + static char lightState; + int16_t temperature = 2550; + int16_t humidity = 5000; + int16_t pressure = 1234; + + switch (aEvent->Type) + { + case AppEvent::kEventType_Timer: { + chip::app::Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Set( + /* endpoint ID */ 1, /* temperature in 0.01*C */ int16_t(temperature)); + + chip::app::Clusters::RelativeHumidityMeasurement::Attributes::MeasuredValue::Set( + /* endpoint ID */ 1, /* humidity in 0.01% */ int16_t(humidity)); + + chip::app::Clusters::PressureMeasurement::Attributes::MeasuredValue::Set( + /* endpoint ID */ 1, /* pressure in 0.01 */ int16_t(pressure)); + + break; + } + + case AppEvent::kEventType_Button: { + lightState = !lightState; + /* ON/OFF Light Led based on Button interrupt */ + if (lightState) + { + sLightLED.Set(1); + sLightLED.SetBrightness(100); + } + else + { + sLightLED.Set(0); + } + + /* Update OnOff Cluster state */ + sAppTask.OnOffUpdateClusterState(); + break; + } + + default: + break; + } +} + +void AppTask::AppTimerCallback(void * params) +{ + AppEvent timer_event = {}; + timer_event.Type = AppEvent::kEventType_Timer; + timer_event.TimerEvent.Context = nullptr; + + timer_event.Handler = AppEventHandler; + sAppTask.PostEvent(&timer_event); +} + +void AppTask::PostButtonEvent(uint8_t btnIdx, uint8_t btnAction) +{ + ASR_LOG("%s %s\n", btnIdx == SWITCH1_BUTTON ? "btn1" : "btn2", btnAction == APP_BUTTON_PRESSED ? "Pressed" : "Released"); + + if (btnIdx != SWITCH1_BUTTON && btnIdx != SWITCH2_BUTTON) + { + return; + } + + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.ButtonIdx = btnIdx; + button_event.ButtonEvent.Action = btnAction; + + if (btnAction == APP_BUTTON_RELEASED) + { + button_event.Handler = AppEventHandler; + sAppTask.PostEvent(&button_event); + } +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + OSStatus status = lega_rtos_push_to_queue(&sAppEventQueue, const_cast(aEvent), LEGA_NO_WAIT); + if (kNoErr != status) + { + ASR_LOG("Post event failed."); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + ASR_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::OnOffUpdateClusterState(void) +{ + uint8_t onoff = sLightLED.Get(); + + // write the new on/off value + EmberAfStatus status = app::Clusters::OnOff::Attributes::OnOff::Set(1, onoff); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ASR_LOG("ERR: updating on/off %x", status); + } +} + +bool lowPowerClusterSleep() +{ + return true; +} diff --git a/examples/all-clusters-app/asr/src/ButtonHandler.cpp b/examples/all-clusters-app/asr/src/ButtonHandler.cpp new file mode 100644 index 00000000000000..1faa7f7f56fbe1 --- /dev/null +++ b/examples/all-clusters-app/asr/src/ButtonHandler.cpp @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ButtonHandler.h" +#include "AppConfig.h" +#include "AppTask.h" +#include + +#ifdef CFG_PLF_RV32 +#define duet_gpio_dev_t asr_gpio_dev_t +#define duet_gpio_init asr_gpio_init +#define duet_gpio_input_get asr_gpio_input_get +#define DUET_INPUT_PULL_UP ASR_INPUT_PULL_UP +#endif + +TaskHandle_t sGpioTaskHandle; +ButtonHandler::KeyInformation ButtonHandler::keyInfo = { 0 }; + +static void GpioTaskMain(void * pvParameter); + +void ButtonHandler::Init(void) +{ + GpioInit(); + + xTaskCreate(GpioTaskMain, GPIO_TASK_NAME, GPIO_TASK_STACK_SIZE, 0, 2, &sGpioTaskHandle); +} + +// port pin +duet_gpio_dev_t switch1_btn; +duet_gpio_dev_t switch2_btn; + +void ButtonHandler::GpioInit(void) +{ + // light switch1 button + switch1_btn.port = SWITCH1_BUTTON; + switch1_btn.config = DUET_INPUT_PULL_UP; + switch1_btn.priv = NULL; + duet_gpio_init(&switch1_btn); + + switch2_btn.port = SWITCH2_BUTTON; + switch2_btn.config = DUET_INPUT_PULL_UP; + switch2_btn.priv = NULL; + duet_gpio_init(&switch2_btn); +} + +void GpioTaskMain(void * pvParameter) +{ + ASR_LOG("GPIO Task started"); + uint32_t btnValue; + uint8_t currentKeys = 0; + + for (;;) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + + duet_gpio_input_get(&switch1_btn, &btnValue); + + if (!btnValue) + { + currentKeys |= 0x01; + } + else + { + currentKeys &= ~0x01; + } + + duet_gpio_input_get(&switch2_btn, &btnValue); + + if (!btnValue) + { + currentKeys |= 0x02; + } + else + { + currentKeys &= ~0x02; + } + + ButtonHandler::keyInfo.keyImPulse = (ButtonHandler::keyInfo.keyDown ^ currentKeys) & ~ButtonHandler::keyInfo.keyDown; + ButtonHandler::keyInfo.keyReleasePulse = (ButtonHandler::keyInfo.keyDown ^ currentKeys) & ButtonHandler::keyInfo.keyDown; + ButtonHandler::keyInfo.keyDown = currentKeys; + + if (ButtonHandler::keyInfo.keyImPulse & 0x01) + { + GetAppTask().PostButtonEvent(SWITCH1_BUTTON, APP_BUTTON_PRESSED); + } + + if (ButtonHandler::keyInfo.keyImPulse & 0x02) + { + GetAppTask().PostButtonEvent(SWITCH2_BUTTON, APP_BUTTON_PRESSED); + } + + if (ButtonHandler::keyInfo.keyReleasePulse & 0x01) + { + GetAppTask().PostButtonEvent(SWITCH1_BUTTON, APP_BUTTON_RELEASED); + } + + if (ButtonHandler::keyInfo.keyReleasePulse & 0x02) + { + GetAppTask().PostButtonEvent(SWITCH2_BUTTON, APP_BUTTON_RELEASED); + } + } +} diff --git a/examples/all-clusters-app/asr/src/DeviceCallbacks.cpp b/examples/all-clusters-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..7b284250787382 --- /dev/null +++ b/examples/all-clusters-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,276 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" + +#include "CHIPDeviceManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LEDWidget.h" +#include "init_OTARequestor.h" +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +static const char * TAG = "app-devicecallbacks"; + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; + +extern LEDWidget sLightLED; +extern LEDWidget sStatusLED; + +uint32_t identifyTimerCount; +constexpr uint32_t kIdentifyTimerDelayMS = 250; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + switch (clusterId) + { + case app::Clusters::OnOff::Id: + OnOnOffPostAttributeChangeCallback(endpointId, attributeId, value); + break; + + case app::Clusters::Identify::Id: + OnIdentifyPostAttributeChangeCallback(endpointId, attributeId, value); + break; + + default: + break; + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} + +void DeviceCallbacks::OnOnOffPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == chip::app::Clusters::OnOff::Attributes::OnOff::Id, + ChipLogError(DeviceLayer, TAG, "Unhandled Attribute ID: '0x%04x", attributeId)); + VerifyOrExit(endpointId == 1 || endpointId == 2, + ChipLogError(DeviceLayer, TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId)); + + switch (attributeId) + { + case chip::app::Clusters::OnOff::Attributes::OnOff::Id: { + ChipLogProgress(Zcl, "ON/OFF level: %u ", *value); + // At this point we can assume that value points to a bool value. + sLightLED.Set(*value); + } + break; + + case chip::app::Clusters::OnOff::Attributes::OnTime::Id: + case chip::app::Clusters::OnOff::Attributes::OffWaitTime::Id: + case chip::app::Clusters::OnOff::Attributes::StartUpOnOff::Id: + case chip::app::Clusters::OnOff::Attributes::GlobalSceneControl::Id: { + ChipLogProgress(Zcl, "Unprocessed attribute ID: %" PRIx32, attributeId); + } + break; + + default: + ChipLogProgress(Zcl, "Unknown attribute ID: %" PRIx32, attributeId); + return; + } // switch (attributeId) +exit: + return; +} + +void DeviceCallbacks::OnLevelPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint16_t size, + uint8_t * value) +{ + switch (attributeId) + { + case chip::app::Clusters::LevelControl::Attributes::CurrentLevel::Id: { + if (size == 1) + { + uint8_t tmp = *value; + ChipLogProgress(Zcl, "New level: %u ", tmp); + sLightLED.SetBrightness(tmp); + } + else + { + ChipLogError(Zcl, "wrong length for level: %d\n", size); + } + } + break; + + case chip::app::Clusters::LevelControl::Attributes::MinLevel::Id: + case chip::app::Clusters::LevelControl::Attributes::MaxLevel::Id: + case chip::app::Clusters::LevelControl::Attributes::CurrentFrequency::Id: + case chip::app::Clusters::LevelControl::Attributes::MinFrequency::Id: + case chip::app::Clusters::LevelControl::Attributes::MaxFrequency::Id: + case chip::app::Clusters::LevelControl::Attributes::Options::Id: + case chip::app::Clusters::LevelControl::Attributes::OnOffTransitionTime::Id: + case chip::app::Clusters::LevelControl::Attributes::OnLevel::Id: + case chip::app::Clusters::LevelControl::Attributes::OnTransitionTime::Id: + case chip::app::Clusters::LevelControl::Attributes::OffTransitionTime::Id: + case chip::app::Clusters::LevelControl::Attributes::DefaultMoveRate::Id: + case chip::app::Clusters::LevelControl::Attributes::StartUpCurrentLevel::Id: { + ChipLogProgress(Zcl, "Unprocessed attribute ID: %" PRIx32, attributeId); + } + break; + + default: + ChipLogProgress(Zcl, "Unknown attribute ID: %" PRIx32, attributeId); + return; + + } // switch (attributeId) +} + +void DeviceCallbacks::OnColorPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + using namespace app::Clusters::ColorControl::Attributes; + + uint8_t hue, saturation; + + if ((attributeId != CurrentHue::Id) && (attributeId != CurrentSaturation::Id)) + { + ChipLogProgress(Zcl, "Unknown attribute ID: %" PRIx32, attributeId); + return; + } + + if (attributeId == CurrentHue::Id) + { + hue = *value; + CurrentSaturation::Get(endpointId, &saturation); + } + if (attributeId == CurrentSaturation::Id) + { + saturation = *value; + CurrentHue::Get(endpointId, &hue); + } + + ChipLogProgress(Zcl, "New hue: %d, New saturation: %d ", hue, saturation); +} + +void IdentifyTimerHandler(Layer * systemLayer, void * appState) +{ + if (identifyTimerCount) + { + systemLayer->StartTimer(Clock::Milliseconds32(kIdentifyTimerDelayMS), IdentifyTimerHandler, appState); + identifyTimerCount--; + } +} + +void DeviceCallbacks::OnIdentifyPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == chip::app::Clusters::Identify::Attributes::IdentifyTime::Id, + ChipLogError(DeviceLayer, "[%s] Unhandled Attribute ID: '0x%04lx", TAG, attributeId)); + VerifyOrExit(endpointId == 1, ChipLogError(DeviceLayer, "[%s] Unexpected EndPoint ID: `0x%02x'", TAG, endpointId)); + + // timerCount represents the number of callback executions before we stop the timer. + // value is expressed in seconds and the timer is fired every 250ms, so just multiply value by 4. + // Also, we want timerCount to be odd number, so the ligth state ends in the same state it starts. + identifyTimerCount = (*value) * 4; + + DeviceLayer::SystemLayer().CancelTimer(IdentifyTimerHandler, this); + DeviceLayer::SystemLayer().StartTimer(Clock::Milliseconds32(kIdentifyTimerDelayMS), IdentifyTimerHandler, this); +exit: + return; +} diff --git a/examples/all-clusters-app/asr/src/main.cpp b/examples/all-clusters-app/asr/src/main.cpp new file mode 100644 index 00000000000000..98048869353676 --- /dev/null +++ b/examples/all-clusters-app/asr/src/main.cpp @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * Copyright 2021, Cypress Semiconductor Corporation (an Infineon company) + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include +#include +#include +#include + +#include + +#include "AppConfig.h" +#include "init_asrPlatform.h" +#include + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/all-clusters-app/asr/third_party/connectedhomeip b/examples/all-clusters-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/all-clusters-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/all-clusters-minimal-app/asr/.gn b/examples/all-clusters-minimal-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/all-clusters-minimal-app/asr/BUILD.gn b/examples/all-clusters-minimal-app/asr/BUILD.gn new file mode 100755 index 00000000000000..752062a9b96ebf --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/BUILD.gn @@ -0,0 +1,134 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/all-clusters-minimal-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("all_clusters_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("clusters_minimal_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-clusters-minimal-example.out" + + sources = [ + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/DeviceCallbacks.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + deps = [ + ":all_clusters_app_sdk_sources", + "${chip_root}/examples/all-clusters-minimal-app/all-clusters-common", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/examples/all-clusters-app/all-clusters-common/include", + "${chip_root}/src", + "${chip_root}/src/lib", + "${chip_root}/src/lib/support", + "${chip_root}/src/app/util", + ] + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + output_dir = root_out_dir +} + +group("asr") { + deps = [ ":clusters_minimal_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/all-clusters-minimal-app/asr/README.md b/examples/all-clusters-minimal-app/asr/README.md new file mode 100755 index 00000000000000..8926066fccece9 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/README.md @@ -0,0 +1,54 @@ +# Matter ASR All Clusters Example + +A prototype application that demonstrates device commissioning and cluster +control on ASR platform. + +--- + +- [Matter ASR All Clusters Example](#matter-asr-all-clusters-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Cluster Control](#cluster-control) + - [Light switch press button and light status LED](#light-switch-press-button-and-light-status-led) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-all-clusters-minimal build +``` + +## Cluster Control + +After successful commissioning, use `chip-tool` to control the board + +For example,control the OnOff Cluster attribute: + +``` +./chip-tool onoff read on-off 1 +./chip-tool onoff on 1 +./chip-tool onoff off 1 +./chip-tool onoff toggle 1 +``` + +## Light switch press button and light status LED + +This demo uses button to test changing the light states and LED to show the +state of these changes. + +| Name | Pin | +| :----: | :---: | +| LED | PAD6 | +| BUTTON | PAD12 | diff --git a/examples/all-clusters-minimal-app/asr/args.gni b/examples/all-clusters-minimal-app/asr/args.gni new file mode 100755 index 00000000000000..66a2de849083d4 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":all_clusters_app_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/all-clusters-minimal-app/asr/build_overrides b/examples/all-clusters-minimal-app/asr/build_overrides new file mode 120000 index 00000000000000..194ee0b812dc3d --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides/ \ No newline at end of file diff --git a/examples/all-clusters-minimal-app/asr/cfg.gni b/examples/all-clusters-minimal-app/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/all-clusters-minimal-app/asr/include/AppConfig.h b/examples/all-clusters-minimal-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..6a633267878a8d --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/include/AppConfig.h @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2021 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. + */ + +#pragma once + +// ---- Lighting Example App Config ---- + +#define APP_TASK_NAME "APP" + +#define APP_EVENT_QUEUE_SIZE 10 +#define APP_TASK_STACK_SIZE (1024 * 4) +#define APP_WAIT_LOOP 1000 + +#define MATTER_DEVICE_NAME "ASR-Clusters-m" + +#define APP_LIGHT_BUTTON_IDX 0 +#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50 + +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/all-clusters-minimal-app/asr/include/AppEvent.h b/examples/all-clusters-minimal-app/asr/include/AppEvent.h new file mode 100755 index 00000000000000..2c59845f3bb577 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/include/AppEvent.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + enum AppEventTypes + { + kEventType_Button = 0, + kEventType_Timer, + kEventType_Light, + kEventType_Install, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t ButtonIdx; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/all-clusters-minimal-app/asr/include/AppTask.h b/examples/all-clusters-minimal-app/asr/include/AppTask.h new file mode 100755 index 00000000000000..97d1bfe538fb64 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/include/AppTask.h @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + static void LightActionEventHandler(AppEvent * aEvent); + void ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction); + void PostEvent(const AppEvent * event); + /** + * Use internally for registration of the ChipDeviceEvents + */ + static void CommonDeviceEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static AppTask sAppTask; + void DispatchEvent(AppEvent * event); + static void OnOffUpdateClusterState(void); +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/all-clusters-minimal-app/asr/include/CHIPProjectConfig.h b/examples/all-clusters-minimal-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..6a81ee6517aedb --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 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 + * 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 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 +#define CHIP_CONFIG_REQUIRE_AUTH 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a version of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/all-clusters-minimal-app/asr/include/DeviceCallbacks.h b/examples/all-clusters-minimal-app/asr/include/DeviceCallbacks.h new file mode 100755 index 00000000000000..18ebb25ed75f36 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg) override; + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); + void OnOnOffPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); + void OnIdentifyPostAttributeChangeCallback(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value); +}; diff --git a/examples/all-clusters-minimal-app/asr/src/AppTask.cpp b/examples/all-clusters-minimal-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..6b97d430953867 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/src/AppTask.cpp @@ -0,0 +1,230 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * Copyright 2021, Cypress Semiconductor Corporation (an Infineon company) + * 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 "AppConfig.h" +#include "AppEvent.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDWidget.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init_Matter.h" +#include "lega_rtos_api.h" + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +LEDWidget sStatusLED; +LEDWidget sLightLED; +LEDWidget sClusterLED; + +namespace { +TaskHandle_t sAppTaskHandle; +QueueHandle_t sAppEventQueue; +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +AppTask AppTask::sAppTask; + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + ASR_LOG("Failed to allocate app event queue"); + appError(APP_ERROR_EVENT_QUEUE_FAILED); + } + // Start App task. + xTaskCreate(AppTaskMain, APP_TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + return (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; +} + +CHIP_ERROR AppTask::Init() +{ + ASR_LOG("App Task started"); + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + return CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + CHIP_ERROR err = sAppTask.Init(); + + if (err != CHIP_NO_ERROR) + { + ASR_LOG("AppTask.Init() failed"); + appError(err); + } + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + } +} + +void AppTask::LightActionEventHandler(AppEvent * aEvent) +{ + /* ON/OFF Light Led based on Button interrupt */ + sLightLED.Invert(); + + /* Update OnOff Cluster state */ + sAppTask.OnOffUpdateClusterState(); +} + +void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction) +{ + if (btnIdx != APP_LIGHT_BUTTON_IDX) + { + return; + } + + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.ButtonIdx = btnIdx; + button_event.ButtonEvent.Action = btnAction; + + if ((btnIdx == APP_LIGHT_BUTTON_IDX) && (btnAction == APP_BUTTON_RELEASED)) + { + button_event.Handler = LightActionEventHandler; + sAppTask.PostEvent(&button_event); + } +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + if (sAppEventQueue != NULL) + { + BaseType_t status; + if (lega_rtos_is_in_interrupt_context()) + { + BaseType_t higherPrioTaskWoken = pdFALSE; + status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); + +#ifdef portYIELD_FROM_ISR + portYIELD_FROM_ISR(higherPrioTaskWoken); +#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + portEND_SWITCHING_ISR(higherPrioTaskWoken); +#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR +#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" +#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + } + else + { + status = xQueueSend(sAppEventQueue, aEvent, 1); + } + + if (!status) + ASR_LOG("Failed to post event to app task event queue"); + } + else + { + ASR_LOG("Event Queue is NULL should never happen"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + ASR_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::OnOffUpdateClusterState(void) +{ + uint8_t onoff = sLightLED.Get(); + + // write the new on/off value + EmberAfStatus status = app::Clusters::OnOff::Attributes::OnOff::Set(2, onoff); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ASR_LOG("ERR: updating on/off %x", status); + } +} + +bool lowPowerClusterSleep() +{ + return true; +} diff --git a/examples/all-clusters-minimal-app/asr/src/DeviceCallbacks.cpp b/examples/all-clusters-minimal-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..104b3f52a46364 --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,180 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" + +#include "CHIPDeviceManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LEDWidget.h" +#include "init_OTARequestor.h" +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +static const char * TAG = "app-devicecallbacks"; + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; + +uint32_t identifyTimerCount; +constexpr uint32_t kIdentifyTimerDelayMS = 250; +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + switch (clusterId) + { + case app::Clusters::OnOff::Id: + OnOnOffPostAttributeChangeCallback(endpointId, attributeId, value); + break; + + case app::Clusters::Identify::Id: + OnIdentifyPostAttributeChangeCallback(endpointId, attributeId, value); + break; + + default: + break; + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} + +void DeviceCallbacks::OnOnOffPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == chip::app::Clusters::OnOff::Attributes::OnOff::Id, + ChipLogError(DeviceLayer, TAG, "Unhandled Attribute ID: '0x%04x", attributeId)); + VerifyOrExit(endpointId == 1 || endpointId == 2, + ChipLogError(DeviceLayer, TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId)); + + // At this point we can assume that value points to a bool value. + // statusLED1.Set(*value); + +exit: + return; +} + +void IdentifyTimerHandler(Layer * systemLayer, void * appState, CHIP_ERROR error) +{ + if (identifyTimerCount) + { + identifyTimerCount--; + } +} + +void DeviceCallbacks::OnIdentifyPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value) +{ + VerifyOrExit(attributeId == chip::app::Clusters::Identify::Attributes::IdentifyTime::Id, + ChipLogError(DeviceLayer, "[%s] Unhandled Attribute ID: '0x%04lx", TAG, attributeId)); + VerifyOrExit(endpointId == 1, ChipLogError(DeviceLayer, "[%s] Unexpected EndPoint ID: `0x%02x'", TAG, endpointId)); + + // timerCount represents the number of callback executions before we stop the timer. + // value is expressed in seconds and the timer is fired every 250ms, so just multiply value by 4. + // Also, we want timerCount to be odd number, so the ligth state ends in the same state it starts. + identifyTimerCount = (*value) * 4; +exit: + return; +} diff --git a/examples/all-clusters-minimal-app/asr/src/main.cpp b/examples/all-clusters-minimal-app/asr/src/main.cpp new file mode 100644 index 00000000000000..7ef86db3591b1f --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/src/main.cpp @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * Copyright 2021, Cypress Semiconductor Corporation (an Infineon company) + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include + +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include +#include +#include +#include + +#include + +#include "AppConfig.h" +#include "init_asrPlatform.h" +#include + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/all-clusters-minimal-app/asr/third_party/connectedhomeip b/examples/all-clusters-minimal-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/all-clusters-minimal-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/bridge-app/asr/.gn b/examples/bridge-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/bridge-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/bridge-app/asr/BUILD.gn b/examples/bridge-app/asr/BUILD.gn new file mode 100755 index 00000000000000..a8db71bd3de7d3 --- /dev/null +++ b/examples/bridge-app/asr/BUILD.gn @@ -0,0 +1,134 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/bridge-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("bridge_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + "ENABLE_ASR_BRIDGE_SUBDEVICE_TEST=1", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("bridge_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-bridge-example.out" + + sources = [ + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/DeviceCallbacks.cpp", + "src/bridged-actions-stub.cpp", + "src/main.cpp", + "subdevice/SubDevice.cpp", + "subdevice/SubDeviceManager.cpp", + "subdevice/subdevice_test.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + deps = [ + ":bridge_app_sdk_sources", + "${chip_root}/examples/bridge-app/bridge-common", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "subdevice", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/src/lib", + ] + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + output_dir = root_out_dir +} + +group("asr") { + deps = [ ":bridge_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/bridge-app/asr/README.md b/examples/bridge-app/asr/README.md new file mode 100755 index 00000000000000..7f4e11a4b2bbe1 --- /dev/null +++ b/examples/bridge-app/asr/README.md @@ -0,0 +1,67 @@ +# Matter ASR Bridge Example + +This example demonstrates the Matter Bridge application on ASR platform. + +--- + +- [Matter ASR Bridge Example](#matter-asr-bridge-example) + - [Supported Chips](#supported-chips) + - [Introduction](#introduction) + - [Building and Commissioning](#building-and-commissioning) + - [Testing the example](#testing-the-example) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Introduction + +A prototype application that demonstrates dynamic endpoint with device +commissioning and cluster control. It adds the non-chip device as endpoints on a +bridge(Matter device). In this example four light devices supporting on-off +cluster have been added as endpoints + +1. Light1 at endpoint 3 +2. Light2 at endpoint 4 +3. Light3 at endpoint 5 +4. Light4 at endpoint 6 + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-bridge build +``` + +## Testing the example + +- An additional light-switch device is required to complete this example. +- Commission bridge device with node-id `1` +- Commission light-switch device with node-id `2` +- After bridge device and light-switch device successful commissioning, use + the GUI tool `DOGO` to input AT command `subdevice sync` for the bridge + device, and then use chip-tool to write ACL to the bridge device. + ``` + ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null },{"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [2], "targets": null }]' 1 0 + ``` +- After successful commissioning, use the `chip-tool` for binding + light-switch's endpoint 1 with bridge device's endpoint 3 respectively. + ``` + ./chip-tool binding write binding '[{"fabricIndex": 1, "node":1, "endpoint":3, "cluster":6}]' 2 1 + ``` +- Light switch button + + This demo uses button to test changing the `Light1`, and the bridge device + will output log information: + + | Name | Pin | + | :----: | :--: | + | BUTTON | PAD6 | diff --git a/examples/bridge-app/asr/args.gni b/examples/bridge-app/asr/args.gni new file mode 100755 index 00000000000000..705cc2b6022c81 --- /dev/null +++ b/examples/bridge-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":bridge_app_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/bridge-app/asr/build_overrides b/examples/bridge-app/asr/build_overrides new file mode 120000 index 00000000000000..194ee0b812dc3d --- /dev/null +++ b/examples/bridge-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides/ \ No newline at end of file diff --git a/examples/bridge-app/asr/cfg.gni b/examples/bridge-app/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/bridge-app/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/bridge-app/asr/include/AppConfig.h b/examples/bridge-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..1250881f65bf60 --- /dev/null +++ b/examples/bridge-app/asr/include/AppConfig.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// ---- Lighting Example App Config ---- + +#define APP_TASK_NAME "APP" +#define MATTER_DEVICE_NAME "ASR-Bridge" +#define APP_TASK_STACK_SIZE (1024 * 4) + +#define LIGHT_LED PWM_OUTPUT_CH4 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/bridge-app/asr/include/AppTask.h b/examples/bridge-app/asr/include/AppTask.h new file mode 100644 index 00000000000000..6cdf9e29daed8e --- /dev/null +++ b/examples/bridge-app/asr/include/AppTask.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + +private: + friend AppTask & GetAppTask(void); + + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/bridge-app/asr/include/CHIPProjectConfig.h b/examples/bridge-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..6b159a670b5ed7 --- /dev/null +++ b/examples/bridge-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,118 @@ +/* + * + * 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 + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +/** + * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY + * + * Enables the use of a hard-coded default Chip device id and credentials if no device id + * is found in Chip NV storage. + * + * This option is for testing only and should be disabled in production releases. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 34 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// define Device type based on the application +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 257 // 0x0101 Dimmable Bulb + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS + * + * Enable recording UTC timestamps. + */ +#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) + +/** + * CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + * + * A size, max count of the sub device for bridge app. + */ +#define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT (16) diff --git a/examples/bridge-app/asr/include/DeviceCallbacks.h b/examples/bridge-app/asr/include/DeviceCallbacks.h new file mode 100644 index 00000000000000..2b5cfe386f8f05 --- /dev/null +++ b/examples/bridge-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + virtual void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); +}; diff --git a/examples/bridge-app/asr/src/AppTask.cpp b/examples/bridge-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..be6763819ac986 --- /dev/null +++ b/examples/bridge-app/asr/src/AppTask.cpp @@ -0,0 +1,102 @@ +/* + * + * 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 "AppConfig.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "SubDeviceManager.h" +#include "init_Matter.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +TaskHandle_t sAppTaskHandle; +} // namespace + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +AppTask AppTask::sAppTask; + +namespace { +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + // Start App task. + xTaskCreate(AppTaskMain, APP_TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + return (sAppTaskHandle == nullptr) ? CHIP_APPLICATION_ERROR(0x02) : CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + ASR_LOG("App Task started"); + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Firmware Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + /* Init Device Endpoint */ + Init_Bridge_Endpoint(); + + /* Delete task */ + vTaskDelete(NULL); +} diff --git a/examples/bridge-app/asr/src/DeviceCallbacks.cpp b/examples/bridge-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..f16b4c956c8022 --- /dev/null +++ b/examples/bridge-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,133 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" +#include "AppConfig.h" +#include "CHIPDeviceManager.h" +#include "init_OTARequestor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; +using namespace ::chip::app::Clusters; + +uint32_t identifyTimerCount; +constexpr uint32_t kIdentifyTimerDelayMS = 250; +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ASR_LOG("IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ASR_LOG("Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ASR_LOG("IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ASR_LOG("Lost IPv6 connectivity..."); + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + ASR_LOG("PostAttributeChangeCallback - Cluster ID: '0x%" PRIx32 "', EndPoint ID: '0x%x', Attribute ID: '0x%" PRIx32 "'", + clusterId, endpointId, attributeId); +} diff --git a/examples/bridge-app/asr/src/bridged-actions-stub.cpp b/examples/bridge-app/asr/src/bridged-actions-stub.cpp new file mode 100755 index 00000000000000..91539e63f8f38e --- /dev/null +++ b/examples/bridge-app/asr/src/bridged-actions-stub.cpp @@ -0,0 +1,100 @@ +/* + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions::Attributes; + +namespace { + +class ActionsAttrAccess : public AttributeAccessInterface +{ +public: + // Register for the Actions cluster on all endpoints. + ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + +private: + static constexpr uint16_t ClusterRevision = 1; + + CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); +}; + +constexpr uint16_t ActionsAttrAccess::ClusterRevision; + +CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + // Just return an empty list + return aEncoder.EncodeEmptyList(); +} + +CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + // Just return an empty list + return aEncoder.EncodeEmptyList(); +} + +CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + const char SetupUrl[] = "https://example.com"; + return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); +} + +CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + return aEncoder.Encode(ClusterRevision); +} + +ActionsAttrAccess gAttrAccess; + +CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == Actions::Id); + + switch (aPath.mAttributeId) + { + case ActionList::Id: + return ReadActionListAttribute(aPath.mEndpointId, aEncoder); + case EndpointLists::Id: + return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); + case SetupURL::Id: + return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); + case ClusterRevision::Id: + return ReadClusterRevision(aPath.mEndpointId, aEncoder); + default: + break; + } + return CHIP_NO_ERROR; +} +} // anonymous namespace + +void MatterActionsPluginServerInitCallback(void) +{ + registerAttributeAccessOverride(&gAttrAccess); +} diff --git a/examples/bridge-app/asr/src/main.cpp b/examples/bridge-app/asr/src/main.cpp new file mode 100644 index 00000000000000..228eeff6f1ee68 --- /dev/null +++ b/examples/bridge-app/asr/src/main.cpp @@ -0,0 +1,76 @@ +/* + * + * 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 "AppConfig.h" +#include "init_asrPlatform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/bridge-app/asr/subdevice/SubDevice.cpp b/examples/bridge-app/asr/subdevice/SubDevice.cpp new file mode 100644 index 00000000000000..c0b60cc3d90f81 --- /dev/null +++ b/examples/bridge-app/asr/subdevice/SubDevice.cpp @@ -0,0 +1,154 @@ +/* + * + * 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 "SubDevice.h" +#ifdef __cplusplus +extern "C" { +#endif +#include +#if CONFIG_ENABLE_ASR_APP_MESH +#include "app.h" +#include "sonata_gap_api.h" +#include "sonata_gatt_api.h" +#endif +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +using namespace ::chip::Platform; + +SubDevice::SubDevice(const char * szSubDeviceName, const char * szLocation) +{ + CopyString(mName, sizeof(mName), szSubDeviceName); + CopyString(mLocation, sizeof(mLocation), szLocation); + mState = kState_Off; + mReachable = false; + mEndpointId = 0; + mChanged_CB = nullptr; +} + +bool SubDevice::IsOn() const +{ + return mState == kState_On; +} + +bool SubDevice::IsReachable() const +{ + return mReachable; +} + +void SubDevice::SetOnOff(bool aOn) +{ + bool changed; + + if (aOn) + { + changed = (mState != kState_On); + mState = kState_On; + ChipLogProgress(DeviceLayer, "SubDevice[%s]: ON", mName); +#if CONFIG_ENABLE_ASR_APP_MESH + if (strcmp(mName, "Light 1") == 0) + { + app_mesh_control_fan(1); + } + else + { + app_mesh_control_light(1); + } +#endif + } + else + { + changed = (mState != kState_Off); + mState = kState_Off; + ChipLogProgress(DeviceLayer, "SubDevice[%s]: OFF", mName); +#if CONFIG_ENABLE_ASR_APP_MESH + if (strcmp(mName, "Light 1") == 0) + { + app_mesh_control_fan(0); + } + else + { + app_mesh_control_light(0); + } +#endif + } + + if (changed && mChanged_CB) + { + mChanged_CB(this, kChanged_State); + } +} + +void SubDevice::SetReachable(bool aReachable) +{ + bool changed = (mReachable != aReachable); + + mReachable = aReachable; + + if (aReachable) + { + ChipLogProgress(DeviceLayer, "SubDevice[%s]: ONLINE", mName); + } + else + { + ChipLogProgress(DeviceLayer, "SubDevice[%s]: OFFLINE", mName); + } + + if (changed && mChanged_CB) + { + mChanged_CB(this, kChanged_Reachable); + } +} + +void SubDevice::SetName(const char * szName) +{ + bool changed = (strncmp(mName, szName, sizeof(mName)) != 0); + + ChipLogProgress(DeviceLayer, "SubDevice[%s]: New Name=\"%s\"", mName, szName); + + CopyString(mName, sizeof(mName), szName); + + if (changed && mChanged_CB) + { + mChanged_CB(this, kChanged_Name); + } +} + +void SubDevice::SetLocation(const char * szLocation) +{ + bool changed = (strncmp(mLocation, szLocation, sizeof(mLocation)) != 0); + + CopyString(mLocation, sizeof(mLocation), szLocation); + + ChipLogProgress(DeviceLayer, "SubDevice[%s]: Location=\"%s\"", mName, mLocation); + + if (changed && mChanged_CB) + { + mChanged_CB(this, kChanged_Location); + } +} + +void SubDevice::SetChangeCallback(SubDeviceCallback_fn aChanged_CB) +{ + mChanged_CB = aChanged_CB; +} diff --git a/examples/bridge-app/asr/subdevice/SubDevice.h b/examples/bridge-app/asr/subdevice/SubDevice.h new file mode 100755 index 00000000000000..d583b07b18c191 --- /dev/null +++ b/examples/bridge-app/asr/subdevice/SubDevice.h @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// These are the bridged devices +#include +#include +#include +#include + +class SubDevice +{ +public: + static const int kSubDeviceNameSize = 32; + static const int kSubDeviceLocationSize = 32; + + enum State_t + { + kState_On = 0, + kState_Off, + } State; + + enum Changed_t + { + kChanged_Reachable = 0x01, + kChanged_State = 0x02, + kChanged_Location = 0x04, + kChanged_Name = 0x08, + } Changed; + + SubDevice(const char * szSubDeviceName, const char * szLocation); + + bool IsOn() const; + bool IsReachable() const; + void SetOnOff(bool aOn); + void SetReachable(bool aReachable); + void SetName(const char * szSubDeviceName); + void SetLocation(const char * szLocation); + inline void SetEndpointId(chip::EndpointId id) { mEndpointId = id; }; + inline chip::EndpointId GetEndpointId() { return mEndpointId; }; + inline char * GetName() { return mName; }; + inline char * GetLocation() { return mLocation; }; + + using SubDeviceCallback_fn = std::function; + void SetChangeCallback(SubDeviceCallback_fn aChanged_CB); + +private: + State_t mState; + bool mReachable; + char mName[kSubDeviceNameSize]; + char mLocation[kSubDeviceLocationSize]; + chip::EndpointId mEndpointId; + SubDeviceCallback_fn mChanged_CB; +}; diff --git a/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp b/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp new file mode 100644 index 00000000000000..6e15406c9ff4fa --- /dev/null +++ b/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp @@ -0,0 +1,269 @@ +/* + * + * 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 "SubDeviceManager.h" +#include "SubDevice.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; +using namespace ::chip::Platform; +using namespace ::chip::app::Clusters; + +static EndpointId gCurrentEndpointId; +static EndpointId gFirstDynamicEndpointId; + +static SubDevice * gSubDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT]; // number of dynamic endpoints count + +int AddDeviceEndpoint(SubDevice * dev, EmberAfEndpointType * ep, const Span & deviceTypeList, + const Span & dataVersionStorage, chip::EndpointId parentEndpointId) +{ + uint8_t index = 0; + while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) + { + if (NULL == gSubDevices[index]) + { + gSubDevices[index] = dev; + EmberAfStatus ret; + while (1) + { + dev->SetEndpointId(gCurrentEndpointId); + ret = + emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, dataVersionStorage, deviceTypeList, parentEndpointId); + if (ret == EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogProgress(DeviceLayer, "Added device %s to dynamic endpoint %d (index=%d)", dev->GetName(), + gCurrentEndpointId, index); + return index; + } + else if (ret != EMBER_ZCL_STATUS_DUPLICATE_EXISTS) + { + return -1; + } + // Handle wrap condition + if (++gCurrentEndpointId < gFirstDynamicEndpointId) + { + gCurrentEndpointId = gFirstDynamicEndpointId; + } + } + } + index++; + } + ChipLogProgress(DeviceLayer, "Failed to add dynamic endpoint: No endpoints available!"); + return -1; +} + +CHIP_ERROR RemoveDeviceEndpoint(SubDevice * dev) +{ + for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; index++) + { + if (gSubDevices[index] == dev) + { + EndpointId ep = emberAfClearDynamicEndpoint(index); + gSubDevices[index] = NULL; + ChipLogProgress(DeviceLayer, "Removed device %s from dynamic endpoint %d (index=%d)", dev->GetName(), ep, index); + // Silence complaints about unused ep when progress logging + // disabled. + UNUSED_VAR(ep); + return CHIP_NO_ERROR; + } + } + return CHIP_ERROR_INTERNAL; +} + +EmberAfStatus HandleReadBridgedDeviceBasicAttribute(SubDevice * dev, chip::AttributeId attributeId, uint8_t * buffer, + uint16_t maxReadLength) +{ + using namespace BridgedDeviceBasicInformation::Attributes; + ChipLogProgress(DeviceLayer, "HandleReadBridgedDeviceBasicAttribute: attrId=%" PRIu32 ", maxReadLength=%u", attributeId, + maxReadLength); + + if ((attributeId == Reachable::Id) && (maxReadLength == 1)) + { + *buffer = dev->IsReachable() ? 1 : 0; + } + else if ((attributeId == NodeLabel::Id) && (maxReadLength == 32)) + { + MutableByteSpan zclNameSpan(buffer, maxReadLength); + MakeZclCharString(zclNameSpan, dev->GetName()); + } + else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 2)) + { + *buffer = (uint16_t) ZCL_BRIDGED_DEVICE_BASIC_CLUSTER_REVISION; + } + else + { + return EMBER_ZCL_STATUS_FAILURE; + } + + return EMBER_ZCL_STATUS_SUCCESS; +} + +EmberAfStatus HandleReadOnOffAttribute(SubDevice * dev, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "HandleReadOnOffAttribute: attrId=%" PRIu32 ", maxReadLength=%u", attributeId, maxReadLength); + + if ((attributeId == OnOff::Attributes::OnOff::Id) && (maxReadLength == 1)) + { + *buffer = dev->IsOn() ? 1 : 0; + } + else if ((attributeId == OnOff::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) + { + *buffer = (uint16_t) ZCL_ON_OFF_CLUSTER_REVISION; + } + else + { + return EMBER_ZCL_STATUS_FAILURE; + } + + return EMBER_ZCL_STATUS_SUCCESS; +} + +EmberAfStatus HandleWriteOnOffAttribute(SubDevice * dev, chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "HandleWriteOnOffAttribute: attrId=%" PRIu32, attributeId); + + ReturnErrorCodeIf((attributeId != OnOff::Attributes::OnOff::Id) || (!dev->IsReachable()), EMBER_ZCL_STATUS_FAILURE); + dev->SetOnOff(*buffer == 1); + return EMBER_ZCL_STATUS_SUCCESS; +} + +EmberAfStatus emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, + uint16_t maxReadLength) +{ + uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); + + if ((endpointIndex < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) && (gSubDevices[endpointIndex] != NULL)) + { + SubDevice * dev = gSubDevices[endpointIndex]; + + // if (clusterId == BridgedDeviceBasic::Id) + if (clusterId == BridgedDeviceBasicInformation::Id) + { + return HandleReadBridgedDeviceBasicAttribute(dev, attributeMetadata->attributeId, buffer, maxReadLength); + } + else if (clusterId == OnOff::Id) + { + return HandleReadOnOffAttribute(dev, attributeMetadata->attributeId, buffer, maxReadLength); + } + } + + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus emberAfExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer) +{ + uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); + + if (endpointIndex < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) + { + SubDevice * dev = gSubDevices[endpointIndex]; + + if ((dev->IsReachable()) && (clusterId == OnOff::Id)) + { + return HandleWriteOnOffAttribute(dev, attributeMetadata->attributeId, buffer); + } + } + + return EMBER_ZCL_STATUS_FAILURE; +} + +namespace { +void CallReportingCallback(intptr_t closure) +{ + auto path = reinterpret_cast(closure); + MatterReportingAttributeChangeCallback(*path); + Platform::Delete(path); +} + +void ScheduleReportingCallback(SubDevice * dev, ClusterId cluster, AttributeId attribute) +{ + auto * path = Platform::New(dev->GetEndpointId(), cluster, attribute); + DeviceLayer::PlatformMgr().ScheduleWork(CallReportingCallback, reinterpret_cast(path)); +} +} // anonymous namespace + +void HandleDeviceStatusChanged(SubDevice * dev, SubDevice::Changed_t itemChangedMask) +{ + if (itemChangedMask & SubDevice::kChanged_Reachable) + { + // ScheduleReportingCallback(dev, BridgedDeviceBasic::Id, BridgedDeviceBasic::Attributes::Reachable::Id); + ScheduleReportingCallback(dev, BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::Reachable::Id); + } + + if (itemChangedMask & SubDevice::kChanged_State) + { + ScheduleReportingCallback(dev, OnOff::Id, OnOff::Attributes::OnOff::Id); + } + + if (itemChangedMask & SubDevice::kChanged_Name) + { + // ScheduleReportingCallback(dev, BridgedDeviceBasic::Id, BridgedDeviceBasic::Attributes::NodeLabel::Id); + ScheduleReportingCallback(dev, BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::NodeLabel::Id); + } +} + +const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; +const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; + +bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, + const Actions::Commands::InstantAction::DecodableType & commandData) +{ + // No actions are implemented, just return status NotFound. + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); + return true; +} + +void Init_Bridge_Endpoint() +{ + // bridge will have own database named gSubDevices. + // Clear database + memset(gSubDevices, 0, sizeof(gSubDevices)); + + // Set starting endpoint id where dynamic endpoints will be assigned, which + // will be the next consecutive endpoint id after the last fixed endpoint. + gFirstDynamicEndpointId = static_cast( + static_cast(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1))) + 1); + gCurrentEndpointId = gFirstDynamicEndpointId; + + // Disable last fixed endpoint, which is used as a placeholder for all of the + // supported clusters so that ZAP will generated the requisite code. + emberAfEndpointEnableDisable(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1)), false); + + // A bridge has root node device type on EP0 and aggregate node device type (bridge) at EP1 + emberAfSetDeviceTypeList(0, Span(gRootDeviceTypes)); + emberAfSetDeviceTypeList(1, Span(gAggregateNodeDeviceTypes)); +} diff --git a/examples/bridge-app/asr/subdevice/SubDeviceManager.h b/examples/bridge-app/asr/subdevice/SubDeviceManager.h new file mode 100644 index 00000000000000..6885f3492a6cc7 --- /dev/null +++ b/examples/bridge-app/asr/subdevice/SubDeviceManager.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. + */ + +#pragma once + +#include "SubDevice.h" +#include "SubDeviceManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +#ifdef __cplusplus +extern "C" { +#endif + +// (taken from chip-devices.xml) +#define DEVICE_TYPE_BRIDGED_NODE 0x0013 +// (taken from lo-devices.xml) +#define DEVICE_TYPE_LO_ON_OFF_LIGHT 0x0100 + +// (taken from chip-devices.xml) +#define DEVICE_TYPE_ROOT_NODE 0x0016 +// (taken from chip-devices.xml) +#define DEVICE_TYPE_BRIDGE 0x000e + +// Device Version for dynamic endpoints: +#define DEVICE_VERSION_DEFAULT 1 + +/* REVISION definitions: + */ + +#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) +#define ZCL_BRIDGED_DEVICE_BASIC_CLUSTER_REVISION (1u) +#define ZCL_FIXED_LABEL_CLUSTER_REVISION (1u) +#define ZCL_ON_OFF_CLUSTER_REVISION (4u) + +int AddDeviceEndpoint(SubDevice * dev, EmberAfEndpointType * ep, const Span & deviceTypeList, + const Span & dataVersionStorage, chip::EndpointId parentEndpointId); +CHIP_ERROR RemoveDeviceEndpoint(SubDevice * dev); +EmberAfStatus HandleReadBridgedDeviceBasicAttribute(SubDevice * dev, chip::AttributeId attributeId, uint8_t * buffer, + uint16_t maxReadLength); +void HandleDeviceStatusChanged(SubDevice * dev, SubDevice::Changed_t itemChangedMask); +void Init_Bridge_Endpoint(); +#ifdef __cplusplus +} +#endif diff --git a/examples/bridge-app/asr/subdevice/subdevice_test.cpp b/examples/bridge-app/asr/subdevice/subdevice_test.cpp new file mode 100644 index 00000000000000..f4998294043925 --- /dev/null +++ b/examples/bridge-app/asr/subdevice/subdevice_test.cpp @@ -0,0 +1,159 @@ +/* + * + * 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 "SubDevice.h" +#include "SubDeviceManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; +using namespace ::chip::Platform; +using namespace ::chip::app::Clusters; + +#if ENABLE_ASR_BRIDGE_SUBDEVICE_TEST + +static const int kNodeLabelSize = 32; +// Current ZCL implementation of Struct uses a max-size array of 254 bytes +static const int kDescriptorAttributeArraySize = 254; + +// 4 Bridged devices +static SubDevice gLight1("Light 1", "Office"); +static SubDevice gLight2("Light 2", "Office"); +static SubDevice gLight3("Light 3", "Kitchen"); +static SubDevice gLight4("Light 4", "Den"); + +/* BRIDGED DEVICE ENDPOINT: contains the following clusters: + - On/Off + - Descriptor + - Bridged Device Basic +*/ + +// Declare On/Off cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(onOffAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(OnOff::Attributes::OnOff::Id, BOOLEAN, 1, 0), /* on/off */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Descriptor cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */ + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */ + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */ + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Bridged Device Basic information cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), /* NodeLabel */ + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0), /* Reachable */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Cluster List for Bridged Light endpoint +// TODO: It's not clear whether it would be better to get the command lists from +// the ZAP config on our last fixed endpoint instead. +constexpr CommandId onOffIncomingCommands[] = { + app::Clusters::OnOff::Commands::Off::Id, + app::Clusters::OnOff::Commands::On::Id, + app::Clusters::OnOff::Commands::Toggle::Id, + app::Clusters::OnOff::Commands::OffWithEffect::Id, + app::Clusters::OnOff::Commands::OnWithRecallGlobalScene::Id, + app::Clusters::OnOff::Commands::OnWithTimedOff::Id, + kInvalidCommandId, +}; + +DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedLightClusters) +DECLARE_DYNAMIC_CLUSTER(OnOff::Id, onOffAttrs, onOffIncomingCommands, nullptr), + DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, nullptr, nullptr), + // DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasic::Id, bridgedDeviceBasicAttrs, nullptr, nullptr) + DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, nullptr, + nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; + +// Declare Bridged Light endpoint +DECLARE_DYNAMIC_ENDPOINT(bridgedLightEndpoint, bridgedLightClusters); + +DataVersion gLight1DataVersions[ArraySize(bridgedLightClusters)]; +DataVersion gLight2DataVersions[ArraySize(bridgedLightClusters)]; +DataVersion gLight3DataVersions[ArraySize(bridgedLightClusters)]; +DataVersion gLight4DataVersions[ArraySize(bridgedLightClusters)]; + +const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; +const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; + +const EmberAfDeviceType gBridgedOnOffDeviceTypes[] = { { DEVICE_TYPE_LO_ON_OFF_LIGHT, DEVICE_VERSION_DEFAULT }, + { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } }; + +extern "C" void Sync_SubDevice_test(void); +extern "C" void Add_SubDevice_test(void); +extern "C" void Remove_SubDevice_test(void); + +void Sync_SubDevice_test() +{ + gLight1.SetReachable(true); + gLight2.SetReachable(true); + gLight3.SetReachable(true); + gLight4.SetReachable(true); + + // Whenever bridged device changes its state + gLight1.SetChangeCallback(&HandleDeviceStatusChanged); + gLight2.SetChangeCallback(&HandleDeviceStatusChanged); + gLight3.SetChangeCallback(&HandleDeviceStatusChanged); + gLight4.SetChangeCallback(&HandleDeviceStatusChanged); + + // Add lights 1..4 --> will be mapped to ZCL endpoints 3..6 + AddDeviceEndpoint(&gLight1, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), + Span(gLight1DataVersions), 1); + AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), + Span(gLight2DataVersions), 1); + AddDeviceEndpoint(&gLight3, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), + Span(gLight3DataVersions), 1); + AddDeviceEndpoint(&gLight4, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), + Span(gLight4DataVersions), 1); +} + +void Add_SubDevice_test() +{ + gLight2.SetReachable(true); + gLight2.SetChangeCallback(&HandleDeviceStatusChanged); + // Re-add Light 2 -- > will be mapped to ZCL endpoint 7 + AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, Span(gBridgedOnOffDeviceTypes), + Span(gLight2DataVersions), 1); +} + +void Remove_SubDevice_test() +{ + gLight2.SetChangeCallback(NULL); + gLight2.SetReachable(false); + // Remove Light 2 -- Others Lights remain + RemoveDeviceEndpoint(&gLight2); +} +#endif // ENABLE_ASR_BRIDGE_SUBDEVICE_TEST diff --git a/examples/bridge-app/asr/third_party/connectedhomeip b/examples/bridge-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/bridge-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/light-switch-app/asr/.gn b/examples/light-switch-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/light-switch-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/light-switch-app/asr/BUILD.gn b/examples/light-switch-app/asr/BUILD.gn new file mode 100755 index 00000000000000..68f0db7fbe4ef7 --- /dev/null +++ b/examples/light-switch-app/asr/BUILD.gn @@ -0,0 +1,136 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("//cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/light-switch-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("light_switch_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("light_switch_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-light-switch-example.out" + + public_deps = [ + ":light_switch_app_sdk_sources", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/src/lib", + ] + + sources = [ + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/BindingHandler.cpp", + "src/ButtonHandler.cpp", + "src/DeviceCallbacks.cpp", + "src/LEDManager.cpp", + "src/LightSwitch.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + defines += [ "GENERIC_SWITCH_ENDPOINT=1" ] + + public_deps += + [ "${chip_root}/examples/light-switch-app/light-switch-common" ] + + output_dir = root_out_dir + + if (chip_print_memory_usage) { + ldflags = [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } +} + +group("asr") { + deps = [ ":light_switch_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/light-switch-app/asr/README.md b/examples/light-switch-app/asr/README.md new file mode 100755 index 00000000000000..c7eba7e2ea116e --- /dev/null +++ b/examples/light-switch-app/asr/README.md @@ -0,0 +1,52 @@ +# Matter ASR Light Switch Example + +This example demonstrates the Matter Light Switch application on ASR platform. + +--- + +- [Matter ASR Light Switch Example](#matter-asr-light-switch-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Testing the example](#testing-the-example) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-light-switch build +``` + +## Testing the example + +- An additional lighting device is required to complete this example. +- Commission lighting device with node-id `1` +- Commission light-switch device with node-id `2` +- After successful commissioning, use the `chip-tool` to write the ACL in + Lighting device to allow access from light-switch device and chip-tool. + ``` + ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null },{"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [2], "targets": null }]' 1 0 + ``` +- After successful commissioning, use the `chip-tool` for binding in + light-switch. + ``` + ./chip-tool binding write binding '[{"fabricIndex": 1, "node":1, "endpoint":1, "cluster":6}]' 2 1 + ``` +- Light switch button + + This demo uses button to test changing the state of lighting: + + | Name | Pin | + | :----: | :--: | + | BUTTON | PAD6 | diff --git a/examples/light-switch-app/asr/args.gni b/examples/light-switch-app/asr/args.gni new file mode 100755 index 00000000000000..d46ba8ec90759f --- /dev/null +++ b/examples/light-switch-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":light_switch_app_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/light-switch-app/asr/build_overrides b/examples/light-switch-app/asr/build_overrides new file mode 120000 index 00000000000000..194ee0b812dc3d --- /dev/null +++ b/examples/light-switch-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides/ \ No newline at end of file diff --git a/examples/light-switch-app/asr/cfg.gni b/examples/light-switch-app/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/light-switch-app/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/light-switch-app/asr/include/AppConfig.h b/examples/light-switch-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..88fefe79fd45cc --- /dev/null +++ b/examples/light-switch-app/asr/include/AppConfig.h @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#include "asr_pinmux.h" +#define duet_gpio_dev_t asr_gpio_dev_t +#else +#include "duet_gpio.h" +#include "duet_pinmux.h" +#endif + +#define TASK_NAME "APP" +#define MATTER_DEVICE_NAME "ASR-Switch" +#define APP_TASK_STACK_SIZE (4096) +#define APP_EVENT_QUEUE_SIZE 10 + +#define GPIO_TASK_NAME "gpio" +#define GPIO_TASK_STACK_SIZE 1024 + +#define BUTTON_DEBOUNCE_PERIOD_MS 50 + +#define BUTTON_PRESSED 0 +#define BUTTON_RELEASED 1 + +#define SWITCH1_BUTTON GPIO6_INDEX +#define SWITCH2_BUTTON GPIO7_INDEX +#define GENERIC_SWITCH_BUTTON GPIO7_INDEX +#define SYSTEM_STATE_LED GPIO12_INDEX +#define SWITCH_LED GPIO13_INDEX + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ---- Lock Example SWU Config ---- +#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours +#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours + +// ---- Thread Polling Config ---- +#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 +#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/light-switch-app/asr/include/AppEvent.h b/examples/light-switch-app/asr/include/AppEvent.h new file mode 100755 index 00000000000000..49ded0945896f9 --- /dev/null +++ b/examples/light-switch-app/asr/include/AppEvent.h @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + constexpr static uint8_t kButtonPushEvent = 1; + constexpr static uint8_t kButtonReleaseEvent = 0; + + enum AppEventTypes + { + kEventType_StartBLEAdvertising, + kEventType_Button, + kEventType_Timer, + kEventType_UpdateLedState, + kEventType_IdentifyStart, + kEventType_IdentifyStop, + kEventType_Light, + kEventType_Install, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t PinNo; + uint8_t Action; + } ButtonEvent; + struct + { + uint8_t TimerType; + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LightEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/light-switch-app/asr/include/AppTask.h b/examples/light-switch-app/asr/include/AppTask.h new file mode 100755 index 00000000000000..c103fd6f60944e --- /dev/null +++ b/examples/light-switch-app/asr/include/AppTask.h @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + void PostEvent(const AppEvent * event); + static void AppTaskMain(void * pvParameter); + static void UpdateClusterState(void); + static void ButtonEventHandler(uint8_t, uint8_t); + static void UpdateStatusLED(); + +private: + enum class Timer : uint8_t + { + Function, + DimmerTrigger, + Dimmer + }; + enum class TimerFunction : uint8_t + { + NoneSelected = 0, + SoftwareUpdate, + FactoryReset + }; + TimerFunction mFunction = TimerFunction::NoneSelected; + + enum class Button : uint8_t + { + Function, + Dimmer, + }; + + friend AppTask & GetAppTask(void); + static AppTask sAppTask; + + CHIP_ERROR Init(); + + void DispatchEvent(AppEvent * event); + + static void ButtonPushHandler(AppEvent *); + static void ButtonReleaseHandler(AppEvent *); + static void StartBLEAdvertisingHandler(AppEvent *); + + static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *, intptr_t); +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/light-switch-app/asr/include/BindingHandler.h b/examples/light-switch-app/asr/include/BindingHandler.h new file mode 100755 index 00000000000000..28509842b7ed84 --- /dev/null +++ b/examples/light-switch-app/asr/include/BindingHandler.h @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "app-common/zap-generated/ids/Clusters.h" +#include "app-common/zap-generated/ids/Commands.h" +#include "lib/core/CHIPError.h" +#include +#include +#include +#include + +class BindingHandler +{ +public: + struct BindingData + { + chip::EndpointId EndpointId; + chip::CommandId CommandId; + chip::ClusterId ClusterId; + uint8_t Value; + bool IsGroup{ false }; + }; + + void Init(); + void PrintBindingTable(); + bool IsGroupBound(); + + static void SwitchWorkerHandler(intptr_t); + static void OnInvokeCommandFailure(BindingData & aBindingData, CHIP_ERROR aError); + + static BindingHandler & GetInstance() + { + static BindingHandler sBindingHandler; + return sBindingHandler; + } + +private: + static void OnOffProcessCommand(chip::CommandId, const EmberBindingTableEntry &, chip::OperationalDeviceProxy *, void *); + static void LevelControlProcessCommand(chip::CommandId, const EmberBindingTableEntry &, chip::OperationalDeviceProxy *, void *); + static void LightSwitchChangedHandler(const EmberBindingTableEntry &, chip::OperationalDeviceProxy *, void *); + static void LightSwitchContextReleaseHandler(void * context); + static void InitInternal(intptr_t); + + bool mCaseSessionRecovered = false; +}; diff --git a/examples/light-switch-app/asr/include/ButtonHandler.h b/examples/light-switch-app/asr/include/ButtonHandler.h new file mode 100644 index 00000000000000..8e853ba46b1da1 --- /dev/null +++ b/examples/light-switch-app/asr/include/ButtonHandler.h @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppEvent.h" +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#else +#include "duet_gpio.h" +#endif + +class ButtonHandler +{ +public: + static void Init(void); + +private: + static void GpioInit(void); +}; diff --git a/examples/light-switch-app/asr/include/CHIPProjectConfig.h b/examples/light-switch-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..df81858b4f3bc0 --- /dev/null +++ b/examples/light-switch-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * 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 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS + * + * Enable recording UTC timestamps. + */ +#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) + +/** + * @def CHIP_CONFIG_MRP_DEFAULT_ACTIVE_RETRY_INTERVAL + * + * @brief + * Active retransmit interval, or time to wait before retransmission after + * subsequent failures in milliseconds. + * + * This is the default value, that might be adjusted by end device depending on its + * needs (e.g. sleeping period) using Service Discovery TXT record CRA key. + * + */ +#define CHIP_CONFIG_MRP_DEFAULT_ACTIVE_RETRY_INTERVAL (2000_ms32) diff --git a/examples/light-switch-app/asr/include/DeviceCallbacks.h b/examples/light-switch-app/asr/include/DeviceCallbacks.h new file mode 100755 index 00000000000000..204263cdaed4b2 --- /dev/null +++ b/examples/light-switch-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg) override; + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); +}; diff --git a/examples/light-switch-app/asr/include/LEDManager.h b/examples/light-switch-app/asr/include/LEDManager.h new file mode 100644 index 00000000000000..a8c29a24a61e07 --- /dev/null +++ b/examples/light-switch-app/asr/include/LEDManager.h @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "AppConfig.h" +#include + +#ifndef LED_Manager_H +#define LED_Manager_H + +class LEDManager +{ +public: + static void InitGpio(void); + void Init(uint8_t ledNum); + void Set(bool state); + void Invert(void); + void Blink(uint32_t changeRateMS); + void Blink(uint32_t onTimeMS, uint32_t offTimeMS); + void Animate(); + +private: + uint64_t mLastChangeTimeMS; + uint32_t mBlinkOnTimeMS; + uint32_t mBlinkOffTimeMS; + uint8_t mGPIONum; + bool mState; + duet_gpio_dev_t gpio; + + void DoSet(bool state); +}; + +#endif // LED_Manager_H diff --git a/examples/light-switch-app/asr/include/LightSwitch.h b/examples/light-switch-app/asr/include/LightSwitch.h new file mode 100644 index 00000000000000..746d46286cb225 --- /dev/null +++ b/examples/light-switch-app/asr/include/LightSwitch.h @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +class LightSwitch +{ +public: + enum class Action : uint8_t + { + Toggle, /// Switch state on lighting-app device + On, /// Turn on light on lighting-app device + Off /// Turn off light on lighting-app device + }; + + void Init(chip::EndpointId aLightSwitchEndpoint); + void InitGeneric(chip::EndpointId aGenericSwitchEndpoint); + void InitiateActionSwitch(Action); + void SwitchChangeBrightness(uint16_t sBrightness); + void GenericSwitchInitialPress(); + void GenericSwitchReleasePress(); + chip::EndpointId GetLightSwitchEndpointId() { return mLightSwitchEndpoint; } + + static LightSwitch & GetInstance() + { + static LightSwitch sLightSwitch; + return sLightSwitch; + } + +private: + constexpr static auto kMaximumBrightness = 254; + + chip::EndpointId mLightSwitchEndpoint; + chip::EndpointId mGenericSwitchEndpointId; +}; diff --git a/examples/light-switch-app/asr/src/AppTask.cpp b/examples/light-switch-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..8836459a7564f2 --- /dev/null +++ b/examples/light-switch-app/asr/src/AppTask.cpp @@ -0,0 +1,509 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "BindingHandler.h" +#include "ButtonHandler.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDManager.h" +#include "LightSwitch.h" +#include "init_Matter.h" +#include "lega_rtos_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +LightSwitch kLightSwitch1; + +namespace { +TaskHandle_t sAppTaskHandle; +QueueHandle_t sAppEventQueue; + +LEDManager sStatusLED; +LEDManager sSwitchLED; + +constexpr EndpointId kLightSwitch1_EndpointId = 1; +#if DUAL_LIGHTSWITCH_ENDPOINT +LightSwitch kLightSwitch2; +constexpr EndpointId kLightSwitch2_EndpointId = 2; +#endif +#if GENERIC_SWITCH_ENDPOINT +LightSwitch GenericSwitch; +constexpr EndpointId kGenericSwitchEndpointId = 2; +#endif + +constexpr size_t kAppEventQueueSize = 10; + +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +Clusters::Identify::EffectIdentifierEnum sIdentifyEffect = Clusters::Identify::EffectIdentifierEnum::kStopEffect; + +namespace { +void OnTriggerIdentifyEffectCompleted(chip::System::Layer * systemLayer, void * appState) +{ + sIdentifyEffect = Clusters::Identify::EffectIdentifierEnum::kStopEffect; +} +} // namespace + +void OnTriggerIdentifyEffect(Identify * identify) +{ + sIdentifyEffect = identify->mCurrentEffectIdentifier; + + if (identify->mCurrentEffectIdentifier == Clusters::Identify::EffectIdentifierEnum::kChannelChange) + { + ChipLogProgress(Zcl, "IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE - Not supported, use effect varriant %d", + to_underlying(identify->mEffectVariant)); + sIdentifyEffect = static_cast(identify->mEffectVariant); + } + + switch (sIdentifyEffect) + { + case Clusters::Identify::EffectIdentifierEnum::kBlink: + case Clusters::Identify::EffectIdentifierEnum::kBreathe: + case Clusters::Identify::EffectIdentifierEnum::kOkay: + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(5), OnTriggerIdentifyEffectCompleted, + identify); + break; + case Clusters::Identify::EffectIdentifierEnum::kFinishEffect: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerIdentifyEffectCompleted, identify); + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(1), OnTriggerIdentifyEffectCompleted, + identify); + break; + case Clusters::Identify::EffectIdentifierEnum::kStopEffect: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerIdentifyEffectCompleted, identify); + sIdentifyEffect = Clusters::Identify::EffectIdentifierEnum::kStopEffect; + break; + default: + ChipLogProgress(Zcl, "No identifier effect"); + } +} + +Identify gIdentify = { + chip::EndpointId{ 1 }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStart"); }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStop"); }, + Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator, + OnTriggerIdentifyEffect, +}; +} // namespace + +AppTask AppTask::sAppTask; +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + ASR_LOG("Failed to allocate app event queue"); + appError(APP_ERROR_EVENT_QUEUE_FAILED); + } + + // Start App task. + xTaskCreate(AppTaskMain, TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + err = (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; + + return err; +} + +CHIP_ERROR AppTask::Init() +{ + ASR_LOG("App Task started"); + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + NetWorkCommissioningInstInit(); + + kLightSwitch1.Init(kLightSwitch1_EndpointId); +#if DUAL_LIGHTSWITCH_ENDPOINT + kLightSwitch2.Init(kLightSwitch2_EndpointId); +#endif +#if GENERIC_SWITCH_ENDPOINT + GenericSwitch.InitGeneric(kGenericSwitchEndpointId); +#endif + // Initialize LEDs + LEDManager::InitGpio(); + + sStatusLED.Init(SYSTEM_STATE_LED); + sStatusLED.Set(false); + + sSwitchLED.Init(SWITCH_LED); + sSwitchLED.Set(false); + UpdateStatusLED(); + + // Initialise WSTK buttons PB0 and PB1 (including debounce). + ButtonHandler::Init(); + + UpdateClusterState(); + + ASR_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + return CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + ASR_LOG("AppTask.Init() failed"); + appError(err); + } + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + + sStatusLED.Animate(); + sSwitchLED.Animate(); + } +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + if (sAppEventQueue != NULL) + { + BaseType_t status; + if (lega_rtos_is_in_interrupt_context()) + { + BaseType_t higherPrioTaskWoken = pdFALSE; + status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); + +#ifdef portYIELD_FROM_ISR + portYIELD_FROM_ISR(higherPrioTaskWoken); +#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + portEND_SWITCHING_ISR(higherPrioTaskWoken); +#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR +#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" +#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + } + else + { + status = xQueueSend(sAppEventQueue, aEvent, 1); + } + + if (!status) + ASR_LOG("Failed to post event to app task event queue"); + } + else + { + ASR_LOG("Event Queue is NULL should never happen"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + ASR_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateClusterState(void) {} + +#define SWITCH_Toggle + +//#define SWITCH_DELAY_ONOFF + +#if DUAL_LIGHTSWITCH_ENDPOINT +#undef SWITCH_Toggle +#undef SWITCH_DELAY_ONOFF +#endif + +#ifdef SWITCH_DELAY_ONOFF +#define SWITCH_TIMER "switch_delay_timer" +#define SWITCH_DELAY_TIME 5 * 1000 +static TimerHandle_t Switch_TimerHandle; +void Switch_Delay_CallBack(TimerHandle_t xTimer) +{ + ASR_LOG("Switch1 OFF!"); + kLightSwitch1.InitiateActionSwitch(LightSwitch::Action::Off); +} +#endif + +void AppTask::ButtonPushHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_Button) + { + switch (aEvent->ButtonEvent.PinNo) + { + case SWITCH1_BUTTON: +#ifdef SWITCH_Toggle + // ASR_LOG("Switch1 Button Pushed."); +#endif +#if DUAL_LIGHTSWITCH_ENDPOINT + ASR_LOG("Switch1 ON!"); + kLightSwitch1.InitiateActionSwitch(LightSwitch::Action::On); +#endif +#ifdef SWITCH_DELAY_ONOFF + { + ASR_LOG("Switch1 ON ,delay %d ms!", SWITCH_DELAY_TIME); + kLightSwitch1.InitiateActionSwitch(LightSwitch::Action::On); + + if (Switch_TimerHandle == NULL) + { + Switch_TimerHandle = + xTimerCreate(SWITCH_TIMER, pdMS_TO_TICKS(SWITCH_DELAY_TIME), pdFALSE, NULL, Switch_Delay_CallBack); + if (Switch_TimerHandle == NULL) + { + ASR_LOG("Failed to create a timer"); + } + } + if (xTimerIsTimerActive(Switch_TimerHandle)) + { + ASR_LOG("switch timer already started!"); + if (xTimerStop(Switch_TimerHandle, 0) == pdFAIL) + { + ASR_LOG("switch timer stop() failed"); + } + } + if (xTimerChangePeriod(Switch_TimerHandle, pdMS_TO_TICKS(SWITCH_DELAY_TIME), 100) != pdPASS) + { + ASR_LOG("switch timer start() failed"); + } + } +#endif + break; +#if DUAL_LIGHTSWITCH_ENDPOINT + case SWITCH2_BUTTON: + ASR_LOG("Switch2 ON!"); + kLightSwitch2.InitiateActionSwitch(LightSwitch::Action::On); + break; +#endif +#if GENERIC_SWITCH_ENDPOINT + case GENERIC_SWITCH_BUTTON: + ASR_LOG("GenericSwitch: InitialPress"); + GenericSwitch.GenericSwitchInitialPress(); + break; +#endif + default: + break; + } + } +} + +void AppTask::ButtonReleaseHandler(AppEvent * aEvent) +{ + + if (aEvent->Type == AppEvent::kEventType_Button) + { + switch (aEvent->ButtonEvent.PinNo) + { + case SWITCH1_BUTTON: +#ifdef SWITCH_Toggle + sSwitchLED.Set(false); + ASR_LOG("Switch1 Toggle!"); + kLightSwitch1.InitiateActionSwitch(LightSwitch::Action::Toggle); +#endif +#if DUAL_LIGHTSWITCH_ENDPOINT + ASR_LOG("Switch1 OFF!"); + kLightSwitch1.InitiateActionSwitch(LightSwitch::Action::Off); +#endif + break; +#if DUAL_LIGHTSWITCH_ENDPOINT + case SWITCH2_BUTTON: + ASR_LOG("Switch2 OFF!"); + kLightSwitch2.InitiateActionSwitch(LightSwitch::Action::Off); + break; +#endif +#if GENERIC_SWITCH_ENDPOINT + case GENERIC_SWITCH_BUTTON: + ASR_LOG("GenericSwitch: ShortRelease"); + GenericSwitch.GenericSwitchReleasePress(); + break; +#endif + default: + break; + } + } +} + +void AppTask::StartBLEAdvertisingHandler(AppEvent * aEvent) +{ + /// Don't allow on starting Matter service BLE advertising after Thread provisioning. + if (Server::GetInstance().GetFabricTable().FabricCount() != 0) + { + ASR_LOG("Matter service BLE advertising not started - device is already commissioned"); + return; + } + + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + ASR_LOG("BLE advertising is already enabled"); + return; + } + + ASR_LOG("Enabling BLE advertising..."); + if (Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR) + { + ASR_LOG("OpenBasicCommissioningWindow() failed"); + } +} + +void AppTask::UpdateStatusLED() +{ + bool sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); + bool sIsWiFiBLEAdvertising = ConnectivityMgr().IsBLEAdvertisingEnabled(); + bool sIsWiFiProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); + bool sIsWiFiEnabled = ConnectivityMgr().IsWiFiStationEnabled(); + // Status LED indicates: + // - blinking 1 s - advertising, ready to commission + // - blinking 200 ms - commissioning in progress + // - constant lightning means commissioned with Thread network + if (sIsWiFiBLEAdvertising && !sHaveBLEConnections) + { + sStatusLED.Blink(50, 950); + } + else if (sIsWiFiProvisioned && sIsWiFiEnabled) + { + sStatusLED.Set(true); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(30, 170); + } + else + { + sStatusLED.Blink(500); + } +} + +void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction) +{ + + AppEvent buttonEvent; + buttonEvent.Type = AppEvent::kEventType_Button; + + if (btnIdx == SWITCH1_BUTTON) + { + if (btnAction == BUTTON_PRESSED) + { + buttonEvent.ButtonEvent.PinNo = SWITCH1_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonPushEvent; + buttonEvent.Handler = ButtonPushHandler; + sAppTask.PostEvent(&buttonEvent); + } + else if (btnAction == BUTTON_RELEASED) + { + buttonEvent.ButtonEvent.PinNo = SWITCH1_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonReleaseEvent; + buttonEvent.Handler = ButtonReleaseHandler; + sAppTask.PostEvent(&buttonEvent); + } + } +#if DUAL_LIGHTSWITCH_ENDPOINT + else if (btnIdx == SWITCH2_BUTTON) + { + if (btnAction == BUTTON_PRESSED) + { + buttonEvent.ButtonEvent.PinNo = SWITCH2_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonPushEvent; + buttonEvent.Handler = ButtonPushHandler; + sAppTask.PostEvent(&buttonEvent); + } + else if (btnAction == BUTTON_RELEASED) + { + buttonEvent.ButtonEvent.PinNo = SWITCH2_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonReleaseEvent; + buttonEvent.Handler = ButtonReleaseHandler; + sAppTask.PostEvent(&buttonEvent); + } + } +#endif +#if GENERIC_SWITCH_ENDPOINT + else if (btnIdx == GENERIC_SWITCH_BUTTON) + { + if (btnAction == BUTTON_PRESSED) + { + buttonEvent.ButtonEvent.PinNo = GENERIC_SWITCH_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonPushEvent; + buttonEvent.Handler = ButtonPushHandler; + sAppTask.PostEvent(&buttonEvent); + } + else if (btnAction == BUTTON_RELEASED) + { + buttonEvent.ButtonEvent.PinNo = GENERIC_SWITCH_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonReleaseEvent; + buttonEvent.Handler = ButtonReleaseHandler; + sAppTask.PostEvent(&buttonEvent); + } + } +#endif +} diff --git a/examples/light-switch-app/asr/src/BindingHandler.cpp b/examples/light-switch-app/asr/src/BindingHandler.cpp new file mode 100644 index 00000000000000..bb2d1d754fc70f --- /dev/null +++ b/examples/light-switch-app/asr/src/BindingHandler.cpp @@ -0,0 +1,316 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BindingHandler.h" +#include "AppConfig.h" +#include "app/CommandSender.h" +#include "app/clusters/bindings/BindingManager.h" +#include "app/server/Server.h" +#include "controller/InvokeInteraction.h" +#include "platform/CHIPDeviceLayer.h" +#include +#include + +using namespace chip; +using namespace chip::app; + +void BindingHandler::Init() +{ + // The initialization of binding manager will try establishing connection with unicast peers + // so it requires the Server instance to be correctly initialized. Post the init function to + // the event queue so that everything is ready when initialization is conducted. + chip::DeviceLayer::PlatformMgr().ScheduleWork(InitInternal); +} + +void BindingHandler::OnInvokeCommandFailure(BindingData & aBindingData, CHIP_ERROR aError) +{ + CHIP_ERROR error; + + if (aError == CHIP_ERROR_TIMEOUT && !BindingHandler::GetInstance().mCaseSessionRecovered) + { + ASR_LOG("Response timeout for invoked command, trying to recover CASE session."); + + // Set flag to not try recover session multiple times. + BindingHandler::GetInstance().mCaseSessionRecovered = true; + + // Allocate new object to make sure its life time will be appropriate. + BindingHandler::BindingData * data = Platform::New(); + *data = aBindingData; + + // Establish new CASE session and retrasmit command that was not applied. + error = BindingManager::GetInstance().NotifyBoundClusterChanged(aBindingData.EndpointId, aBindingData.ClusterId, + static_cast(data)); + + if (CHIP_NO_ERROR != error) + { + ASR_LOG("NotifyBoundClusterChanged failed due to: %" CHIP_ERROR_FORMAT, error.Format()); + return; + } + } + else + { + ASR_LOG("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, aError.Format()); + } +} + +void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, + OperationalDeviceProxy * aDevice, void * aContext) +{ + CHIP_ERROR ret = CHIP_NO_ERROR; + BindingData * data = reinterpret_cast(aContext); + + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + ASR_LOG("Binding command applied successfully!"); + + // If session was recovered and communication works, reset flag to the initial state. + if (BindingHandler::GetInstance().mCaseSessionRecovered) + BindingHandler::GetInstance().mCaseSessionRecovered = false; + }; + + auto onFailure = [dataRef = *data](CHIP_ERROR aError) mutable { BindingHandler::OnInvokeCommandFailure(dataRef, aError); }; + + if (aDevice) + { + // We are validating connection is ready once here instead of multiple times in each case statement below. + VerifyOrDie(aDevice->ConnectionReady()); + } + + switch (aCommandId) + { + case Clusters::OnOff::Commands::Toggle::Id: + Clusters::OnOff::Commands::Toggle::Type toggleCommand; + if (aDevice) + { + ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(), + aBinding.remote, toggleCommand, onSuccess, onFailure); + } + else + { + + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, toggleCommand); + } + break; + + case Clusters::OnOff::Commands::On::Id: + Clusters::OnOff::Commands::On::Type onCommand; + if (aDevice) + { + ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(), + aBinding.remote, onCommand, onSuccess, onFailure); + } + else + { + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, onCommand); + } + break; + + case Clusters::OnOff::Commands::Off::Id: + Clusters::OnOff::Commands::Off::Type offCommand; + if (aDevice) + { + ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(), + aBinding.remote, offCommand, onSuccess, onFailure); + } + else + { + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, offCommand); + } + break; + default: + ASR_LOG("Invalid binding command data - commandId is not supported"); + break; + } + if (CHIP_NO_ERROR != ret) + { + ASR_LOG("Invoke OnOff Command Request ERROR: %s", ErrorStr(ret)); + } +} + +void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, + OperationalDeviceProxy * aDevice, void * aContext) +{ + CHIP_ERROR ret = CHIP_NO_ERROR; + BindingData * data = reinterpret_cast(aContext); + + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + ASR_LOG("Binding command applied successfully!"); + + // If session was recovered and communication works, reset flag to the initial state. + if (BindingHandler::GetInstance().mCaseSessionRecovered) + BindingHandler::GetInstance().mCaseSessionRecovered = false; + }; + + auto onFailure = [dataRef = *data](CHIP_ERROR aError) mutable { BindingHandler::OnInvokeCommandFailure(dataRef, aError); }; + + if (aDevice) + { + // We are validating connection is ready once here instead of multiple times in each case statement below. + VerifyOrDie(aDevice->ConnectionReady()); + } + + switch (aCommandId) + { + case Clusters::LevelControl::Commands::MoveToLevel::Id: { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + moveToLevelCommand.level = data->Value; + if (aDevice) + { + ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(), + aBinding.remote, moveToLevelCommand, onSuccess, onFailure); + } + else + { + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, moveToLevelCommand); + } + } + break; + default: + ASR_LOG("Invalid binding command data - CommandId is not supported"); + break; + } + if (CHIP_NO_ERROR != ret) + { + ASR_LOG("Invoke Group Command Request ERROR: %s", ErrorStr(ret)); + } +} + +void BindingHandler::LightSwitchChangedHandler(const EmberBindingTableEntry & aBinding, OperationalDeviceProxy * deviceProxy, + void * context) +{ + VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null")); + BindingData * data = static_cast(context); + + if (aBinding.type == EMBER_MULTICAST_BINDING && data->IsGroup) + { + switch (data->ClusterId) + { + case Clusters::OnOff::Id: + OnOffProcessCommand(data->CommandId, aBinding, nullptr, context); + break; + case Clusters::LevelControl::Id: + LevelControlProcessCommand(data->CommandId, aBinding, nullptr, context); + break; + default: + ChipLogError(NotSpecified, "Invalid binding group command data"); + break; + } + } + else if (aBinding.type == EMBER_UNICAST_BINDING && !data->IsGroup) + { + switch (data->ClusterId) + { + case Clusters::OnOff::Id: + OnOffProcessCommand(data->CommandId, aBinding, deviceProxy, context); + break; + case Clusters::LevelControl::Id: + LevelControlProcessCommand(data->CommandId, aBinding, deviceProxy, context); + break; + default: + ChipLogError(NotSpecified, "Invalid binding unicast command data"); + break; + } + } +} + +void BindingHandler::LightSwitchContextReleaseHandler(void * context) +{ + VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "LightSwitchContextReleaseHandler: context is null")); + + Platform::Delete(static_cast(context)); +} + +void BindingHandler::InitInternal(intptr_t arg) +{ + ASR_LOG("Initialize binding Handler"); + auto & server = chip::Server::GetInstance(); + chip::BindingManager::GetInstance().Init( + { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() }); + chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler); + chip::BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(LightSwitchContextReleaseHandler); + BindingHandler::GetInstance().PrintBindingTable(); +} + +bool BindingHandler::IsGroupBound() +{ + BindingTable & bindingTable = BindingTable::GetInstance(); + + for (auto & entry : bindingTable) + { + if (EMBER_MULTICAST_BINDING == entry.type) + { + return true; + } + } + return false; +} + +void BindingHandler::PrintBindingTable() +{ + BindingTable & bindingTable = BindingTable::GetInstance(); + + ASR_LOG("Binding Table size: [%d]:", bindingTable.Size()); + uint8_t i = 0; + for (auto & entry : bindingTable) + { + switch (entry.type) + { + case EMBER_UNICAST_BINDING: + ASR_LOG("[%d] UNICAST:", i++); + ASR_LOG("\t\t+ Fabric: %d\n \ + \t+ LocalEndpoint %d \n \ + \t+ ClusterId %d \n \ + \t+ RemoteEndpointId %d \n \ + \t+ NodeId %d", + (int) entry.fabricIndex, (int) entry.local, (int) entry.clusterId.Value(), (int) entry.remote, + (int) entry.nodeId); + break; + case EMBER_MULTICAST_BINDING: + ASR_LOG("[%d] GROUP:", i++); + ASR_LOG("\t\t+ Fabric: %d\n \ + \t+ LocalEndpoint %d \n \ + \t+ RemoteEndpointId %d \n \ + \t+ GroupId %d", + (int) entry.fabricIndex, (int) entry.local, (int) entry.remote, (int) entry.groupId); + break; + case EMBER_UNUSED_BINDING: + ASR_LOG("[%d] UNUSED", i++); + break; + // case EMBER_MANY_TO_ONE_BINDING: + // ASR_LOG("[%d] MANY TO ONE", i++); + // break; + default: + break; + } + } +} + +/******************************************************** + * Switch functions + *********************************************************/ + +void BindingHandler::SwitchWorkerHandler(intptr_t context) +{ + VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "SwitchWorkerFunction - Invalid work data")); + + BindingData * data = reinterpret_cast(context); + BindingManager::GetInstance().NotifyBoundClusterChanged(data->EndpointId, data->ClusterId, static_cast(data)); +} diff --git a/examples/light-switch-app/asr/src/ButtonHandler.cpp b/examples/light-switch-app/asr/src/ButtonHandler.cpp new file mode 100644 index 00000000000000..c0d521bc9d8858 --- /dev/null +++ b/examples/light-switch-app/asr/src/ButtonHandler.cpp @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ButtonHandler.h" +#include "AppConfig.h" +#include "AppTask.h" +#include + +#ifdef CFG_PLF_RV32 +#define duet_gpio_init asr_gpio_init +#define duet_gpio_input_get asr_gpio_input_get +#define DUET_INPUT_PULL_UP ASR_INPUT_PULL_UP +#endif + +TaskHandle_t sGpioTaskHandle; +static void GpioTaskMain(void * pvParameter); + +void ButtonHandler::Init(void) +{ + GpioInit(); + + xTaskCreate(GpioTaskMain, GPIO_TASK_NAME, GPIO_TASK_STACK_SIZE, 0, 2, &sGpioTaskHandle); +} + +// port pin +duet_gpio_dev_t switch1_btn; +duet_gpio_dev_t switch2_btn; + +void ButtonHandler::GpioInit(void) +{ + // light switch1 button + switch1_btn.port = SWITCH1_BUTTON; + switch1_btn.config = DUET_INPUT_PULL_UP; + switch1_btn.priv = NULL; + duet_gpio_init(&switch1_btn); +#if DUAL_LIGHTSWITCH_ENDPOINT + // light switch2 button + switch2_btn.port = SWITCH2_BUTTON; +#endif +#if GENERIC_SWITCH_ENDPOINT + // generic switch2 button + switch2_btn.port = GENERIC_SWITCH_BUTTON; +#endif + switch2_btn.config = DUET_INPUT_PULL_UP; + switch2_btn.priv = NULL; + duet_gpio_init(&switch2_btn); +} + +static uint32_t btn1Value = 1; +static uint8_t btn1_trigger = 0; +static uint32_t btn2Value = 1; +static uint8_t btn2_trigger = 0; +void GpioTaskMain(void * pvParameter) +{ + ASR_LOG("GPIO Task started"); + uint32_t btnValue; + uint8_t buttonevent = 0; + while (true) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + // switch button 1 + duet_gpio_input_get(&switch1_btn, &btnValue); + if (btnValue != btn1Value) + { + if (btn1_trigger) + { + btn1Value = btnValue; + buttonevent = (uint8_t) btnValue; + GetAppTask().ButtonEventHandler(SWITCH1_BUTTON, (buttonevent) ? BUTTON_RELEASED : BUTTON_PRESSED); + btn1_trigger = 0; + } + else + { + btn1_trigger = 1; + } + } + else + { + btn1_trigger = 0; + } + // switch button 2 + duet_gpio_input_get(&switch2_btn, &btnValue); + if (btnValue != btn2Value) + { + if (btn2_trigger) + { + btn2Value = btnValue; + buttonevent = (uint8_t) btnValue; +#if DUAL_LIGHTSWITCH_ENDPOINT + GetAppTask().ButtonEventHandler(SWITCH2_BUTTON, (buttonevent) ? BUTTON_RELEASED : BUTTON_PRESSED); +#endif +#if GENERIC_SWITCH_ENDPOINT + GetAppTask().ButtonEventHandler(GENERIC_SWITCH_BUTTON, (buttonevent) ? BUTTON_RELEASED : BUTTON_PRESSED); +#endif + btn2_trigger = 0; + } + else + { + btn2_trigger = 1; + } + } + else + { + btn2_trigger = 0; + } + } +} diff --git a/examples/light-switch-app/asr/src/DeviceCallbacks.cpp b/examples/light-switch-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..e967094e0fbccd --- /dev/null +++ b/examples/light-switch-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,147 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" +#include "AppTask.h" +#include "CHIPDeviceManager.h" +#include "LEDWidget.h" +#include "init_OTARequestor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; +using namespace ::chip::app::Clusters; + +uint32_t identifyTimerCount; + +constexpr uint32_t kIdentifyTimerDelayMS = 250; +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + GetAppTask().UpdateStatusLED(); + break; + case DeviceEventType::kCHIPoBLEAdvertisingChange: + GetAppTask().UpdateStatusLED(); + break; + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == OnOffSwitchConfiguration::Id) + { + ChipLogProgress(Zcl, "OnOff Switch Configuration attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + // WIP Apply attribute change to Light + } + else if (clusterId == Identify::Id) + { + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} diff --git a/examples/light-switch-app/asr/src/LEDManager.cpp b/examples/light-switch-app/asr/src/LEDManager.cpp new file mode 100644 index 00000000000000..518f5c05186abf --- /dev/null +++ b/examples/light-switch-app/asr/src/LEDManager.cpp @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LEDManager.h" +#include "AppTask.h" +#include + +#ifdef CFG_PLF_RV32 +#define duet_gpio_init asr_gpio_init +#define duet_gpio_output_low asr_gpio_output_low +#define duet_gpio_output_high asr_gpio_output_high +#define DUET_OUTPUT_PUSH_PULL ASR_OUTPUT_PUSH_PULL +#endif + +void LEDManager::InitGpio(void) {} + +void LEDManager::Init(uint8_t gpioNum) +{ + mLastChangeTimeMS = 0; + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + mGPIONum = gpioNum; + + gpio.port = mGPIONum; + gpio.config = DUET_OUTPUT_PUSH_PULL; + duet_gpio_init(&gpio); +} + +void LEDManager::Invert(void) +{ + Set(!mState); +} + +void LEDManager::Set(bool state) +{ + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + DoSet(state); +} + +void LEDManager::Blink(uint32_t changeRateMS) +{ + Blink(changeRateMS, changeRateMS); +} + +void LEDManager::Blink(uint32_t onTimeMS, uint32_t offTimeMS) +{ + mBlinkOnTimeMS = onTimeMS; + mBlinkOffTimeMS = offTimeMS; + Animate(); +} + +void LEDManager::Animate() +{ + if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) + { + uint64_t nowMS = chip::System::SystemClock().GetMonotonicMilliseconds64().count(); + uint64_t stateDurMS = ((mState) ? mBlinkOnTimeMS : mBlinkOffTimeMS); + uint64_t nextChangeTimeMS = mLastChangeTimeMS + stateDurMS; + + if (nextChangeTimeMS < nowMS) + { + DoSet(!mState); + mLastChangeTimeMS = nowMS; + } + } +} + +void LEDManager::DoSet(bool state) +{ + mState = state; + + if (state) + { + duet_gpio_output_low(&gpio); + } + else + { + duet_gpio_output_high(&gpio); + } +} diff --git a/examples/light-switch-app/asr/src/LightSwitch.cpp b/examples/light-switch-app/asr/src/LightSwitch.cpp new file mode 100644 index 00000000000000..4365131e3110e5 --- /dev/null +++ b/examples/light-switch-app/asr/src/LightSwitch.cpp @@ -0,0 +1,113 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LightSwitch.h" +#include "AppEvent.h" +#include "BindingHandler.h" +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; + +void LightSwitch::Init(chip::EndpointId aLightDimmerSwitchEndpoint) +{ + BindingHandler::GetInstance().Init(); + mLightSwitchEndpoint = aLightDimmerSwitchEndpoint; +} + +void LightSwitch::InitiateActionSwitch(Action mAction) +{ + BindingHandler::BindingData * data = Platform::New(); + if (data) + { + data->EndpointId = mLightSwitchEndpoint; + data->ClusterId = Clusters::OnOff::Id; + switch (mAction) + { + case Action::Toggle: + data->CommandId = Clusters::OnOff::Commands::Toggle::Id; + break; + case Action::On: + data->CommandId = Clusters::OnOff::Commands::On::Id; + break; + case Action::Off: + data->CommandId = Clusters::OnOff::Commands::Off::Id; + break; + default: + Platform::Delete(data); + return; + } + data->IsGroup = BindingHandler::GetInstance().IsGroupBound(); + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + } +} + +void LightSwitch::SwitchChangeBrightness(uint16_t sBrightness) +{ + BindingHandler::BindingData * data = Platform::New(); + if (data) + { + data->EndpointId = mLightSwitchEndpoint; + data->CommandId = Clusters::LevelControl::Commands::MoveToLevel::Id; + data->ClusterId = Clusters::LevelControl::Id; + // set brightness of light. + if (sBrightness > kMaximumBrightness) + { + sBrightness = kMaximumBrightness; + } + data->Value = (uint8_t) sBrightness; + data->IsGroup = BindingHandler::GetInstance().IsGroupBound(); + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + } +} + +void LightSwitch::InitGeneric(chip::EndpointId aGenericSwitchEndpoint) +{ + BindingHandler::GetInstance().Init(); + mGenericSwitchEndpointId = aGenericSwitchEndpoint; +} + +void LightSwitch::GenericSwitchInitialPress() +{ + DeviceLayer::SystemLayer().ScheduleLambda([this] { + // Press moves Position from 0 (idle) to 1 (press) + uint8_t newPosition = 1; + + Clusters::Switch::Attributes::CurrentPosition::Set(mGenericSwitchEndpointId, newPosition); + // InitialPress event takes newPosition as event data + Clusters::SwitchServer::Instance().OnInitialPress(mGenericSwitchEndpointId, newPosition); + }); +} + +void LightSwitch::GenericSwitchReleasePress() +{ + DeviceLayer::SystemLayer().ScheduleLambda([this] { + // Release moves Position from 1 (press) to 0 (idle) + uint8_t previousPosition = 1; + uint8_t newPosition = 0; + + Clusters::Switch::Attributes::CurrentPosition::Set(mGenericSwitchEndpointId, newPosition); + // ShortRelease event takes previousPosition as event data + Clusters::SwitchServer::Instance().OnShortRelease(mGenericSwitchEndpointId, previousPosition); + }); +} diff --git a/examples/light-switch-app/asr/src/main.cpp b/examples/light-switch-app/asr/src/main.cpp new file mode 100644 index 00000000000000..f83f06573ff7d5 --- /dev/null +++ b/examples/light-switch-app/asr/src/main.cpp @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppConfig.h" +#include "init_asrPlatform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/light-switch-app/asr/third_party/connectedhomeip b/examples/light-switch-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/light-switch-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/lock-app/asr/.gn b/examples/lock-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/lock-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/lock-app/asr/BUILD.gn b/examples/lock-app/asr/BUILD.gn new file mode 100755 index 00000000000000..8e6b86822418d8 --- /dev/null +++ b/examples/lock-app/asr/BUILD.gn @@ -0,0 +1,131 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/lock-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("lock_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("lock_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-lock-example.out" + + public_deps = [ + ":lock_app_sdk_sources", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/lock-app/lock-common", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/src/lib", + ] + + sources = [ + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/BoltLockManager.cpp", + "src/ButtonHandler.cpp", + "src/DeviceCallbacks.cpp", + "src/LEDManager.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + output_dir = root_out_dir + + if (chip_print_memory_usage) { + ldflags = [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } +} + +group("asr") { + deps = [ ":lock_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/lock-app/asr/README.md b/examples/lock-app/asr/README.md new file mode 100755 index 00000000000000..00c7bc0f8a37eb --- /dev/null +++ b/examples/lock-app/asr/README.md @@ -0,0 +1,56 @@ +# Matter ASR Lock Example + +The ASR Lock Example demonstrates how to remotely control a door lock device +with one basic bolt. It uses buttons to test changing the lock and device states +and LEDs to show the state of these changes. You can use this example as a +reference for creating your own application. + +--- + +- [Matter ASR Lock Example](#matter-asr-lock-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Cluster Control](#cluster-control) + - [Lock press button and lock status led](#lock-press-button-and-lock-status-led) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-lock build +``` + +## Cluster Control + +After successful commissioning, use `chip-tool` to control the board + +- OnOff Cluster + +``` +./chip-tool onoff read on-off 1 +./chip-tool onoff on 1 +./chip-tool onoff off 1 +./chip-tool onoff toggle 1 +``` + +## Lock press button and lock status led + +This demo uses button to test changing the lock and device states and LED to +show the state of these changes. + +| Name | Pin | +| :---------: | :---: | +| LOCK-STATE | PAD13 | +| LOCK-BUTTON | PAD6 | diff --git a/examples/lock-app/asr/args.gni b/examples/lock-app/asr/args.gni new file mode 100755 index 00000000000000..9c9e2aa953656d --- /dev/null +++ b/examples/lock-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":lock_app_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/lock-app/asr/build_overrides b/examples/lock-app/asr/build_overrides new file mode 120000 index 00000000000000..194ee0b812dc3d --- /dev/null +++ b/examples/lock-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides/ \ No newline at end of file diff --git a/examples/lock-app/asr/cfg.gni b/examples/lock-app/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/lock-app/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/lock-app/asr/include/AppConfig.h b/examples/lock-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..60320f47c9f3c7 --- /dev/null +++ b/examples/lock-app/asr/include/AppConfig.h @@ -0,0 +1,83 @@ +/* + * + * 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 + +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#include "asr_pinmux.h" +#define duet_gpio_dev_t asr_gpio_dev_t +#else +#include "duet_gpio.h" +#include "duet_pinmux.h" +#endif + +// ---- Lock Example App Config ---- + +#define APP_TASK_NAME "APP" + +#define APP_TASK_STACK_SIZE (1024 * 4) +#define APP_TASK_PRIORITY 2 +#define APP_EVENT_QUEUE_SIZE 10 + +#define MATTER_DEVICE_NAME "ASR-LOCK" + +#define APP_LOCK_BUTTON_IDX 0 +#define APP_FUNCTION_BUTTON_IDX 1 + +#define APP_LOCK_BUTTON GPIO6_INDEX +#define APP_FUNCTION_BUTTON GPIO7_INDEX + +#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50 + +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 + +#define SYSTEM_STATE_LED GPIO12_INDEX +#define LOCK_STATE_LED GPIO13_INDEX + +#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 +#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ---- Lock Example SWU Config ---- +#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours +#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours + +// ---- Thread Polling Config ---- +#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 +#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/lock-app/asr/include/AppEvent.h b/examples/lock-app/asr/include/AppEvent.h new file mode 100755 index 00000000000000..7b954c05230f1d --- /dev/null +++ b/examples/lock-app/asr/include/AppEvent.h @@ -0,0 +1,57 @@ +/* + * + * 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 + { + uint8_t ButtonIdx; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LockEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/lock-app/asr/include/AppTask.h b/examples/lock-app/asr/include/AppTask.h new file mode 100755 index 00000000000000..854d70efdb9744 --- /dev/null +++ b/examples/lock-app/asr/include/AppTask.h @@ -0,0 +1,95 @@ +/* + * + * 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 +#include + +#include "AppEvent.h" +#include "BoltLockManager.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + + void PostLockActionRequest(int32_t actor, BoltLockManager::Action action); + void PostEvent(const AppEvent * event); + + void ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction); + void UpdateClusterState(void); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static void ActionInitiated(BoltLockManager::Action action, int32_t actor); + static void ActionCompleted(BoltLockManager::Action action); + + void CancelTimer(void); + + void DispatchEvent(AppEvent * event); + + static void FunctionTimerEventHandler(AppEvent * event); + static void FunctionHandler(AppEvent * event); + static void LockActionEventHandler(AppEvent * event); + static void TimerEventHandler(TimerHandle_t timer); + + static void UpdateCluster(intptr_t context); + + void StartTimer(uint32_t aTimeoutMs); + + enum class Function + { + kNoneSelected = 0, + kSoftwareUpdate = 0, + kStartBleAdv = 1, + kFactoryReset = 2, + + kInvalid + }; + + Function mFunction = Function::kNoneSelected; + bool mFunctionTimerActive = false; + bool mSyncClusterToButtonAction = false; + + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/lock-app/asr/include/BoltLockManager.h b/examples/lock-app/asr/include/BoltLockManager.h new file mode 100755 index 00000000000000..4c0093b3efd592 --- /dev/null +++ b/examples/lock-app/asr/include/BoltLockManager.h @@ -0,0 +1,84 @@ +/* + * + * 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 + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support + +#include + +class BoltLockManager +{ +public: + enum class Action + { + kLock = 0, + kUnlock, + KInvalid + }; + + enum class State + { + kLockingInitiated = 0, + kLockingCompleted, + kUnlockingInitiated, + kUnlockingCompleted, + }; + + CHIP_ERROR Init(); + bool IsUnlocked(); + void EnableAutoRelock(bool aOn); + void SetAutoLockDuration(uint32_t aDurationInSecs); + bool IsActionInProgress(); + bool InitiateAction(int32_t aActor, Action aAction); + + typedef void (*Callback_fn_initiated)(Action, int32_t aActor); + typedef void (*Callback_fn_completed)(Action); + void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + +private: + friend BoltLockManager & BoltLockMgr(void); + State mState = State::kUnlockingCompleted; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + bool mAutoRelock = false; + uint32_t mAutoLockDuration = 0; + bool mAutoLockTimerArmed = false; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + static void TimerEventHandler(TimerHandle_t xTimer); + 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/asr/include/ButtonHandler.h b/examples/lock-app/asr/include/ButtonHandler.h new file mode 100755 index 00000000000000..978cad1937b8d9 --- /dev/null +++ b/examples/lock-app/asr/include/ButtonHandler.h @@ -0,0 +1,51 @@ +/* + * + * 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 "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer suppo +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#define duet_gpio_dev_t asr_gpio_dev_t +#define DUET_INPUT_PULL_UP ASR_INPUT_PULL_UP +#define duet_gpio_init asr_gpio_init +#define duet_gpio_output_low asr_gpio_output_low +#define duet_gpio_output_high asr_gpio_output_high +#define duet_gpio_input_get asr_gpio_input_get +#define duet_gpio_enable_irq asr_gpio_enable_irq +#define DUET_IRQ_TRIGGER_FALLING_EDGE ASR_IRQ_TRIGGER_FALLING_EDGE +#else +#include "duet_gpio.h" +#endif + +#define GPIO_INTERRUPT_PRIORITY (5) + +class ButtonHandler +{ +public: + static void Init(void); + +private: + static void GpioInit(void); + static void lockbuttonIsr(void * handler_arg); + static void functionbuttonIsr(void * handler_arg); + static void TimerCallback(TimerHandle_t xTimer); +}; diff --git a/examples/lock-app/asr/include/CHIPProjectConfig.h b/examples/lock-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..fbaf9ea3c7c9be --- /dev/null +++ b/examples/lock-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,112 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +/** + * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY + * + * Enables the use of a hard-coded default Chip device id and credentials if no device id + * is found in Chip NV storage. + * + * This option is for testing only and should be disabled in production releases. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 34 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// define Device type based on the application +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 10 // 0x00A Door lock + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +// #define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/lock-app/asr/include/DeviceCallbacks.h b/examples/lock-app/asr/include/DeviceCallbacks.h new file mode 100755 index 00000000000000..11fb7177fe8466 --- /dev/null +++ b/examples/lock-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg) override; + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); +}; diff --git a/examples/lock-app/asr/include/LEDManager.h b/examples/lock-app/asr/include/LEDManager.h new file mode 100644 index 00000000000000..b64d1e88e8c17c --- /dev/null +++ b/examples/lock-app/asr/include/LEDManager.h @@ -0,0 +1,47 @@ +/* + * + * 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 "AppConfig.h" +#include + +#ifndef LED_Manager_H +#define LED_Manager_H + +class LEDManager +{ +public: + void InitGpio(void); + void Init(uint8_t ledNum); + void Set(bool state); + void Invert(void); + void Blink(uint32_t changeRateMS); + void Blink(uint32_t onTimeMS, uint32_t offTimeMS); + void Animate(); + +private: + uint64_t mLastChangeTimeMS; + uint32_t mBlinkOnTimeMS; + uint32_t mBlinkOffTimeMS; + uint8_t mGPIONum; + bool mState; + duet_gpio_dev_t gpio; + + void DoSet(bool state); +}; + +#endif // LED_Manager_H diff --git a/examples/lock-app/asr/src/AppTask.cpp b/examples/lock-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..d46069955dc6ab --- /dev/null +++ b/examples/lock-app/asr/src/AppTask.cpp @@ -0,0 +1,497 @@ +/* + * + * 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 "AppConfig.h" +#include "AppEvent.h" +#include "ButtonHandler.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDManager.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init_Matter.h" +#include +#include +#include +#include +#include + +namespace { + +TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. + +TaskHandle_t sAppTaskHandle; +QueueHandle_t sAppEventQueue; + +LEDManager sStatusLED; +LEDManager sLockLED; + +bool sIsWiFiStationEnabled = false; +bool sIsWiFiStationConnected = false; +bool sHaveBLEConnections = false; +} // namespace + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +AppTask AppTask::sAppTask; + +namespace { +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + ASR_LOG("Failed to allocate app event queue"); + appError(APP_ERROR_EVENT_QUEUE_FAILED); + } + + // Start App task. + xTaskCreate(AppTaskMain, APP_TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + return (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; +} + +CHIP_ERROR AppTask::Init() +{ + ASR_LOG("App Task started"); + + CHIP_ERROR err = CHIP_NO_ERROR; + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + return CHIP_ERROR_INTERNAL; + + // Initialise WSTK buttons PB0 and PB1 (including debounce). + ButtonHandler::Init(); + + // Create FreeRTOS sw timer for Function Selection. + sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = app task obj context + TimerEventHandler // timer callback handler + ); + if (sFunctionTimer == NULL) + { + ASR_LOG("funct timer create failed"); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + err = BoltLockMgr().Init(); + if (err != CHIP_NO_ERROR) + { + ASR_LOG("BoltLockMgr().Init() failed"); + appError(err); + } + + BoltLockMgr().SetCallbacks(ActionInitiated, ActionCompleted); + + // Initialize LEDs + sStatusLED.Init(SYSTEM_STATE_LED); + sStatusLED.Set(0); + + sLockLED.Init(LOCK_STATE_LED); + sLockLED.Set(!BoltLockMgr().IsUnlocked()); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + return err; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + ASR_LOG("AppTask.Init() failed"); + appError(err); + } + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + if (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + } + + // 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 != Function::kFactoryReset) + { + if (sIsWiFiStationEnabled && !sIsWiFiStationConnected) + { + sStatusLED.Blink(950, 50); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(100, 100); + } + else + { + sStatusLED.Blink(50, 950); + } + } + sStatusLED.Animate(); + sLockLED.Animate(); + } +} + +void AppTask::LockActionEventHandler(AppEvent * event) +{ + bool initiated = false; + BoltLockManager::Action action = BoltLockManager::Action::KInvalid; + int32_t actor = 0; + CHIP_ERROR err = CHIP_NO_ERROR; + + if (event->Type == AppEvent::kEventType_Lock) + { + action = static_cast(event->LockEvent.Action); + actor = event->LockEvent.Actor; + } + else if (event->Type == AppEvent::kEventType_Button) + { + if (BoltLockMgr().IsUnlocked()) + { + action = BoltLockManager::Action::kLock; + } + else + { + action = BoltLockManager::Action::kUnlock; + } + actor = AppEvent::kEventType_Button; + } + else + { + err = APP_ERROR_UNHANDLED_EVENT; + } + + if (err == CHIP_NO_ERROR) + { + initiated = BoltLockMgr().InitiateAction(actor, action); + + if (!initiated) + { + ASR_LOG("Action is already in progress or active."); + } + } +} + +void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction) +{ + if (btnIdx != APP_LOCK_BUTTON_IDX && btnIdx != APP_FUNCTION_BUTTON_IDX) + { + return; + } + + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.ButtonIdx = btnIdx; + button_event.ButtonEvent.Action = btnAction; + + if (btnIdx == APP_LOCK_BUTTON_IDX) + { + button_event.Handler = LockActionEventHandler; + sAppTask.PostEvent(&button_event); + } + else if (btnIdx == APP_FUNCTION_BUTTON_IDX) + { + button_event.Handler = FunctionHandler; + sAppTask.PostEvent(&button_event); + } +} + +void AppTask::TimerEventHandler(TimerHandle_t timer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = (void *) timer; + event.Handler = FunctionTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FunctionTimerEventHandler(AppEvent * event) +{ + if (event->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 == Function::kStartBleAdv) + { + ASR_LOG("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 = Function::kFactoryReset; + + // 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 == Function::kFactoryReset) + { + // Actually trigger Factory Reset + sAppTask.mFunction = Function::kNoneSelected; + chip::Server::GetInstance().ScheduleFactoryReset(); + } +} + +void AppTask::FunctionHandler(AppEvent * event) +{ + if (event->ButtonEvent.ButtonIdx != APP_FUNCTION_BUTTON_IDX) + { + return; + } + // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< + // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the + // APP_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 APP_FUNCTION_BUTTON once all LEDs + // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT + if (event->ButtonEvent.Action == APP_BUTTON_RELEASED) + { + if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kNoneSelected) + { + sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); + sAppTask.mFunction = Function::kStartBleAdv; + } + } + else + { + // If the button was released before factory reset got initiated, start Thread Network + if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kStartBleAdv) + { + sAppTask.CancelTimer(); + sAppTask.mFunction = Function::kNoneSelected; + } + else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kFactoryReset) + { + // 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 = Function::kNoneSelected; + + ASR_LOG("Factory Reset has been Canceled"); + } + } +} + +void AppTask::CancelTimer() +{ + if (xTimerStop(sFunctionTimer, 0) == pdFAIL) + { + ASR_LOG("app timer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } + + mFunctionTimerActive = false; +} + +void AppTask::StartTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sFunctionTimer)) + { + ASR_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + ASR_LOG("app timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } + + mFunctionTimerActive = true; +} + +void AppTask::ActionInitiated(BoltLockManager::Action action, int32_t actor) +{ + // 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 (action == BoltLockManager::Action::kLock) + { + ASR_LOG("Lock Action has been initiated"); + } + else if (action == BoltLockManager::Action::kUnlock) + { + ASR_LOG("Unlock Action has been initiated"); + } + + if (actor == AppEvent::kEventType_Button) + { + sAppTask.mSyncClusterToButtonAction = true; + } + + sLockLED.Blink(50, 50); +} + +void AppTask::ActionCompleted(BoltLockManager::Action action) +{ + // 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 (action == BoltLockManager::Action::kLock) + { + ASR_LOG("Lock Action has been completed"); + + sLockLED.Set(true); + } + else if (action == BoltLockManager::Action::kUnlock) + { + ASR_LOG("Unlock Action has been completed"); + + sLockLED.Set(false); + } + + if (sAppTask.mSyncClusterToButtonAction) + { + sAppTask.UpdateClusterState(); + sAppTask.mSyncClusterToButtonAction = false; + } +} + +void AppTask::PostLockActionRequest(int32_t actor, BoltLockManager::Action action) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Lock; + event.LockEvent.Actor = actor; + event.LockEvent.Action = static_cast(action); + event.Handler = LockActionEventHandler; + PostEvent(&event); +} + +void AppTask::PostEvent(const AppEvent * event) +{ + if (sAppEventQueue != NULL) + { + if (!xQueueSend(sAppEventQueue, event, 1)) + { + ASR_LOG("Failed to post event to app task event queue"); + } + } +} + +void AppTask::DispatchEvent(AppEvent * event) +{ + if (event->Handler) + { + event->Handler(event); + } + else + { + ASR_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateCluster(intptr_t context) +{ + uint8_t unlocked = BoltLockMgr().IsUnlocked(); + + DlLockState newState = unlocked ? DlLockState::kUnlocked : DlLockState::kLocked; + + OperationSourceEnum source = OperationSourceEnum::kUnspecified; + // write the new lock value + EmberAfStatus status = + DoorLockServer::Instance().SetLockState(1, newState, source) ? EMBER_ZCL_STATUS_SUCCESS : EMBER_ZCL_STATUS_FAILURE; + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ASR_LOG("ERR: updating lock state %x", status); + } +} + +void AppTask::UpdateClusterState(void) +{ + chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateCluster, reinterpret_cast(nullptr)); +} diff --git a/examples/lock-app/asr/src/BoltLockManager.cpp b/examples/lock-app/asr/src/BoltLockManager.cpp new file mode 100755 index 00000000000000..c52f55dec78377 --- /dev/null +++ b/examples/lock-app/asr/src/BoltLockManager.cpp @@ -0,0 +1,225 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BoltLockManager.h" + +#include "AppConfig.h" +#include "AppTask.h" +#include + +BoltLockManager BoltLockManager::sLock; + +TimerHandle_t sLockTimer; + +CHIP_ERROR BoltLockManager::Init() +{ + // Create FreeRTOS sw timer for lock timer. + sLockTimer = xTimerCreate("lockTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = lock obj context + TimerEventHandler // timer callback handler + ); + + if (sLockTimer == NULL) + { + ASR_LOG("sLockTimer timer create failed"); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + + mState = State::kUnlockingCompleted; + mAutoLockTimerArmed = false; + mAutoRelock = false; + mAutoLockDuration = 0; + + return CHIP_NO_ERROR; +} + +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 == State::kLockingInitiated || mState == State::kUnlockingInitiated); +} + +bool BoltLockManager::IsUnlocked() +{ + return (mState == State::kUnlockingCompleted); +} + +void BoltLockManager::EnableAutoRelock(bool aOn) +{ + mAutoRelock = aOn; +} + +void BoltLockManager::SetAutoLockDuration(uint32_t aDurationInSecs) +{ + mAutoLockDuration = aDurationInSecs; +} + +bool BoltLockManager::InitiateAction(int32_t aActor, Action aAction) +{ + bool action_initiated = false; + State new_state; + + // Initiate Lock/Unlock Action only when the previous one is complete. + if (mState == State::kLockingCompleted && aAction == Action::kUnlock) + { + action_initiated = true; + + new_state = State::kUnlockingInitiated; + } + else if (mState == State::kUnlockingCompleted && aAction == Action::kLock) + { + action_initiated = true; + + new_state = State::kLockingInitiated; + } + + if (action_initiated) + { + if (mAutoLockTimerArmed && new_state == State::kLockingInitiated) + { + // If auto lock timer has been armed and someone initiates locking, + // cancel the timer and continue as normal. + mAutoLockTimerArmed = false; + + CancelTimer(); + } + + StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); + + // Since the timer started successfully, update the state and trigger callback + mState = new_state; + + if (mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor); + } + } + + return action_initiated; +} + +void BoltLockManager::StartTimer(uint32_t aTimeoutMs) +{ + if (xTimerIsTimerActive(sLockTimer)) + { + ASR_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sLockTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS) + { + ASR_LOG("sLockTimer timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void BoltLockManager::CancelTimer(void) +{ + if (xTimerStop(sLockTimer, 0) == pdFAIL) + { + ASR_LOG("Lock timer timer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } +} + +void BoltLockManager::TimerEventHandler(TimerHandle_t xTimer) +{ + // Get lock obj context from timer id. + BoltLockManager * lock = static_cast(pvTimerGetTimerID(xTimer)); + + // The timer event handler will be called in the context of the timer task + // once sLockTimer expires. Post an event to apptask queue with the actual handler + // so that the event can be handled in the context of the apptask. + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = lock; + if (lock->mAutoLockTimerArmed) + { + event.Handler = AutoReLockTimerEventHandler; + } + else + { + event.Handler = ActuatorMovementTimerEventHandler; + } + GetAppTask().PostEvent(&event); +} + +void BoltLockManager::AutoReLockTimerEventHandler(AppEvent * aEvent) +{ + BoltLockManager * lock = static_cast(aEvent->TimerEvent.Context); + int32_t actor = 0; + + // Make sure auto lock timer is still armed. + if (!lock->mAutoLockTimerArmed) + { + return; + } + + lock->mAutoLockTimerArmed = false; + + ASR_LOG("Auto Re-Lock has been triggered!"); + + lock->InitiateAction(actor, Action::kLock); +} + +void BoltLockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) +{ + Action actionCompleted = Action::KInvalid; + + BoltLockManager * lock = static_cast(aEvent->TimerEvent.Context); + + if (lock->mState == State::kLockingInitiated) + { + lock->mState = State::kLockingCompleted; + actionCompleted = Action::kLock; + } + else if (lock->mState == State::kUnlockingInitiated) + { + lock->mState = State::kUnlockingCompleted; + actionCompleted = Action::kUnlock; + } + + if (actionCompleted != Action::KInvalid) + { + if (lock->mActionCompleted_CB) + { + lock->mActionCompleted_CB(actionCompleted); + } + + if (lock->mAutoRelock && actionCompleted == Action::kUnlock) + { + // Start the timer for auto relock + lock->StartTimer(lock->mAutoLockDuration * 1000); + + lock->mAutoLockTimerArmed = true; + + ASR_LOG("Auto Re-lock enabled. Will be triggered in %lu seconds", lock->mAutoLockDuration); + } + } +} diff --git a/examples/lock-app/asr/src/ButtonHandler.cpp b/examples/lock-app/asr/src/ButtonHandler.cpp new file mode 100644 index 00000000000000..b74f1befd4652d --- /dev/null +++ b/examples/lock-app/asr/src/ButtonHandler.cpp @@ -0,0 +1,100 @@ +/* + * + * 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 "ButtonHandler.h" +#include "AppConfig.h" +#include "AppTask.h" + +namespace { +constexpr int kButtonCount = 2; + +TimerHandle_t buttonTimers[kButtonCount]; // FreeRTOS timers used for debouncing +// buttons. Array to hold handles to +// the created timers. + +} // namespace + +void ButtonHandler::Init(void) +{ + GpioInit(); + // Create FreeRTOS sw timers for debouncing buttons. + for (uint8_t i = 0; i < kButtonCount; i++) + { + buttonTimers[i] = xTimerCreate("BtnTmr", // Just a text name, not used by the RTOS kernel + APP_BUTTON_DEBOUNCE_PERIOD_MS, // timer period + false, // no timer reload (==one-shot) + (void *) (int) i, // init timer id = button index + TimerCallback // timer callback handler (all buttons use + // the same timer cn function) + ); + } +} + +// port pin +duet_gpio_dev_t lock_btn; +duet_gpio_dev_t func_btn; + +void ButtonHandler::GpioInit(void) +{ + // lock button + lock_btn.port = APP_LOCK_BUTTON; + lock_btn.config = DUET_INPUT_PULL_UP; + lock_btn.priv = NULL; + duet_gpio_init(&lock_btn); + duet_gpio_enable_irq(&lock_btn, DUET_IRQ_TRIGGER_FALLING_EDGE, lockbuttonIsr, NULL); + + // function button + func_btn.port = APP_FUNCTION_BUTTON; + func_btn.config = DUET_INPUT_PULL_UP; + func_btn.priv = NULL; + duet_gpio_init(&func_btn); + duet_gpio_enable_irq(&func_btn, DUET_IRQ_TRIGGER_FALLING_EDGE, functionbuttonIsr, NULL); +} + +void ButtonHandler::lockbuttonIsr(void * handler_arg) +{ + portBASE_TYPE taskWoken = pdFALSE; + xTimerStartFromISR(buttonTimers[APP_LOCK_BUTTON_IDX], &taskWoken); +} + +void ButtonHandler::functionbuttonIsr(void * handler_arg) +{ + portBASE_TYPE taskWoken = pdFALSE; + xTimerStartFromISR(buttonTimers[APP_FUNCTION_BUTTON_IDX], &taskWoken); +} + +void ButtonHandler::TimerCallback(TimerHandle_t xTimer) +{ + // Get the button index of the expired timer and call button event helper. + uint32_t timerId; + uint8_t buttonevent = 0; + uint32_t btnValue; + + timerId = (uint32_t) pvTimerGetTimerID(xTimer); + if (timerId == APP_LOCK_BUTTON_IDX) + { + duet_gpio_input_get(&lock_btn, &btnValue); + buttonevent = (uint8_t) btnValue; + } + else + { + duet_gpio_input_get(&func_btn, &btnValue); + buttonevent = (uint8_t) btnValue; + } + GetAppTask().ButtonEventHandler(timerId, (buttonevent) ? APP_BUTTON_PRESSED : APP_BUTTON_RELEASED); +} diff --git a/examples/lock-app/asr/src/DeviceCallbacks.cpp b/examples/lock-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..8782f038f29677 --- /dev/null +++ b/examples/lock-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,162 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" + +#include "AppTask.h" +#include "BoltLockManager.h" +#include "CHIPDeviceManager.h" +#include "LEDWidget.h" +#include "init_OTARequestor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; +using namespace ::chip::app::Clusters; + +uint32_t identifyTimerCount; +constexpr uint32_t kIdentifyTimerDelayMS = 250; +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + ChipLogProgress(DeviceLayer, + "MatterPostAttributeChangeCallback - Cluster ID: " ChipLogFormatMEI + ", EndPoint ID: '0x%02x', Attribute ID: " ChipLogFormatMEI, + ChipLogValueMEI(clusterId), endpointId, ChipLogValueMEI(attributeId)); + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { + BoltLockMgr().InitiateAction(AppEvent::kEventType_Lock, + *value ? BoltLockManager::Action::kLock : BoltLockManager::Action::kUnlock); + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} + +/** @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/asr/src/LEDManager.cpp b/examples/lock-app/asr/src/LEDManager.cpp new file mode 100644 index 00000000000000..c5e140f98487b6 --- /dev/null +++ b/examples/lock-app/asr/src/LEDManager.cpp @@ -0,0 +1,96 @@ +/* + * + * 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. + */ + +#include "LEDManager.h" +#include "AppTask.h" +#include + +#ifdef CFG_PLF_RV32 +#define duet_gpio_init asr_gpio_init +#define duet_gpio_output_low asr_gpio_output_low +#define duet_gpio_output_high asr_gpio_output_high +#define DUET_OUTPUT_PUSH_PULL ASR_OUTPUT_PUSH_PULL +#endif + +void LEDManager::InitGpio(void) {} + +void LEDManager::Init(uint8_t gpioNum) +{ + mLastChangeTimeMS = 0; + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + mGPIONum = gpioNum; + + gpio.port = mGPIONum; + gpio.config = DUET_OUTPUT_PUSH_PULL; + duet_gpio_init(&gpio); +} + +void LEDManager::Invert(void) +{ + Set(!mState); +} + +void LEDManager::Set(bool state) +{ + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + DoSet(state); +} + +void LEDManager::Blink(uint32_t changeRateMS) +{ + Blink(changeRateMS, changeRateMS); +} + +void LEDManager::Blink(uint32_t onTimeMS, uint32_t offTimeMS) +{ + mBlinkOnTimeMS = onTimeMS; + mBlinkOffTimeMS = offTimeMS; + Animate(); +} + +void LEDManager::Animate() +{ + if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) + { + uint64_t nowMS = chip::System::SystemClock().GetMonotonicMilliseconds64().count(); + uint64_t stateDurMS = ((mState) ? mBlinkOnTimeMS : mBlinkOffTimeMS); + uint64_t nextChangeTimeMS = mLastChangeTimeMS + stateDurMS; + + if (nextChangeTimeMS < nowMS) + { + DoSet(!mState); + mLastChangeTimeMS = nowMS; + } + } +} + +void LEDManager::DoSet(bool state) +{ + mState = state; + + if (state) + { + duet_gpio_output_low(&gpio); + } + else + { + duet_gpio_output_high(&gpio); + } +} diff --git a/examples/lock-app/asr/src/main.cpp b/examples/lock-app/asr/src/main.cpp new file mode 100755 index 00000000000000..8dc468f24cb738 --- /dev/null +++ b/examples/lock-app/asr/src/main.cpp @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "AppConfig.h" +#include "init_asrPlatform.h" +#include + +#include "ASRUtils.h" + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/lock-app/asr/third_party/connectedhomeip b/examples/lock-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/lock-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/ota-requestor-app/asr/.gn b/examples/ota-requestor-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/ota-requestor-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/ota-requestor-app/asr/BUILD.gn b/examples/ota-requestor-app/asr/BUILD.gn new file mode 100755 index 00000000000000..93b0b4a0673bec --- /dev/null +++ b/examples/ota-requestor-app/asr/BUILD.gn @@ -0,0 +1,129 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/ota-requestor-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("ota_requestor_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("ota_requestor_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-ota-requestor-example.out" + + sources = [ + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/DeviceCallbacks.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + deps = [ + ":ota_requestor_app_sdk_sources", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/ota-requestor-app/ota-requestor-common", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/src/lib", + "${chip_root}/examples/ota-requestor-app/ota-requestor-common/include", + ] + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + output_dir = root_out_dir +} + +group("asr") { + deps = [ ":ota_requestor_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/ota-requestor-app/asr/README.md b/examples/ota-requestor-app/asr/README.md new file mode 100755 index 00000000000000..d0dcc9f7146554 --- /dev/null +++ b/examples/ota-requestor-app/asr/README.md @@ -0,0 +1,61 @@ +# Matter ASR OTA Requestor Example + +This example demonstrates the Matter OTA Requestor application on ASR platform. + +--- + +- [Matter ASR OTA Requestor Example](#matter-asr-ota-requestor-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Testing the example](#testing-the-example) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-ota-requestor build +``` + +## Testing the example + +- Make OTA image: Taking lighting-app as an example, light project must + compiled before this operation: + + ``` + third_party/asr/asr582x/asr_sdk/tools/otaImage/image_gen_header out/asr-asr582x-lighting/chip-asr-lighting-example.bin flash_remapping + ``` + + After that, `chip-asr-lighting-example.ota.bin` will generated in the + directory `./out/asr-asr582x-lighting/`. + +- Run the Linux OTA Provider with OTA image. + ``` + ./chip-ota-provider-app -f chip-asr-lighting-example.ota.bin + ``` +- OTA Provider commissioning in another Linux terminal. + ``` + ./chip-tool pairing onnetwork 1 20202021 + ``` +- After OTA Provider commissioning is successful, use `chip-tool` to write ACL + for OAT Provider. + ``` + ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null },{"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null }]' 0 + ``` +- Commission ota requestor device with node-id `OTA REQUESTOR APP NODE ID` +- After OTA Requestor commissioning is successful, use `chip-tool` to inform + OTA Provider to send OTA image to OTA Requestor. + ``` + ./chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 0 + ``` diff --git a/examples/ota-requestor-app/asr/args.gni b/examples/ota-requestor-app/asr/args.gni new file mode 100755 index 00000000000000..1f1b199cc87b61 --- /dev/null +++ b/examples/ota-requestor-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":ota_requestor_app_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/ota-requestor-app/asr/build_overrides b/examples/ota-requestor-app/asr/build_overrides new file mode 120000 index 00000000000000..194ee0b812dc3d --- /dev/null +++ b/examples/ota-requestor-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides/ \ No newline at end of file diff --git a/examples/ota-requestor-app/asr/cfg.gni b/examples/ota-requestor-app/asr/cfg.gni new file mode 100755 index 00000000000000..f2d7bfbc1b80fb --- /dev/null +++ b/examples/ota-requestor-app/asr/cfg.gni @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} + +chip_enable_ota_requestor = true diff --git a/examples/ota-requestor-app/asr/include/AppConfig.h b/examples/ota-requestor-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..826ebfd44f3793 --- /dev/null +++ b/examples/ota-requestor-app/asr/include/AppConfig.h @@ -0,0 +1,43 @@ +/* + * + * 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 + +// ---- Lighting Example App Config ---- + +#define MATTER_DEVICE_NAME "ASR-OTA-REQ" +#define APP_TASK_NAME "APP" +#define APP_TASK_STACK_SIZE (1024 * 4) + +#define LIGHT_LED PWM_OUTPUT_CH3 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/ota-requestor-app/asr/include/AppTask.h b/examples/ota-requestor-app/asr/include/AppTask.h new file mode 100644 index 00000000000000..fd7f4d9f058f1d --- /dev/null +++ b/examples/ota-requestor-app/asr/include/AppTask.h @@ -0,0 +1,44 @@ +/* + * + * 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 "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include +#include + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + +private: + friend AppTask & GetAppTask(void); + + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/ota-requestor-app/asr/include/CHIPProjectConfig.h b/examples/ota-requestor-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..9f21f281471076 --- /dev/null +++ b/examples/ota-requestor-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,109 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +/** + * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY + * + * Enables the use of a hard-coded default Chip device id and credentials if no device id + * is found in Chip NV storage. + * + * This option is for testing only and should be disabled in production releases. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 34 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS + * + * Enable recording UTC timestamps. + */ +#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/ota-requestor-app/asr/include/DeviceCallbacks.h b/examples/ota-requestor-app/asr/include/DeviceCallbacks.h new file mode 100644 index 00000000000000..2b5cfe386f8f05 --- /dev/null +++ b/examples/ota-requestor-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + virtual void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value) override; + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); +}; diff --git a/examples/ota-requestor-app/asr/src/AppTask.cpp b/examples/ota-requestor-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..3eb7cd14b69aec --- /dev/null +++ b/examples/ota-requestor-app/asr/src/AppTask.cpp @@ -0,0 +1,103 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDWidget.h" +#include "init_Matter.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +TaskHandle_t sAppTaskHandle; +} // namespace + +LEDWidget lightLED; + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +AppTask AppTask::sAppTask; + +namespace { +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + // Start App task. + xTaskCreate(AppTaskMain, APP_TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + return (sAppTaskHandle == nullptr) ? CHIP_APPLICATION_ERROR(0x02) : CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + ASR_LOG("App Task started"); + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Firmware Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + lightLED.Init(LIGHT_LED); + /* Delete task */ + vTaskDelete(NULL); +} diff --git a/examples/ota-requestor-app/asr/src/DeviceCallbacks.cpp b/examples/ota-requestor-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..a1fa28e413f647 --- /dev/null +++ b/examples/ota-requestor-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,148 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" +#include "AppConfig.h" +#include "CHIPDeviceManager.h" +#include "init_OTARequestor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +using namespace ::chip; +using namespace ::chip::app::Clusters; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceManager; +using namespace ::chip::Logging; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ASR_LOG("IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address. + // Now, init it when we have gotten IPv4 address just for verification. + // It depends on your application! + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ASR_LOG("Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ASR_LOG("IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ASR_LOG("Lost IPv6 connectivity..."); + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + switch (clusterId) + { + case Identify::Id: + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + break; + default: + ChipLogProgress(Zcl, "Unknown cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + break; + } +} diff --git a/examples/ota-requestor-app/asr/src/main.cpp b/examples/ota-requestor-app/asr/src/main.cpp new file mode 100644 index 00000000000000..1dc5a4e0e69a00 --- /dev/null +++ b/examples/ota-requestor-app/asr/src/main.cpp @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppConfig.h" +#include "init_asrPlatform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} + +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/ota-requestor-app/asr/third_party/connectedhomeip b/examples/ota-requestor-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/ota-requestor-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/temperature-measurement-app/asr/.gn b/examples/temperature-measurement-app/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/temperature-measurement-app/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/temperature-measurement-app/asr/BUILD.gn b/examples/temperature-measurement-app/asr/BUILD.gn new file mode 100755 index 00000000000000..6a8e4f76990449 --- /dev/null +++ b/examples/temperature-measurement-app/asr/BUILD.gn @@ -0,0 +1,129 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("//cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/temperature-measurement-app/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("temperature_measurement_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + "ASR_ENABLE_LED1_DISPLAY=0", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("temperature_measurement_app") { + include_dirs = [] + defines = [] + output_name = "chip-asr-temperature-measurment-example.out" + + public_deps = [ + ":temperature_measurement_app_sdk_sources", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/examples/temperature-measurement-app/temperature-measurement-common", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/src/lib", + ] + + sources = [ + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/DeviceCallbacks.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + output_dir = root_out_dir + + if (chip_print_memory_usage) { + ldflags = [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } +} + +group("asr") { + deps = [ ":temperature_measurement_app" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/temperature-measurement-app/asr/README.md b/examples/temperature-measurement-app/asr/README.md new file mode 100755 index 00000000000000..4151259686e80a --- /dev/null +++ b/examples/temperature-measurement-app/asr/README.md @@ -0,0 +1,40 @@ +# Matter ASR Temperature Measurement Example + +The ASR Temperature Measurement Example demonstrates getting simulated data from +temperature sensor. + +--- + +- [Matter ASR Temperature Measurement Example](#matter-asr-temperature-measurement-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Cluster Control](#cluster-control) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-temperature-measurement build +``` + +## Cluster Control + +After successful commissioning, use `chip-tool` to control the board + +For example,read temperature sensor measured value: + +``` +./chip-tool temperaturemeasurement read measured-value 1 +``` diff --git a/examples/temperature-measurement-app/asr/args.gni b/examples/temperature-measurement-app/asr/args.gni new file mode 100755 index 00000000000000..2156d7904ec9f6 --- /dev/null +++ b/examples/temperature-measurement-app/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = get_label_info(":temperature_measurement_app_sdk_sources", + "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/temperature-measurement-app/asr/build_overrides b/examples/temperature-measurement-app/asr/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/temperature-measurement-app/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/temperature-measurement-app/asr/cfg.gni b/examples/temperature-measurement-app/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/temperature-measurement-app/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/temperature-measurement-app/asr/include/AppConfig.h b/examples/temperature-measurement-app/asr/include/AppConfig.h new file mode 100644 index 00000000000000..4955ee049d07ad --- /dev/null +++ b/examples/temperature-measurement-app/asr/include/AppConfig.h @@ -0,0 +1,79 @@ +/* + * + * 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 + +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#include "asr_pinmux.h" +#define duet_gpio_dev_t asr_gpio_dev_t +#else +#include "duet_gpio.h" +#include "duet_pinmux.h" +#endif +// ---- Lock Example App Config ---- + +#define APP_TASK_NAME "APP" + +#define APP_TASK_STACK_SIZE (1024 * 4) + +#define MATTER_DEVICE_NAME "ASR-Temperature" + +#define APP_LOCK_BUTTON_IDX 0 +#define APP_FUNCTION_BUTTON_IDX 1 + +#define APP_LOCK_BUTTON GPIO10_INDEX +#define APP_FUNCTION_BUTTON GPIO11_INDEX + +#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50 + +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 + +#define SYSTEM_STATE_LED GPIO12_INDEX +#define LOCK_STATE_LED GPIO13_INDEX + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ---- Lock Example SWU Config ---- +#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours +#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours + +// ---- Thread Polling Config ---- +#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 +#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#define CONFIG_RENDEZVOUS_MODE 6 + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/temperature-measurement-app/asr/include/AppEvent.h b/examples/temperature-measurement-app/asr/include/AppEvent.h new file mode 100755 index 00000000000000..7b954c05230f1d --- /dev/null +++ b/examples/temperature-measurement-app/asr/include/AppEvent.h @@ -0,0 +1,57 @@ +/* + * + * 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 + { + uint8_t ButtonIdx; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LockEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/temperature-measurement-app/asr/include/AppTask.h b/examples/temperature-measurement-app/asr/include/AppTask.h new file mode 100755 index 00000000000000..97d1bfe538fb64 --- /dev/null +++ b/examples/temperature-measurement-app/asr/include/AppTask.h @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + static void LightActionEventHandler(AppEvent * aEvent); + void ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction); + void PostEvent(const AppEvent * event); + /** + * Use internally for registration of the ChipDeviceEvents + */ + static void CommonDeviceEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static AppTask sAppTask; + void DispatchEvent(AppEvent * event); + static void OnOffUpdateClusterState(void); +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/temperature-measurement-app/asr/include/CHIPProjectConfig.h b/examples/temperature-measurement-app/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..00af1a3364eb3e --- /dev/null +++ b/examples/temperature-measurement-app/asr/include/CHIPProjectConfig.h @@ -0,0 +1,109 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +/** + * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY + * + * Enables the use of a hard-coded default Chip device id and credentials if no device id + * is found in Chip NV storage. + * + * This option is for testing only and should be disabled in production releases. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 37 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +// #define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/temperature-measurement-app/asr/include/DeviceCallbacks.h b/examples/temperature-measurement-app/asr/include/DeviceCallbacks.h new file mode 100644 index 00000000000000..dccb1bef2c0f7d --- /dev/null +++ b/examples/temperature-measurement-app/asr/include/DeviceCallbacks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + virtual void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value); + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); +}; diff --git a/examples/temperature-measurement-app/asr/src/AppTask.cpp b/examples/temperature-measurement-app/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..bdb37a20e6c7fd --- /dev/null +++ b/examples/temperature-measurement-app/asr/src/AppTask.cpp @@ -0,0 +1,104 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDWidget.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "init_Matter.h" + +namespace { +TaskHandle_t sAppTaskHandle; +} // namespace + +LEDWidget lightLED; + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +AppTask AppTask::sAppTask; + +namespace { +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +static DeviceCallbacks EchoCallbacks; + +CHIP_ERROR AppTask::StartAppTask() +{ + // Start App task. + xTaskCreate(AppTaskMain, APP_TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + return (sAppTaskHandle == nullptr) ? CHIP_APPLICATION_ERROR(0x02) : CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + ASR_LOG("App Task started"); + + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Firmware Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + /* Delete task */ + vTaskDelete(NULL); +} diff --git a/examples/temperature-measurement-app/asr/src/DeviceCallbacks.cpp b/examples/temperature-measurement-app/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..0ecafc10a5eb6c --- /dev/null +++ b/examples/temperature-measurement-app/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,143 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" +#include "AppConfig.h" + +#include +#include + +#include "init_OTARequestor.h" +#include +#include +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +constexpr uint32_t kReportDelaySec = 3; + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + ChipLogProgress(DeviceLayer, + "PostAttributeChangeCallback - Cluster ID: " ChipLogFormatMEI + ", EndPoint ID: '0x%02x', Attribute ID: " ChipLogFormatMEI, + ChipLogValueMEI(clusterId), endpointId, ChipLogValueMEI(attributeId)); +} + +void TempMeas(System::Layer * systemLayer, void * appState) +{ + + int16_t temperature = 2550; + int16_t humidity = 5000; + + ASR_LOG("Sensor T:%d H:%d", temperature, humidity); + + chip::app::Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Set( + /* endpoint ID */ 1, /* temperature in 0.01*C */ int16_t(temperature)); + + // chip::app::Clusters::RelativeHumidityMeasurement::Attributes::MeasuredValue::Set( + // /* endpoint ID */ 1, /* humidity in 0.01*C */ int16_t(humidity)); + + systemLayer->StartTimer(Clock::Seconds32(kReportDelaySec), TempMeas, nullptr); +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kReportDelaySec), TempMeas, nullptr); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} diff --git a/examples/temperature-measurement-app/asr/src/main.cpp b/examples/temperature-measurement-app/asr/src/main.cpp new file mode 100755 index 00000000000000..8dc468f24cb738 --- /dev/null +++ b/examples/temperature-measurement-app/asr/src/main.cpp @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "AppConfig.h" +#include "init_asrPlatform.h" +#include + +#include "ASRUtils.h" + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/temperature-measurement-app/asr/third_party/connectedhomeip b/examples/temperature-measurement-app/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/temperature-measurement-app/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/thermostat/asr/.gn b/examples/thermostat/asr/.gn new file mode 100755 index 00000000000000..8d75f1eafcdb89 --- /dev/null +++ b/examples/thermostat/asr/.gn @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/thermostat/asr/BUILD.gn b/examples/thermostat/asr/BUILD.gn new file mode 100755 index 00000000000000..cc972b5b162163 --- /dev/null +++ b/examples/thermostat/asr/BUILD.gn @@ -0,0 +1,132 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/asr.gni") +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("${asr_sdk_build_root}/asr_sdk.gni") +import("${build_root}/config/defaults.gni") +import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/platform/device.gni") +import("${chip_root}/third_party/asr/asr_executable.gni") + +import("//cfg.gni") + +assert(current_os == "freertos") + +asr_project_dir = "${chip_root}/examples/thermostat/asr" +examples_plat_dir = "${chip_root}/examples/platform/asr" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false +} + +asr_sdk_sources("thermostat_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/ASR", + "${asr_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "ASR_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", + "ASR_ENABLE_LED1_DISPLAY=0", + "ASR_ENABLE_LED2_DISPLAY=0", + ] + + if (chip_enable_factory_data) { + defines += [ + "CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER=1", + "CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER=1", + ] + } + + if (chip_lwip_ip6_hook) { + defines += [ + "CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT", + "CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT", + ] + } + + sources = [ "${asr_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${asr_sdk_build_root}:asr_sdk_config" ] +} + +asr_executable("thermostat") { + include_dirs = [] + defines = [] + output_name = "chip-asr-thermostat-example.out" + + public_deps = [ + ":thermostat_sdk_sources", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/providers:device_info_provider", + "${chip_root}/examples/thermostat/thermostat-common", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${asr_project_dir}/include", + "${chip_root}/src/lib", + ] + + sources = [ + "${examples_plat_dir}/CHIPDeviceManager.cpp", + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_Matter.cpp", + "${examples_plat_dir}/init_asrPlatform.cpp", + "${examples_plat_dir}/shell/matter_shell.cpp", + "src/AppTask.cpp", + "src/DeviceCallbacks.cpp", + "src/SensorManager.cpp", + "src/TemperatureManager.cpp", + "src/main.cpp", + ] + + if (chip_enable_ota_requestor) { + sources += [ "${examples_plat_dir}/init_OTARequestor.cpp" ] + } + + defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] + + if (chip_build_libshell) { + defines += [ "CONFIG_ENABLE_CHIP_SHELL=1" ] + sources += [ "${examples_plat_dir}/shell/launch_shell.cpp" ] + include_dirs += [ "${examples_plat_dir}/shell" ] + } + + output_dir = root_out_dir + + if (chip_print_memory_usage) { + ldflags = [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } +} + +group("asr") { + deps = [ ":thermostat" ] +} + +group("default") { + deps = [ ":asr" ] +} diff --git a/examples/thermostat/asr/README.md b/examples/thermostat/asr/README.md new file mode 100755 index 00000000000000..f582c1b97e045e --- /dev/null +++ b/examples/thermostat/asr/README.md @@ -0,0 +1,52 @@ +# Matter ASR Thermostat Example + +The ASR Thermostat Example demonstrates controlling a thermostat and getting +temperature from local sensor. + +--- + +- [Matter ASR Thermostat Example](#matter-asr-thermostat-example) + - [Supported Chips](#supported-chips) + - [Building and Commissioning](#building-and-commissioning) + - [Cluster Control](#cluster-control) + +--- + +## Supported Chips + +The Matter demo application is supported on: + +- ASR582X +- ASR595X + +## Building and Commissioning + +Please refer +[Building and Commissioning](../../../docs/guides/asr_getting_started_guide.md#building-the-example-application) +guides to get started + +``` +./scripts/build/build_examples.py --target asr-$ASR_BOARD-thermostat build +``` + +## Cluster Control + +After successful commissioning, use `chip-tool` to control the board + +For example,read local-temperature value: + +``` +./chip-tool thermostat read local-temperature 1 +``` + +increases the temperature by sending a SetpointRaiseLower command: + +``` +./chip-tool thermostat setpoint-raise-lower 0 10 1 +``` + +decreases the temperature by sending a SetpointRaiseLower command: + +``` +./chip-tool thermostat setpoint-raise-lower 0 -10 1 +``` diff --git a/examples/thermostat/asr/args.gni b/examples/thermostat/asr/args.gni new file mode 100755 index 00000000000000..89f03298f4490a --- /dev/null +++ b/examples/thermostat/asr/args.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("//cfg.gni") +import("${chip_root}/src/platform/ASR/args.gni") + +asr_target_project = + get_label_info(":thermostat_sdk_sources", "label_no_toolchain") + +declare_args() { + # Disable lock tracking, since our FreeRTOS configuration does not set + # INCLUDE_xSemaphoreGetMutexHolder + chip_stack_lock_tracking = "none" +} diff --git a/examples/thermostat/asr/build_overrides b/examples/thermostat/asr/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/thermostat/asr/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/thermostat/asr/cfg.gni b/examples/thermostat/asr/cfg.gni new file mode 100755 index 00000000000000..15fe50e79efb6d --- /dev/null +++ b/examples/thermostat/asr/cfg.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +declare_args() { + chip_enable_factory_data = false + + chip_lwip_ip6_hook = false + + setupPinCode = 20202021 + + setupDiscriminator = 3840 +} diff --git a/examples/thermostat/asr/include/AppConfig.h b/examples/thermostat/asr/include/AppConfig.h new file mode 100644 index 00000000000000..86c67695c016bc --- /dev/null +++ b/examples/thermostat/asr/include/AppConfig.h @@ -0,0 +1,81 @@ +/* + * + * 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 + +#ifdef CFG_PLF_RV32 +#include "asr_gpio.h" +#include "asr_pinmux.h" +#define duet_gpio_dev_t asr_gpio_dev_t +#else +#include "duet_gpio.h" +#include "duet_pinmux.h" +#endif + +// ---- Lock Example App Config ---- + +#define APP_TASK_NAME "APP" + +#define APP_EVENT_QUEUE_SIZE 10 +#define APP_TASK_STACK_SIZE (1024 * 4) + +#define MATTER_DEVICE_NAME "ASR-Thermostat" + +#define APP_LOCK_BUTTON_IDX 0 +#define APP_FUNCTION_BUTTON_IDX 1 + +#define APP_LOCK_BUTTON GPIO10_INDEX +#define APP_FUNCTION_BUTTON GPIO11_INDEX + +#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50 + +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 + +#define SYSTEM_STATE_LED GPIO12_INDEX +#define LOCK_STATE_LED GPIO13_INDEX + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ---- Lock Example SWU Config ---- +#define SWU_INTERVAl_WINDOW_MIN_MS (23 * 60 * 60 * 1000) // 23 hours +#define SWU_INTERVAl_WINDOW_MAX_MS (24 * 60 * 60 * 1000) // 24 hours + +// ---- Thread Polling Config ---- +#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 +#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 + +// ASR Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void ASR_LOG(const char * aFormat, ...); + +#ifdef __cplusplus +} + +#define CONFIG_RENDEZVOUS_MODE 6 + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/thermostat/asr/include/AppEvent.h b/examples/thermostat/asr/include/AppEvent.h new file mode 100755 index 00000000000000..36a2593cd3263c --- /dev/null +++ b/examples/thermostat/asr/include/AppEvent.h @@ -0,0 +1,71 @@ +/* + * + * 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_UpdateLedState, + kEventType_IdentifyStart, + kEventType_IdentifyStop, + kEventType_Lighting, + kEventType_Thermostat, + kEventType_Install, + kEventType_Contact, + kEventType_Start, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LightingEvent; + struct + { + uint8_t Action; + } ContactEvent; + struct + { + uint8_t Action; + int32_t Actor; + } StartEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/thermostat/asr/include/AppTask.h b/examples/thermostat/asr/include/AppTask.h new file mode 100644 index 00000000000000..90a8ac65adff46 --- /dev/null +++ b/examples/thermostat/asr/include/AppTask.h @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2021 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. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" +#include "FreeRTOS.h" +#include "SensorManager.h" +#include "TemperatureManager.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +#include +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + static void LightActionEventHandler(AppEvent * aEvent); + void ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction); + void PostEvent(const AppEvent * event); + /** + * Use internally for registration of the ChipDeviceEvents + */ + static void CommonDeviceEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void UpdateClusterState(void); + void UpdateThermoStatUI(void); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static AppTask sAppTask; + void DispatchEvent(AppEvent * event); + static void OnOffUpdateClusterState(void); +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/thermostat/asr/include/BindingHandler.h b/examples/thermostat/asr/include/BindingHandler.h new file mode 100644 index 00000000000000..50874b67c04421 --- /dev/null +++ b/examples/thermostat/asr/include/BindingHandler.h @@ -0,0 +1,54 @@ +/* + * + * 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 "app-common/zap-generated/ids/Attributes.h" +#include "app-common/zap-generated/ids/Clusters.h" +#include "app-common/zap-generated/ids/Commands.h" +#include "lib/core/CHIPError.h" +#include +#include +#include +#include + +class BindingHandler +{ +public: + static void Init(); + static void ThermostatNotifyFunction(intptr_t); + static void PrintBindingTable(); + static bool IsGroupBound(); + + struct BindingData + { + chip::EndpointId EndpointId; + chip::CommandId CommandId; + chip::ClusterId ClusterId; + chip::AttributeId AttributeId; + uint8_t Value; + bool IsGroup{ false }; + }; + + static void SubscribeHumidityAttribute(chip::AttributeId attributeId, chip::DeviceProxy * peer_device, void * context); + +private: + static void ReadTemperatureAttribute(chip::AttributeId, const EmberBindingTableEntry &, chip::DeviceProxy *, void *); + static void ReadHumidityAttribute(chip::AttributeId, const EmberBindingTableEntry &, chip::DeviceProxy *, void *); + static void ThermostatChangedHandler(const EmberBindingTableEntry &, chip::OperationalDeviceProxy *, void *); + static void ThermostatContextReleaseHandler(void *); + static void InitInternal(intptr_t); +}; diff --git a/examples/thermostat/asr/include/CHIPClusters.h b/examples/thermostat/asr/include/CHIPClusters.h new file mode 100644 index 00000000000000..e3b7157126b8c8 --- /dev/null +++ b/examples/thermostat/asr/include/CHIPClusters.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Prevent multiple inclusion +#pragma once + +#include +#include + +#include +#include +#include + +namespace chip { +namespace Controller { + +class DLL_EXPORT IdentifyCluster : public ClusterBase +{ +public: + IdentifyCluster(Messaging::ExchangeManager & exchangeManager, const SessionHandle & session, EndpointId endpoint) : + ClusterBase(exchangeManager, session, endpoint) + {} + ~IdentifyCluster() {} +}; + +class DLL_EXPORT DescriptorCluster : public ClusterBase +{ +public: + DescriptorCluster(Messaging::ExchangeManager & exchangeManager, const SessionHandle & session, EndpointId endpoint) : + ClusterBase(exchangeManager, session, endpoint) + {} + ~DescriptorCluster() {} +}; + +class DLL_EXPORT OtaSoftwareUpdateProviderCluster : public ClusterBase +{ +public: + OtaSoftwareUpdateProviderCluster(Messaging::ExchangeManager & exchangeManager, const SessionHandle & session, + EndpointId endpoint) : + ClusterBase(exchangeManager, session, endpoint) + {} + ~OtaSoftwareUpdateProviderCluster() {} +}; + +class DLL_EXPORT TemperatureMeasurementCluster : public ClusterBase +{ +public: + TemperatureMeasurementCluster(Messaging::ExchangeManager & exchangeManager, const SessionHandle & session, + EndpointId endpoint) : + ClusterBase(exchangeManager, session, endpoint) + {} + ~TemperatureMeasurementCluster() {} +}; + +class DLL_EXPORT RelativeHumidityMeasurementCluster : public ClusterBase +{ +public: + RelativeHumidityMeasurementCluster(Messaging::ExchangeManager & exchangeManager, const SessionHandle & session, + EndpointId endpoint) : + ClusterBase(exchangeManager, session, endpoint) + {} + ~RelativeHumidityMeasurementCluster() {} +}; + +} // namespace Controller +} // namespace chip diff --git a/examples/thermostat/asr/include/CHIPProjectConfig.h b/examples/thermostat/asr/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..00af1a3364eb3e --- /dev/null +++ b/examples/thermostat/asr/include/CHIPProjectConfig.h @@ -0,0 +1,109 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +/** + * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY + * + * Enables the use of a hard-coded default Chip device id and credentials if no device id + * is found in Chip NV storage. + * + * This option is for testing only and should be disabled in production releases. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 37 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * + * A string identifying the software version running on the device. + * CHIP service currently expects the software version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0" +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + * + * A uint32_t identifying the software version running on the device. + */ +/* The SoftwareVersion attribute of the Basic cluster. */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +// #define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/thermostat/asr/include/DeviceCallbacks.h b/examples/thermostat/asr/include/DeviceCallbacks.h new file mode 100644 index 00000000000000..dccb1bef2c0f7d --- /dev/null +++ b/examples/thermostat/asr/include/DeviceCallbacks.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.h + * + * Implementations for the DeviceManager callbacks for this application + * + **/ + +#pragma once + +#include "CHIPDeviceManager.h" +#include +#include +#include + +class DeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallbacks +{ +public: + virtual void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void PostAttributeChangeCallback(chip::EndpointId endpointId, chip::ClusterId clusterId, chip::AttributeId attributeId, + uint8_t type, uint16_t size, uint8_t * value); + +private: + void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); +}; diff --git a/examples/thermostat/asr/include/SensorManager.h b/examples/thermostat/asr/include/SensorManager.h new file mode 100644 index 00000000000000..76095c30259e78 --- /dev/null +++ b/examples/thermostat/asr/include/SensorManager.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppEvent.h" +#include "lega_at_api.h" +#include +#include +#include +#include + +class SensorManager +{ +public: + CHIP_ERROR Init(); + +private: + friend SensorManager & SensorMgr(); + + // Reads new generated sensor value, stores it, and updates local temperature attribute + static void TimerEventHandler(lega_timer_t * timer); + static void SensorTimerEventHandler(AppEvent * aEvent); + + static SensorManager sSensorManager; +}; + +inline SensorManager & SensorMgr() +{ + return SensorManager::sSensorManager; +} diff --git a/examples/thermostat/asr/include/TemperatureManager.h b/examples/thermostat/asr/include/TemperatureManager.h new file mode 100755 index 00000000000000..e19a4fcf248057 --- /dev/null +++ b/examples/thermostat/asr/include/TemperatureManager.h @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include + +using namespace chip; + +// AppCluster Spec Table 85. +enum ThermMode +{ + OFF = 0, + AUTO, + NOT_USED, + COOL, + HEAT, +}; + +class TemperatureManager +{ +public: + CHIP_ERROR Init(); + void AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size); + uint8_t GetMode(); + int8_t GetCurrentTemp(); + int8_t GetHeatingSetPoint(); + int8_t GetCoolingSetPoint(); + +private: + friend TemperatureManager & TempMgr(); + + int8_t mCurrentTempCelsius; + int8_t mCoolingCelsiusSetPoint; + int8_t mHeatingCelsiusSetPoint; + uint8_t mThermMode; + + int8_t ConvertToPrintableTemp(int16_t temperature); + static TemperatureManager sTempMgr; +}; + +inline TemperatureManager & TempMgr() +{ + return TemperatureManager::sTempMgr; +} diff --git a/examples/thermostat/asr/src/AppTask.cpp b/examples/thermostat/asr/src/AppTask.cpp new file mode 100644 index 00000000000000..544c3c42108be2 --- /dev/null +++ b/examples/thermostat/asr/src/AppTask.cpp @@ -0,0 +1,176 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "CHIPDeviceManager.h" +#include "DeviceCallbacks.h" +#include "LEDWidget.h" +#include "init_Matter.h" +#include "qrcodegen.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; +using namespace ::chip::System; + +namespace { +TaskHandle_t sAppTaskHandle; +QueueHandle_t sAppEventQueue; + +constexpr EndpointId kThermostatEndpointId = 1; +} // namespace + +namespace { +constexpr EndpointId kNetworkCommissioningEndpointMain = 0; +constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; + +app::Clusters::NetworkCommissioning::Instance + sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, + &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); +} // namespace + +void NetWorkCommissioningInstInit() +{ + sWiFiNetworkCommissioningInstance.Init(); + + // We only have network commissioning on endpoint 0. + emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); +} + +AppTask AppTask::sAppTask; +static DeviceCallbacks EchoCallbacks; +LEDWidget lightLED; + +CHIP_ERROR AppTask::StartAppTask() +{ + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + ASR_LOG("Failed to allocate app event queue"); + appError(APP_ERROR_EVENT_QUEUE_FAILED); + } + // Start App task. + xTaskCreate(AppTaskMain, APP_TASK_NAME, APP_TASK_STACK_SIZE, 0, 2, &sAppTaskHandle); + return (sAppTaskHandle == nullptr) ? CHIP_APPLICATION_ERROR(0x02) : CHIP_NO_ERROR; +} + +CHIP_ERROR AppTask::Init() +{ + if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); + + if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR) + appError(CHIP_ERROR_INTERNAL); + + NetWorkCommissioningInstInit(); + + ASR_LOG("Current Firmware Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + CHIP_ERROR err; + err = SensorMgr().Init(); + if (err != CHIP_NO_ERROR) + { + ASR_LOG("SensorMgr Init fail"); + appError(err); + } + err = TempMgr().Init(); + if (err != CHIP_NO_ERROR) + { + ASR_LOG("TempMgr Init fail"); + appError(err); + } + + return CHIP_NO_ERROR; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + + AppEvent event; + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + ASR_LOG("AppTask.Init() failed"); + appError(err); + } + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + if (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + } + } + + /* Delete task */ + vTaskDelete(NULL); +} + +void AppTask::UpdateThermoStatUI(void) +{ + ASR_LOG("Thermostat Status - M:%d T:%d'C H:%d'C C:%d'C", TempMgr().GetMode(), TempMgr().GetCurrentTemp(), + TempMgr().GetHeatingSetPoint(), TempMgr().GetCoolingSetPoint()); +} + +void AppTask::UpdateClusterState() {} + +void AppTask::PostEvent(const AppEvent * event) +{ + if (sAppEventQueue != NULL) + { + if (!xQueueSend(sAppEventQueue, event, 1)) + { + ASR_LOG("Failed to post event to app task event queue"); + } + } +} + +void AppTask::DispatchEvent(AppEvent * event) +{ + if (event->Handler) + { + event->Handler(event); + } + else + { + ASR_LOG("Event received with no handler. Dropping event."); + } +} diff --git a/examples/thermostat/asr/src/DeviceCallbacks.cpp b/examples/thermostat/asr/src/DeviceCallbacks.cpp new file mode 100644 index 00000000000000..62f991c7086da9 --- /dev/null +++ b/examples/thermostat/asr/src/DeviceCallbacks.cpp @@ -0,0 +1,130 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file DeviceCallbacks.cpp + * + * Implements all the callbacks to the application from the CHIP Stack + * + **/ +#include "DeviceCallbacks.h" +#include "AppConfig.h" +#include "TemperatureManager.h" +#include +#include + +#include "init_OTARequestor.h" +#include +#include +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +#include "route_hook/asr_route_hook.h" +#endif + +constexpr uint32_t kReportDelaySec = 3; + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::System; +using namespace ::chip::DeviceManager; +using namespace ::chip::DeviceLayer; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +constexpr uint32_t kInitOTARequestorDelaySec = 3; + +void InitOTARequestorHandler(System::Layer * systemLayer, void * appState) +{ + OTAInitializer::Instance().InitOTARequestor(); +} +#endif +void DeviceCallbacks::DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kInternetConnectivityChange: + OnInternetConnectivityChange(event); + break; + + case DeviceEventType::kInterfaceIpAddressChanged: + if ((event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV4_Assigned) || + (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned)) + { + // MDNS server restart on any ip assignment: if link local ipv6 is configured, that + // will not trigger a 'internet connectivity change' as there is no internet + // connectivity. MDNS still wants to refresh its listening interfaces to include the + // newly selected address. + chip::app::DnssdServer::Instance().StartServer(); + + if (event->InterfaceIpAddressChanged.Type == InterfaceIpChangeType::kIpV6_Assigned) + { +#if defined CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT || defined CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT + ChipLogProgress(NotSpecified, "Initializing route hook..."); + asr_route_hook_init(); +#endif + } + } + break; + } +} + +void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, uint8_t type, + uint16_t size, uint8_t * value) +{ + ChipLogProgress(DeviceLayer, + "PostAttributeChangeCallback - Cluster ID: " ChipLogFormatMEI + ", EndPoint ID: '0x%02x', Attribute ID: " ChipLogFormatMEI, + ChipLogValueMEI(clusterId), endpointId, ChipLogValueMEI(attributeId)); + + if (clusterId == chip::app::Clusters::Thermostat::Id) + { + TempMgr().AttributeChangeHandler(endpointId, attributeId, value, size); + } +} + +void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + static bool isOTAInitialized = false; +#endif + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv4 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); + } + else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv4 connectivity..."); + } + if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + ChipLogProgress(DeviceLayer, "IPv6 Server ready..."); + chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Init OTA requestor only when we have gotten IPv6 address + if (!isOTAInitialized) + { + chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(kInitOTARequestorDelaySec), + InitOTARequestorHandler, nullptr); + isOTAInitialized = true; + } +#endif + } + else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) + { + ChipLogProgress(DeviceLayer, "Lost IPv6 connectivity..."); + } +} diff --git a/examples/thermostat/asr/src/SensorManager.cpp b/examples/thermostat/asr/src/SensorManager.cpp new file mode 100644 index 00000000000000..8d2d405e02c768 --- /dev/null +++ b/examples/thermostat/asr/src/SensorManager.cpp @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SensorManager.h" +#include "AppConfig.h" +#include "AppTask.h" +#include "lega_rtos_api.h" + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr EndpointId kThermostatEndpoint = 1; +constexpr uint16_t kSensorTimerPeriodMs = 30000; // 30s timer period +constexpr uint16_t kMinTemperatureDelta = 50; // 0.5 degree Celsius + +lega_timer_t sSensorTimer; + +SensorManager SensorManager::sSensorManager; + +constexpr uint16_t kSimulatedReadingFrequency = (60000 / kSensorTimerPeriodMs); // Change Simulated number at each minutes +static int16_t mSimulatedTemp[] = { 2300, 2400, 2800, 2550, 2200, 2125, 2100, 2600, 1800, 2700 }; + +CHIP_ERROR SensorManager::Init() +{ + // Initialize temp sensor timer + lega_rtos_init_timer(&sSensorTimer, kSensorTimerPeriodMs, (timer_handler_t) &TimerEventHandler, this); + lega_rtos_start_timer(&sSensorTimer); + + return CHIP_NO_ERROR; +} + +void SensorManager::TimerEventHandler(lega_timer_t * timer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Thermostat; + event.TimerEvent.Context = timer->arg; + event.Handler = SensorTimerEventHandler; + GetAppTask().PostEvent(&event); +} + +void SensorManager::SensorTimerEventHandler(AppEvent * aEvent) +{ + int16_t temperature = 0; + static int16_t lastTemperature = 0; + + static uint8_t nbOfRepetition = 0; + static uint8_t simulatedIndex = 0; + if (simulatedIndex >= sizeof(mSimulatedTemp)) + { + simulatedIndex = 0; + } + temperature = mSimulatedTemp[simulatedIndex]; + + nbOfRepetition++; + if (nbOfRepetition >= kSimulatedReadingFrequency) + { + simulatedIndex++; + nbOfRepetition = 0; + } + + ASR_LOG("Sensor Temp is : %d", temperature); + + if ((temperature >= (lastTemperature + kMinTemperatureDelta)) || temperature <= (lastTemperature - kMinTemperatureDelta)) + { + lastTemperature = temperature; + PlatformMgr().LockChipStack(); + app::Clusters::Thermostat::Attributes::LocalTemperature::Set(kThermostatEndpoint, temperature); + PlatformMgr().UnlockChipStack(); + } + + // Start next timer to handle temp sensor. + lega_rtos_start_timer(&sSensorTimer); +} diff --git a/examples/thermostat/asr/src/TemperatureManager.cpp b/examples/thermostat/asr/src/TemperatureManager.cpp new file mode 100644 index 00000000000000..219f428e85e781 --- /dev/null +++ b/examples/thermostat/asr/src/TemperatureManager.cpp @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TemperatureManager.h" +#include "AppConfig.h" +#include "AppTask.h" + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr EndpointId kThermostatEndpoint = 1; + +namespace ThermAttr = chip::app::Clusters::Thermostat::Attributes; + +TemperatureManager TemperatureManager::sTempMgr; + +CHIP_ERROR TemperatureManager::Init() +{ + app::DataModel::Nullable temp; + int16_t heatingSetpoint, coolingSetpoint; + uint8_t systemMode; + + PlatformMgr().LockChipStack(); + ThermAttr::LocalTemperature::Get(kThermostatEndpoint, temp); + ThermAttr::OccupiedCoolingSetpoint::Get(kThermostatEndpoint, &coolingSetpoint); + ThermAttr::OccupiedHeatingSetpoint::Get(kThermostatEndpoint, &heatingSetpoint); + ThermAttr::SystemMode::Get(kThermostatEndpoint, &systemMode); + PlatformMgr().UnlockChipStack(); + + mCurrentTempCelsius = ConvertToPrintableTemp(temp.Value()); + mHeatingCelsiusSetPoint = ConvertToPrintableTemp(coolingSetpoint); + mCoolingCelsiusSetPoint = ConvertToPrintableTemp(heatingSetpoint); + mThermMode = systemMode; + + GetAppTask().UpdateThermoStatUI(); + + return CHIP_NO_ERROR; +} + +int8_t TemperatureManager::ConvertToPrintableTemp(int16_t temperature) +{ + constexpr uint8_t kRoundUpValue = 50; + + // Round up the temperature as we won't print decimals on LCD + // Is it a negative temperature + if (temperature < 0) + { + temperature -= kRoundUpValue; + } + else + { + temperature += kRoundUpValue; + } + + return static_cast(temperature / 100); +} + +void TemperatureManager::AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size) +{ + switch (attributeId) + { + case ThermAttr::LocalTemperature::Id: { + int8_t Temp = ConvertToPrintableTemp(*((int16_t *) value)); + ASR_LOG("Local temp %d", Temp); + mCurrentTempCelsius = Temp; + } + break; + + case ThermAttr::OccupiedCoolingSetpoint::Id: { + int8_t coolingTemp = ConvertToPrintableTemp(*((int16_t *) value)); + ASR_LOG("CoolingSetpoint %d", coolingTemp); + mCoolingCelsiusSetPoint = coolingTemp; + } + break; + + case ThermAttr::OccupiedHeatingSetpoint::Id: { + int8_t heatingTemp = ConvertToPrintableTemp(*((int16_t *) value)); + ASR_LOG("HeatingSetpoint %d", heatingTemp); + mHeatingCelsiusSetPoint = heatingTemp; + } + break; + + case ThermAttr::SystemMode::Id: { + ASR_LOG("SystemMode %d", static_cast(*value)); + uint8_t mode = static_cast(*value); + if (mThermMode != mode) + { + mThermMode = mode; + } + } + break; + + default: { + ASR_LOG("Unhandled thermostat attribute %x", attributeId); + return; + } + break; + } + + GetAppTask().UpdateThermoStatUI(); +} + +uint8_t TemperatureManager::GetMode() +{ + return mThermMode; +} + +int8_t TemperatureManager::GetCurrentTemp() +{ + return mCurrentTempCelsius; +} +int8_t TemperatureManager::GetHeatingSetPoint() +{ + return mHeatingCelsiusSetPoint; +} + +int8_t TemperatureManager::GetCoolingSetPoint() +{ + return mCoolingCelsiusSetPoint; +} diff --git a/examples/thermostat/asr/src/main.cpp b/examples/thermostat/asr/src/main.cpp new file mode 100644 index 00000000000000..eb58449e1caab3 --- /dev/null +++ b/examples/thermostat/asr/src/main.cpp @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "AppConfig.h" +#include "AppTask.h" +#include "init_asrPlatform.h" + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + ASR_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + lega_rtos_declare_critical(); + lega_rtos_enter_critical(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_asrPlatform(); + + CHIP_ERROR ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + ASR_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + ASR_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/thermostat/asr/third_party/connectedhomeip b/examples/thermostat/asr/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/thermostat/asr/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index f573feec814940..279191e45d1bf9 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -418,7 +418,15 @@ def BuildASRTarget(): # apps target.AppendFixedTargets([ + TargetPart('all-clusters', app=ASRApp.ALL_CLUSTERS), + TargetPart('all-clusters-minimal', app=ASRApp.ALL_CLUSTERS_MINIMAL), TargetPart('lighting', app=ASRApp.LIGHT), + TargetPart('light-switch', app=ASRApp.LIGHT_SWITCH), + TargetPart('lock', app=ASRApp.LOCK), + TargetPart('bridge', app=ASRApp.BRIDGE), + TargetPart('temperature-measurement', app=ASRApp.TEMPERATURE_MEASUREMENT), + TargetPart('thermostat', app=ASRApp.THERMOSTAT), + TargetPart('ota-requestor', app=ASRApp.OTA_REQUESTOR), ]) # modifiers diff --git a/scripts/build/builders/asr.py b/scripts/build/builders/asr.py index c329f70e29ddc7..23c9e4294c138a 100644 --- a/scripts/build/builders/asr.py +++ b/scripts/build/builders/asr.py @@ -19,17 +19,57 @@ class ASRApp(Enum): + ALL_CLUSTERS = auto() + ALL_CLUSTERS_MINIMAL = auto() LIGHT = auto() + LIGHT_SWITCH = auto() + LOCK = auto() + BRIDGE = auto() + TEMPERATURE_MEASUREMENT = auto() + THERMOSTAT = auto() + OTA_REQUESTOR = auto() def ExampleName(self): - if self == ASRApp.LIGHT: + if self == ASRApp.ALL_CLUSTERS: + return 'all-clusters-app' + elif self == ASRApp.ALL_CLUSTERS_MINIMAL: + return 'all-clusters-minimal-app' + elif self == ASRApp.LIGHT: return 'lighting-app' + elif self == ASRApp.LIGHT_SWITCH: + return 'light-switch-app' + elif self == ASRApp.LOCK: + return 'lock-app' + elif self == ASRApp.BRIDGE: + return 'bridge-app' + elif self == ASRApp.TEMPERATURE_MEASUREMENT: + return 'temperature-measurement-app' + elif self == ASRApp.THERMOSTAT: + return 'thermostat' + elif self == ASRApp.OTA_REQUESTOR: + return 'ota-requestor-app' else: raise Exception('Unknown app type: %r' % self) def AppNamePrefix(self): - if self == ASRApp.LIGHT: + if self == ASRApp.ALL_CLUSTERS: + return 'chip-asr-all-clusters-app' + elif self == ASRApp.ALL_CLUSTERS_MINIMAL: + return 'chip-asr-all-clusters-minimal-app' + elif self == ASRApp.LIGHT: return 'chip-asr-lighting-app' + elif self == ASRApp.LIGHT_SWITCH: + return 'chip-asr-light-switch-app' + elif self == ASRApp.LOCK: + return 'chip-asr-lock-example' + elif self == ASRApp.BRIDGE: + return 'chip-asr-bridge-example' + elif self == ASRApp.TEMPERATURE_MEASUREMENT: + return 'chip-asr-temperature-measurement-example' + elif self == ASRApp.THERMOSTAT: + return 'chip-asr-thermostat-example' + elif self == ASRApp.OTA_REQUESTOR: + return 'chip-asr-ota-requestor-example' else: raise Exception('Unknown app type: %r' % self) diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index e4f8a8968253f8..1b8c95d4c51c7d 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -1,5 +1,5 @@ ameba-amebad-{all-clusters,all-clusters-minimal,light,light-switch,pigweed} -asr-{asr582x,asr595x}-lighting[-ota][-shell][-no_logging][-factory][-rotating_id] +asr-{asr582x,asr595x}-{all-clusters,all-clusters-minimal,lighting,light-switch,lock,bridge,temperature-measurement,thermostat,ota-requestor}[-ota][-shell][-no_logging][-factory][-rotating_id] android-{arm,arm64,x86,x64,androidstudio-arm,androidstudio-arm64,androidstudio-x86,androidstudio-x64}-{chip-tool,chip-test,tv-server,tv-casting-app,java-matter-controller}[-no-debug] bouffalolab-{bl602-iot-matter-v1,bl602-iot-dvk-3s,bl602-night-light,xt-zb6-devkit,bl706-iot-dvk,bl706-night-light}-light[-shell][-115200][-rpc][-cdc] cc32xx-lock