diff --git a/config/nrfconnect/app/sample-defaults.conf b/config/nrfconnect/app/sample-defaults.conf index 7145c2d7b704c9..22625d175148f1 100644 --- a/config/nrfconnect/app/sample-defaults.conf +++ b/config/nrfconnect/app/sample-defaults.conf @@ -41,9 +41,12 @@ CONFIG_NET_SOCKETS_POSIX_NAMES=n CONFIG_MAIN_STACK_SIZE=8192 CONFIG_INIT_STACKS=y +# Enable Zephyr IPv6 multicast +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=14 +CONFIG_NET_IPV6_MLD=y + # Disable certain parts of Zephyr IPv6 stack CONFIG_NET_IPV6_NBR_CACHE=n -CONFIG_NET_IPV6_MLD=n # Network buffers CONFIG_NET_PKT_RX_COUNT=16 diff --git a/examples/light-switch-app/nrfconnect/.gitignore b/examples/light-switch-app/nrfconnect/.gitignore new file mode 100644 index 00000000000000..84c048a73cc2e5 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/examples/light-switch-app/nrfconnect/CMakeLists.txt b/examples/light-switch-app/nrfconnect/CMakeLists.txt new file mode 100644 index 00000000000000..3610cbfc72b526 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/CMakeLists.txt @@ -0,0 +1,103 @@ +# +# 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. +# + +cmake_minimum_required(VERSION 3.20.0) + +get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH) +get_filename_component(NRFCONNECT_COMMON ${CHIP_ROOT}/examples/platform/nrfconnect REALPATH) +get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH) + +include(${CHIP_ROOT}/config/nrfconnect/app/check-nrfconnect-version.cmake) + +# Load NCS/Zephyr build system +set(CONF_FILE ${CHIP_ROOT}/config/nrfconnect/app/sample-defaults.conf prj.conf) + +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}.conf) + list(APPEND CONF_FILE boards/${BOARD}.conf) +endif() + +set(BUILD_WITH_DFU "MATTER" CACHE STRING "Build target with Device Firmware Upgrade support") + +if(NOT BUILD_WITH_DFU STREQUAL "OFF") + if(BUILD_WITH_DFU STREQUAL "BLE") + if(BOARD STREQUAL "nrf5340dk_nrf5340_cpuapp") + list(INSERT OVERLAY_CONFIG 0 ${CHIP_ROOT}/config/nrfconnect/app/overlay-multi_image_smp_dfu_support.conf) + else() + list(INSERT OVERLAY_CONFIG 0 ${CHIP_ROOT}/config/nrfconnect/app/overlay-single_image_smp_dfu_support.conf) + endif() + elseif(NOT BUILD_WITH_DFU STREQUAL "MATTER") + message(FATAL_ERROR "Selected invalid BUILD_WITH_DFU value: ${BUILD_WITH_DFU}") + endif() + + list(INSERT OVERLAY_CONFIG 0 ${CHIP_ROOT}/config/nrfconnect/app/overlay-mcuboot_qspi_nor_support.conf) + list(INSERT OVERLAY_CONFIG 0 ${CHIP_ROOT}/config/nrfconnect/app/overlay-ota_requestor.conf) + + if(BOARD STREQUAL "nrf5340dk_nrf5340_cpuapp") + # DFU over Matter doesn't support multi-image update yet, but using this configs should not harm it anyway. + set(mcuboot_OVERLAY_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/configuration/mcuboot_multi_image_dfu.conf CACHE INTERNAL "") + else() + set(mcuboot_OVERLAY_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/configuration/mcuboot_single_image_dfu.conf CACHE INTERNAL "") + endif() + + set(PM_STATIC_YML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/configuration/${BOARD}/pm_static.yml) +endif() + +list(APPEND ZEPHYR_EXTRA_MODULES ${CHIP_ROOT}/config/nrfconnect/chip-module) +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) + +# -Wmaybe-uninitialized has too many false positives, including on std::optional +# and chip::Optional. Make it nonfatal. +# +# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635 +target_compile_options(app PRIVATE -Werror -Wno-error=maybe-uninitialized) + +project(chip-nrfconnect-light-switch-example) + +include(${CHIP_ROOT}/config/nrfconnect/app/enable-gnu-std.cmake) +include(${CHIP_ROOT}/config/nrfconnect/app/flashing.cmake) +include(${CHIP_ROOT}/src/app/chip_data_model.cmake) + +target_include_directories(app PRIVATE + main/include + ${GEN_DIR}/app-common + ${GEN_DIR}/light-switch-app + ${NRFCONNECT_COMMON}/util/include + ${NRFCONNECT_COMMON}/app/include) + +target_sources(app PRIVATE + main/AppTask.cpp + main/main.cpp + main/LightSwitch.cpp + main/ShellCommands.cpp + main/BindingHandler.cpp + ${GEN_DIR}/light-switch-app/zap-generated/callback-stub.cpp + ${GEN_DIR}/light-switch-app/zap-generated/IMClusterCommandHandler.cpp + ${NRFCONNECT_COMMON}/util/LEDWidget.cpp + ${NRFCONNECT_COMMON}/util/ThreadUtil.cpp) + + +if(CONFIG_CHIP_OTA_REQUESTOR) + target_sources(app PRIVATE ${NRFCONNECT_COMMON}/util/OTAUtil.cpp) +endif() + +if(BUILD_WITH_DFU STREQUAL "BLE") + target_sources(app PRIVATE ${NRFCONNECT_COMMON}/util/DFUOverSMP.cpp) +endif() + +chip_configure_data_model(app + INCLUDE_SERVER + ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../light-switch-common/light-switch-app.zap +) diff --git a/examples/light-switch-app/nrfconnect/Kconfig b/examples/light-switch-app/nrfconnect/Kconfig new file mode 100644 index 00000000000000..9bee833c7681de --- /dev/null +++ b/examples/light-switch-app/nrfconnect/Kconfig @@ -0,0 +1,26 @@ +# +# 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. +# +mainmenu "Matter nRF Connect Light Switch Example Application" + +config STATE_LEDS + bool "Use LEDs to indicate the device state" + default y + help + Use LEDs to render the current state of the device such as the progress of commissioning of + the device into a network or the factory reset initiation. Note that setting this option to + 'n' does not disable the LED indicating the state of the simulated bolt. + +source "Kconfig.zephyr" diff --git a/examples/light-switch-app/nrfconnect/README.md b/examples/light-switch-app/nrfconnect/README.md new file mode 100644 index 00000000000000..a11642be5d72a6 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/README.md @@ -0,0 +1,721 @@ +# Matter nRF Connect Light Switch Example Application + +The nRF Connect Light Switch Example demonstrates how to remotely control a +lighting devices such as light bulbs or LEDs. The application should be used +together with the +[lighting app example](../../lighting-app/nrfconnect/README.md). The light +switch uses buttons to test changing the lighting application example LED state +and works as a brightness dimmer. You can use this example as a reference for +creating your own application. + +

+ Nordic Semiconductor logo + nRF52840 DK +

+ +The example is based on +[Matter](https://github.com/project-chip/connectedhomeip) and Nordic +Semiconductor's nRF Connect SDK, and supports remote access and control of a +lighting examples over a low-power, 802.15.4 Thread network. + +The example behaves as a Matter accessory, that is a device that can be paired +into an existing Matter network and can be controlled by this network. + +
+ +- [Overview](#overview) + - [Bluetooth LE advertising](#bluetooth-le-advertising) + - [Bluetooth LE rendezvous](#bluetooth-le-rendezvous) + - [Device Firmware Upgrade](#device-firmware-upgrade) +- [Requirements](#requirements) + - [Supported devices](#supported_devices) +- [Device UI](#device-ui) + - [LEDs](#leds) + - [Buttons](#buttons) + - [Matter CLI](#matter-cli-commands) +- [Setting up the environment](#setting-up-the-environment) + - [Using Docker container for setup](#using-docker-container-for-setup) + - [Using native shell for setup](#using-native-shell-for-setup) +- [Building](#building) + - [Removing build artifacts](#removing-build-artifacts) + - [Building with release configuration](#building-with-release-configuration) + - [Building with low-power configuration](#building-with-low-power-configuration) + - [Building with Device Firmware Upgrade support](#building-with-device-firmware-upgrade-support) +- [Configuring the example](#configuring-the-example) +- [Flashing and debugging](#flashing-and-debugging) +- [Testing the example](#testing-the-example) + - [Binding process](#binding-process) + - [Testing Device Firmware Upgrade](#testing-device-firmware-upgrade) + +
+ + + +## Overview + +This example is running on the nRF Connect platform, which is based on Nordic +Semiconductor's +[nRF Connect SDK](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/index.html) +and [Zephyr RTOS](https://zephyrproject.org/). Visit Matter's +[nRF Connect platform overview](../../../docs/guides/nrfconnect_platform_overview.md) +to read more about the platform structure and dependencies. + +A light switch device is a simple embedded controller, which has the ability to +control lighting devices, such as light bulbs or LEDs. After commissioning into +a Matter network, the light switch device does not know what it can control. In +other words, it has no information about another device being connected to the +same network. You must provide this information to the light switch through the +process called binding, which links clusters and endpoints on both devices, so +that the devices can interact with each other. + +The Matter device that runs the light switch application is controlled by the +Matter controller device over the Thread protocol. By default, the Matter device +has Thread disabled, and it should be paired with Matter controller and get +configuration from it. Some actions required before establishing full +communication are described below. + +The example also comes with a test mode, which allows to start Thread with the +default settings by pressing button manually. However, this mode does not +guarantee that the device will be able to communicate with the Matter controller +and other devices. + +The example can be configured to use the secure bootloader and utilize it for +performing over-the-air Device Firmware Upgrade using Bluetooth LE. + +### Bluetooth LE advertising + +In this example, to commission the device onto a Matter network, it must be +discoverable over Bluetooth LE. For security reasons, you must start Bluetooth +LE advertising manually after powering up the device by pressing **Button 4**. + +### Bluetooth LE rendezvous + +In this example, the commissioning procedure is done over Bluetooth LE between a +Matter device and the Matter controller, where the controller has the +commissioner role. + +To start the rendezvous, the controller must get the commissioning information +from the Matter device. The data payload is encoded within a QR code, printed to +the UART console, and shared using an NFC tag. NFC tag emulation starts +automatically when Bluetooth LE advertising is started and stays enabled until +Bluetooth LE advertising timeout expires. + +#### Thread provisioning + +Last part of the rendezvous procedure, the provisioning operation involves +sending the Thread network credentials from the Matter controller to the Matter +device. As a result, the device is able to join the Thread network and +communicate with other Thread devices in the network. + +### Device Firmware Upgrade + +The example supports over-the-air (OTA) device firmware upgrade (DFU) using one +of the two available methods: + +- Matter OTA DFU that is mandatory for Matter-compliant devices. This option + is enabled by default. +- [Simple Management Protocol](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/guides/device_mgmt/index.html#device-mgmt) + over Bluetooth LE from Nordic Semiconductor's nRF Connect SDK. This is an + optional proprietary method that is not part of the Matter specification and + can be enabled to work alongside the default Matter OTA DFU. + +For both methods, the +[MCUboot](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/mcuboot/index.html) +bootloader solution is used to replace the old firmware image with the new one. + +#### Matter Over-the-Air DFU + +The Matter over-the-air DFU distinguishes two types of nodes: OTA Provider and +OTA Requestor. + +An OTA Provider is a node that hosts a new firmware image and is able to respond +on an OTA Requestor's queries regarding availability of new firmware images or +requests to start sending the update packages. + +An OTA Requestor is a node that wants to download a new firmware image and sends +requests to an OTA Provider to start the update process. + +#### Simple Management Protocol + +Simple Management Protocol (SMP) is a basic transfer encoding that is used for +device management purposes, including application image management. SMP supports +using different transports, such as Bluetooth LE, UDP, or serial USB/UART. + +In this example, the Matter device runs the SMP Server to download the +application update image using the Bluetooth LE transport. + +See the +[Building with Device Firmware Upgrade support](#building-with-device-firmware-upgrade-support) +section to learn how to enable SMP and use it for the DFU purpose in this +example. + +#### Bootloader + +MCUboot is a secure bootloader used for swapping firmware images of different +versions and generating proper build output files that can be used in the device +firmware upgrade process. + +The bootloader solution requires an area of flash memory to swap application +images during the firmware upgrade. Nordic Semiconductor devices use an external +memory chip for this purpose. The memory chip communicates with the +microcontroller through the QSPI bus. + +See the +[Building with Device Firmware Upgrade support](#building-with-device-firmware-upgrade-support) +section to learn how to change MCUboot and flash configuration in this example. + +
+ + + +## Requirements + +The application requires a specific revision of the nRF Connect SDK to work +correctly. See [Setting up the environment](#setting-up-the-environment) for +more information. + + + +### Supported devices + +The example supports building and running on the following devices: + +| Hardware platform | Build target | Platform image | +| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| [nRF52840 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) | `nrf52840dk_nrf52840` |
nRF52840 DKnRF52840 DK
| +| [nRF5340 DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF5340-DK) | `nrf5340dk_nrf5340_cpuapp` |
nRF5340 DKnRF5340 DK
| + +### Additional requirements for testing + +If you want to test the Light Switch Example application with other devices, you +also need to flash and program the following examples using the compatible +development kits: + +- [Lighting Example Application](../../lighting-app/nrfconnect/README.md) + +Read the [CHIP Tool user guide](../../../docs/guides/chip_tool_guide.md) to +learn how to commission the lighting device to the same Matter network using the +CHIP Tool. + +
+ + + +## Device UI + +This section lists the User Interface elements that you can use to control and +monitor the state of the device. These correspond to PCB components on the +platform image. + +### LEDs + +This section describes all behaviors of LEDs located on platform image. + +**LED 1** shows the overall state of the device and its connectivity. The +following states are possible: + +- _Short Flash On (50 ms on/950 ms off)_ — The device is in the + unprovisioned (unpaired) state and is waiting for a commissioning + application to connect. + +- _Rapid Even Flashing (100 ms on/100 ms off)_ — The device is in the + unprovisioned state and a commissioning application is connected through + Bluetooth LE. + +- _Short Flash Off (950ms on/50ms off)_ — The device is fully + provisioned, but does not yet have full Thread network or service + connectivity. + +- _Solid On_ — The device is fully provisioned and has full Thread + network and service connectivity. + +**LED 2** simulates the BLE DFU process. The following states are possible: + +- _Off_ — BLE is not advertising and DFU can not be performed. + +- _Rapid Even Flashing (30 ms off / 170 ms on)_ — BLE is advertising, + DFU process can be started. + +**LED 3** can be used to identify the device. The LED starts blinking evenly +(500 ms on/500 ms off) when the Identify command of the Identify cluster is +received. The command's argument can be used to specify the duration of the +effect. + +### Buttons + +This section describes a reaction to pressing or holding buttons located on the +platform image. + +**Button 1** can be used for the following purposes: + +- _Pressed for 6 s_ — Initiates the factory reset of the device. + Releasing the button within the 3-second window cancels the factory reset + procedure. **LEDs 1-4** blink in unison when the factory reset procedure is + initiated. + +- _Pressed for less than 3 s_ — Initiates the OTA software update + process. This feature is disabled by default, but can be enabled by + following the + [Building with Device Firmware Upgrade support](#building-with-device-firmware-upgrade-support) + instruction. + +**Button 2** can be used for the following purposes: + +- _Pressed once_ — Changes the light state to the opposite one on a + bound lighting bulb device ([lighting-app](../../lighting-app/nrfconnect/) + example). + +- _Pressed for more than 2 s_ — Changes the brightness of the light on a + bound lighting bulb device ([lighting-app](../../lighting-app/nrfconnect/) + example) (dimmer functionality). The brightness is changing from 0% to 100% + with 1% increments every 300 milliseconds as long as **Button 2** is + pressed. + +**Button 4** can be used to start the NFC tag emulation and enable Bluetooth LE +advertising for the predefined period of time (15 minutes by default). + +**SEGGER J-Link USB port** can be used to get logs from the device or +communicate with it using the +[command line interface](../../../docs/guides/nrfconnect_examples_cli.md). + +**NFC port with antenna attached** can be used to start the +[rendezvous](#bluetooth-le-rendezvous) by providing the commissioning +information from the Matter device in a data payload that can be shared using +NFC. + +### Matter CLI commands + +The Matter CLI allows to run commands via serial interface after USB cable +connection to Nordic Semiconductor's kit. + +To enable the Matter CLI, you must compile the Light Switch Example application +with the additional option **-DCONFIG_CHIP_LIB_SHELL=y**. Run the following +command with _build-target_ replaced with the build target name of Nordic +Semiconductor's kit you are using (for example, `nrf52840dk_nrf52840`): + + west build -b build-target -- -DCONFIG_CHIP_LIB_SHELL=y + +You can use the following commands to control a device that is programmed with +the Light Switch Example application by using the Matter CLI: + + uart:~$ switch onoff on : sends unicast On command to bound device + uart:~$ switch onoff off : sends unicast Off command to bound device + uart:~$ switch onoff toggle : sends unicast Toggle command to bound device + +You can use the following commands a group of devices that are programmed with +the Light Switch Example application by using the Matter CLI: + + uart:~$ switch groups onoff on : sends multicast On command to all bound devices in a group + uart:~$ switch groups onoff off : sends multicast Off command to all bound devices in a group + uart:~$ switch groups onoff toggle : sends multicast Toggle command to all bound devices in a group + +Check the [CLI user guide](../../../docs/guides/nrfconnect_examples_cli.md) to +learn how to use other CLI commands of the application. + +
+ +## Setting up the environment + +Before building the example, check out the Matter repository and sync submodules +using the following command: + + $ git submodule update --init + +The example requires a specific revision of the nRF Connect SDK. You can either +install it along with the related tools directly on your system or use a Docker +image that has the tools pre-installed. + +If you are a macOS user, you won't be able to use the Docker container to flash +the application onto a Nordic development kit due to +[certain limitations of Docker for macOS](https://docs.docker.com/docker-for-mac/faqs/#can-i-pass-through-a-usb-device-to-a-container). +Use the [native shell](#using-native-shell) for building instead. + +### Using Docker container for setup + +To use the Docker container for setup, complete the following steps: + +1. If you do not have the nRF Connect SDK installed yet, create a directory for + it by running the following command: + + $ mkdir ~/nrfconnect + +2. Download the latest version of the nRF Connect SDK Docker image by running + the following command: + + $ docker pull nordicsemi/nrfconnect-chip + +3. Start Docker with the downloaded image by running the following command, + customized to your needs as described below: + + $ docker run --rm -it -e RUNAS=$(id -u) -v ~/nrfconnect:/var/ncs -v ~/connectedhomeip:/var/chip \ + -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" nordicsemi/nrfconnect-chip + + In this command: + + - _~/nrfconnect_ can be replaced with an absolute path to the nRF Connect + SDK source directory. + - _~/connectedhomeip_ must be replaced with an absolute path to the CHIP + source directory. + - _-v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:_ rmw"\* + parameters can be omitted if you are not planning to flash the example + onto hardware. These parameters give the container access to USB devices + connected to your computer such as the nRF52840 DK. + - _--rm_ can be omitted if you do not want the container to be + auto-removed when you exit the container shell session. + - _-e RUNAS=\$(id -u)_ is needed to start the container session as the + current user instead of root. + +4. Update the nRF Connect SDK to the most recent supported revision, by running + the following command: + + $ cd /var/chip + $ python3 scripts/setup/nrfconnect/update_ncs.py --update + +Now you can proceed with the [Building](#building) instruction. + +### Using native shell for setup + +To use the native shell for setup, complete the following steps: + +1. Download and install the following additional software: + + - [nRF Command Line Tools](https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Command-Line-Tools) + - [GN meta-build system](https://gn.googlesource.com/gn/) + +2. If you do not have the nRF Connect SDK installed, follow the + [guide](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/gs_assistant.html#) + in the nRF Connect SDK documentation to install the latest stable nRF + Connect SDK version. Since command-line tools will be used for building the + example, installing SEGGER Embedded Studio is not required. + + If you have the SDK already installed, continue to the next step and update + the nRF Connect SDK after initializing environment variables. + +3. Initialize environment variables referred to by the CHIP and the nRF Connect + SDK build scripts. Replace _nrfconnect-dir_ with the path to your nRF + Connect SDK installation directory, and _toolchain-dir_ with the path to GNU + Arm Embedded Toolchain. + + $ source nrfconnect-dir/zephyr/zephyr-env.sh + $ export ZEPHYR_TOOLCHAIN_VARIANT=gnuarmemb + $ export GNUARMEMB_TOOLCHAIN_PATH=toolchain-dir + +4. Update the nRF Connect SDK to the most recent supported revision by running + the following command (replace _matter-dir_ with the path to Matter + repository directory): + + $ cd matter-dir + $ python3 scripts/setup/nrfconnect/update_ncs.py --update + +Now you can proceed with the [Building](#building) instruction. + +
+ + + +## Building + +Complete the following steps, regardless of the method used for setting up the +environment: + +1. Navigate to the example's directory: + + $ cd examples/light-switch-app/nrfconnect + +2. Run the following command to build the example, with _build-target_ replaced + with the build target name of the Nordic Semiconductor's kit you own, for + example `nrf52840dk_nrf52840`: + + $ west build -b build-target + + You only need to specify the build target on the first build. See + [Requirements](#requirements) for the build target names of compatible kits. + +The output `zephyr.hex` file will be available in the `build/zephyr/` directory. + +### Removing build artifacts + +If you're planning to build the example for a different kit or make changes to +the configuration, remove all build artifacts before building. To do so, use the +following command: + + $ rm -r build + +### Building with release configuration + +To build the example with release configuration that disables the diagnostic +features like logs and command-line interface, run the following command: + + $ west build -b build-target -- -DOVERLAY_CONFIG=third_party/connectedhomeip/config/nrfconnect/app/release.conf + +Remember to replace _build-target_ with the build target name of the Nordic +Semiconductor's kit you own. + +### Building with low-power configuration + +You can build the example using the low-power configuration, which enables +Thread's Sleepy End Device mode and disables debug features, such as the UART +console or the **LED 1** usage. + +To build for the low-power configuration, run the following command with +_build-target_ replaced with the build target name of the Nordic Semiconductor's +kit you own (for example `nrf52840dk_nrf52840`): + + $ west build -b build-target -- -DOVERLAY_CONFIG=overlay-low_power.conf + +For example, use the following command for `nrf52840dk_nrf52840`: + + $ west build -b nrf52840dk_nrf52840 -- -DOVERLAY_CONFIG=overlay-low_power.conf + +### Building with Device Firmware Upgrade support + +Support for DFU using Matter OTA is enabled by default. + +To enable DFU over Bluetooth LE, run the following command with _build-target_ +replaced with the build target name of the Nordic Semiconductor kit you are +using (for example `nrf52840dk_nrf52840`): + + $ west build -b build-target -- -DBUILD_WITH_DFU=BLE + +To completely disable support for both DFU methods, run the following command +with _build-target_ replaced with the build target name of the Nordic +Semiconductor kit you are using (for example `nrf52840dk_nrf52840`): + + $ west build -b build-target -- -DBUILD_WITH_DFU=OFF + +> **Note**: +> +> There are two types of Device Firmware Upgrade modes: single-image DFU and +> multi-image DFU. Single-image mode supports upgrading only one firmware image, +> the application image, and should be used for single-core nRF52840 DK devices. +> Multi-image mode allows to upgrade more firmware images and is suitable for +> upgrading the application core and network core firmware in two-core nRF5340 +> DK devices. + +#### Changing Device Firmware Upgrade configuration + +To change the default DFU configuration, edit the following overlay files +corresponding to the selected configuration: + +- `overlay-mcuboot_qspi_nor_support.conf` - general file enabling MCUboot and + QSPI NOR support, used by all DFU configurations +- `overlay-single_image_smp_dfu_support.conf` - file enabling single-image DFU + over Bluetooth LE using SMP +- `overlay-multi_image_smp_dfu_support.conf` - file enabling multi-image DFU + over Bluetooth LE using SMP +- `overlay-ota_requestor.conf` - file enabling Matter OTA Requestor support. + +The files are located in the `config/nrfconnect/app` directory. You can also +define the desired options in your example's `prj.conf` file. + +#### Changing bootloader configuration + +To change the default MCUboot configuration, edit the +`mcuboot_single_image_dfu.conf` or `mcuboot_multi_image_dfu.conf` overlay files +depending on whether the build target device supports multi-image DFU (nRF5340 +DK) or single-image DFU (nRF52840 DK). The files are located in the +`configuration` directory. + +Make sure to keep the configuration consistent with changes made to the +application configuration. This is necessary for the configuration to work, as +the bootloader image is a separate application from the user application and it +has its own configuration file. + +#### Changing flash memory settings + +In the default configuration, the MCUboot uses the +[Partition Manager](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/scripts/partition_manager/partition_manager.html#partition-manager) +to configure flash partitions used for the bootloader application image slot +purposes. You can change these settings by defining +[static partitions](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/scripts/partition_manager/partition_manager.html#ug-pm-static). +This example uses this option to define using an external flash. + +To modify the flash settings of your board (that is, your _build-target_, for +example `nrf52840dk_nrf52840`), edit the `pm_static.yml` file located in the +`configuration/build-target/` directory. + +
+ + + +## Configuring the example + +The Zephyr ecosystem is based on Kconfig files and the settings can be modified +using the menuconfig utility. + +To open the menuconfig utility, run the following command from the example +directory: + + $ west build -b build-target -t menuconfig + +Remember to replace _build-target_ with the build target name of the Nordic +Semiconductor's kit you own. + +Changes done with menuconfig will be lost if the `build` directory is deleted. +To make them persistent, save the configuration options in the `prj.conf` file. +For more information, see the +[Configuring nRF Connect SDK examples](../../../docs/guides/nrfconnect_examples_configuration.md) +page. + +
+ + + +## Flashing and debugging + +To flash the application to the device, use the west tool and run the following +command from the example directory: + + $ west flash --erase + +If you have multiple development kits connected, west will prompt you to pick +the correct one. + +To debug the application on target, run the following command from the example +directory: + + $ west debug + +
+ + + +## Testing the example + +After building and flashing the example, you can test its functionalities. For +this purpose, you need to prepare a second device that is programmed with the +[Lighting Example](../../lighting-app/nrfconnect/), perform the binding process, +and add Access Control Lists (ACLs). + +### Commissioning the lighting device + +To commission the Lighting Example Application to the same Matter network, read +the [CHIP Tool user guide](../../../docs/guides/chip_tool_guide.md). + +### Binding cluster and endpoints + +Binding links clusters and endpoints on both devices, which enables them to +communicate with each other. + +To perform binding, you need a controller that can write the binding table to +the light switch device and write proper ACL to the endpoint light bulb on the +[Lighting Example application](../../lighting-app/nrfconnect/)). For example, +you can use the [CHIP Tool for Windows or Linux](../../chip-tool/README.md) as +the controller. The ACL should contain information about all clusters that can +be called by the light switch application. See the section about +[interacting with ZCL clusters](../../../docs/guides/chip_tool_guide.md#interacting-with-zcl-clusters) +in the CHIP Tool's user guide for more information about ACLs. + +You can perform the binding process to a single remote endpoint (unicast +binding) or to a group of remote endpoints (group multicast). + +> **Note:** To use a light switch without brightness dimmer, apply only the +> first binding command with cluster no. 6. + +#### Unicast binding to a remote endpoint using the CHIP Tool for Windows or Linux + +In this scenario, commands are provided for a light switch device with the +`nodeId = 2` and a light bulb device with `nodeId = 1`, both commissioned to the +same Matter network. + +To perform the unicast binding process, complete the following steps: + +1. Build the CHIP Tool according to the steps from the + [CHIP Tool user guide](../../../docs/guides/chip_tool_guide.md#building). +2. Go to the CHIP Tool build directory. +3. Add an ACL to the development kit that is programmed with the + [Lighting Application Example](../../lighting-app/nrfconnect/) by running + the following command: + + chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [2], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}, {"cluster": 8, "endpoint": 1, "deviceType": null}]}]' 1 0 + + In this command: + + - `{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}` + is an ACL for the communication with the CHIP Tool. + - `{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [2], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}, {"cluster": 8, "endpoint": 1, "deviceType": null}]}` + is an ACL for binding (cluster no. 6 is the On/Off cluster and the + cluster no. 8 is the Level Control cluster). + + This command adds permissions on the lighting application device that allows + it to receive commands from the light switch device. + +4. Add a binding table to the Light Switch binding cluster: + + chip-tool binding write binding '[{"fabricIndex": 1, "node": 1, "endpoint": 1, "cluster": 6}, {"fabricIndex": 1, "node": 1, "endpoint": 1, "cluster": 8}]' 2 1 + + In this command: + + - `{"fabricIndex": 1, "node": <1>, "endpoint": 1, "cluster": 6}` is a + binding for the On/Off cluster. + - `{"fabricIndex": 1, "node": <1>, "endpoint": 1, "cluster": 8}` is a + binding for the Level Control cluster. + +> **Note:** When a light switch device reboots, the binding table is restored +> from flash memory and the device tries to bind a known device that is +> programmed with the Lighting Application Example. + +#### Group multicast binding to the group of remote endpoints using the CHIP Tool for Windows or Linux + +The group multicast binding lets you control more than one lighting device at a +time using a single light switch. + +The group multicast binding targets all development kits that are programmed +with the [Lighting Application Example](../../lighting-app/nrfconnect/) and +added to the same multicast group. After the binding is established, the light +switch device can send multicast requests, and all of the devices in the bound +groups can run the received command. + +In this scenario, commands are provided for a light switch device with the +`nodeId = 2` and a light bulb device with `nodeId = 1`, both commissioned to the +same Matter network. + +To perform the unicast binding process, complete the following steps: + +1. Build the CHIP Tool according to the steps from the + [CHIP Tool user guide](../../../docs/guides/chip_tool_guide.md#building). +2. Go to the CHIP Tool build directory. +3. Add an ACL to the [lighting endpoint](../../lighting-app/nrfconnect/) + permissions by running the following command: + + chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [2], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}, {"cluster": 8, "endpoint": 1, "deviceType": null}]}]' 1 0 + + In this command: + + - `{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}` + is an ACL for the communication with the CHIP Tool. + - `{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [2], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}, {"cluster": 8, "endpoint": 1, "deviceType": null}]}` + is an ACL for binding (cluster `no. 6` is the On/Off cluster and the + cluster `no. 8` is the Level Control cluster). + + This allows the lighting application device to receive commands from the + light switch device. + +4. Add the light switch device to the multicast group by running the following + command: + + chip-tool tests TestGroupDemoConfig --nodeId 1 + +5. Add all light bulbs to the same multicast group by applying command below + for each of the light bulbs, using the appropriate `` (the + user-defined ID of the node being commissioned except `2` due to use this + `` for light-switch) for each of them: + + chip-tool tests TestGroupDemoConfig --nodeId + +6. Add Binding commands for group multicast: + + chip-tool binding write binding '[{"fabricIndex": 1, "group": 257}]' 2 1 + +### Testing the communication + +To test the communication between the light switch device and the bound devices, +use [light switch buttons](#buttons) or +[Matter CLI commands](#matter-cli-commands), as described in the +[Device UI](#device-ui) section. + +### Testing Device Firmware Upgrade + +Read the +[DFU tutorial](../../../docs/guides/nrfconnect_examples_software_update.md) to +see how to upgrade your device firmware. diff --git a/examples/light-switch-app/nrfconnect/boards/nrf52840dk_nrf52840.conf b/examples/light-switch-app/nrfconnect/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 00000000000000..fb419f0c7aa921 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,17 @@ +# +# 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. +# + +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 diff --git a/examples/light-switch-app/nrfconnect/boards/nrf52840dk_nrf52840.overlay b/examples/light-switch-app/nrfconnect/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000000..b03d3f032eb0e1 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; + + /* + * In some default configurations within the nRF Connect SDK, + * e.g. on nRF52840, the chosen zephyr,entropy node is &cryptocell. + * This devicetree overlay ensures that default is overridden wherever it + * is set, as this application uses the RNG node for entropy exclusively. + */ + + chosen { + zephyr,entropy = &rng; + }; + +}; diff --git a/examples/light-switch-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.conf b/examples/light-switch-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 00000000000000..ce2e61edce82ca --- /dev/null +++ b/examples/light-switch-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,17 @@ +# +# 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. +# + +CONFIG_XOROSHIRO_RANDOM_GENERATOR=y diff --git a/examples/light-switch-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay b/examples/light-switch-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000000..16973a1b1570ee --- /dev/null +++ b/examples/light-switch-app/nrfconnect/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,66 @@ +/* + * 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. + */ + +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + }; + + soc { + /* Add a flash controller which has the compatible + * 'zephyr,sim-flash'. This will ensure that the flash + * simulator can use it. None of the other properties in this + * node is used for anything. + */ + nordic_ram_flash_controller: nordic_ram-flash-controller@0 { + compatible = "zephyr,sim-flash"; + reg = <0x00000000 DT_SIZE_K(40)>; + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + label = "nordic_ram_flash_flash_controller"; + + /* This node label must match that used in the flash + * simulator. + */ + flash_sim0: flash_sim@0 { + status = "okay"; + compatible = "soc-nv-flash"; + label = "simulated_flash"; + erase-block-size = <4096>; + write-block-size = <4>; + reg = <0x00000000 DT_SIZE_K(256)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* This partition must be defined for + * MCUboot to find the partition ID + * of the primary slot for image 1, + * which is stored in this partition. + */ + slot2_partition: partition@0 { + label = "image-2"; + reg = <0x00000000 0x00000A000>; + }; + }; + }; + }; + }; + +}; diff --git a/examples/light-switch-app/nrfconnect/child_image/multiprotocol_rpmsg.conf b/examples/light-switch-app/nrfconnect/child_image/multiprotocol_rpmsg.conf new file mode 100644 index 00000000000000..329d787b50feab --- /dev/null +++ b/examples/light-switch-app/nrfconnect/child_image/multiprotocol_rpmsg.conf @@ -0,0 +1,22 @@ +# +# 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. +# + +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=n +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_BUF_ACL_RX_SIZE=502 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 diff --git a/examples/light-switch-app/nrfconnect/configuration/mcuboot_multi_image_dfu.conf b/examples/light-switch-app/nrfconnect/configuration/mcuboot_multi_image_dfu.conf new file mode 100644 index 00000000000000..2c4579fd928b52 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/configuration/mcuboot_multi_image_dfu.conf @@ -0,0 +1,48 @@ +# +# 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. +# + +# QSPI configuration +CONFIG_NORDIC_QSPI_NOR=y +CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16 + +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# The following configurations are required to support simultaneous multi image update +CONFIG_PCD_APP=y +CONFIG_UPDATEABLE_IMAGE_NUMBER=2 +CONFIG_BOOT_UPGRADE_ONLY=y +# The network core cannot access external flash directly. The flash simulator must be used to +# provide a memory region that is used to forward the new firmware to the network core. +CONFIG_FLASH_SIMULATOR=y +CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y +CONFIG_FLASH_SIMULATOR_STATS=n + +# bootloader size optimization +CONFIG_LOG=n +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_BOOT_BANNER=n +CONFIG_TIMESLICING=n +CONFIG_RESET_ON_FATAL_ERROR=n +CONFIG_MULTITHREADING=n +CONFIG_TICKLESS_KERNEL=n +CONFIG_TIMEOUT_64BIT=n +CONFIG_USE_SEGGER_RTT=n +CONFIG_GPIO=n +CONFIG_NRF_ENABLE_ICACHE=n diff --git a/examples/light-switch-app/nrfconnect/configuration/mcuboot_single_image_dfu.conf b/examples/light-switch-app/nrfconnect/configuration/mcuboot_single_image_dfu.conf new file mode 100644 index 00000000000000..56e61619aef7d4 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/configuration/mcuboot_single_image_dfu.conf @@ -0,0 +1,38 @@ +# +# 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. +# + +# QSPI configuration +CONFIG_NORDIC_QSPI_NOR=y +CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16 + +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# bootloader size optimization +CONFIG_LOG=n +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_BOOT_BANNER=n +CONFIG_TIMESLICING=n +CONFIG_RESET_ON_FATAL_ERROR=n +CONFIG_MULTITHREADING=n +CONFIG_TICKLESS_KERNEL=n +CONFIG_TIMEOUT_64BIT=n +CONFIG_USE_SEGGER_RTT=n +CONFIG_GPIO=n +CONFIG_NRF_ENABLE_ICACHE=n diff --git a/examples/light-switch-app/nrfconnect/configuration/nrf52840dk_nrf52840/pm_static.yml b/examples/light-switch-app/nrfconnect/configuration/nrf52840dk_nrf52840/pm_static.yml new file mode 100644 index 00000000000000..9c26550c0902be --- /dev/null +++ b/examples/light-switch-app/nrfconnect/configuration/nrf52840dk_nrf52840/pm_static.yml @@ -0,0 +1,38 @@ +mcuboot: + address: 0x0 + size: 0x7000 + region: flash_primary +mcuboot_pad: + address: 0x7000 + size: 0x200 +app: + address: 0x7200 + size: 0xf0e00 +mcuboot_primary: + orig_span: &id001 + - mcuboot_pad + - app + span: *id001 + address: 0x7000 + size: 0xf1000 + region: flash_primary +mcuboot_primary_app: + orig_span: &id002 + - app + span: *id002 + address: 0x7200 + size: 0xf0e00 +settings_storage: + address: 0xf8000 + size: 0x8000 + region: flash_primary +mcuboot_secondary: + address: 0x0 + size: 0xf1000 + device: MX25R64 + region: external_flash +external_flash: + address: 0xf1000 + size: 0x70f000 + device: MX25R64 + region: external_flash diff --git a/examples/light-switch-app/nrfconnect/configuration/nrf5340dk_nrf5340_cpuapp/pm_static.yml b/examples/light-switch-app/nrfconnect/configuration/nrf5340dk_nrf5340_cpuapp/pm_static.yml new file mode 100644 index 00000000000000..9f9f677d8af4fc --- /dev/null +++ b/examples/light-switch-app/nrfconnect/configuration/nrf5340dk_nrf5340_cpuapp/pm_static.yml @@ -0,0 +1,52 @@ +mcuboot: + address: 0x0 + size: 0xC000 + region: flash_primary +mcuboot_pad: + address: 0xC000 + size: 0x200 +app: + address: 0xC200 + size: 0xebe00 +mcuboot_primary: + orig_span: &id001 + - mcuboot_pad + - app + span: *id001 + address: 0xC000 + size: 0xec000 + region: flash_primary +mcuboot_primary_app: + orig_span: &id002 + - app + span: *id002 + address: 0xC200 + size: 0xebe00 +settings_storage: + address: 0xf8000 + size: 0x8000 + region: flash_primary +mcuboot_primary_1: + address: 0x0 + size: 0x40000 + device: flash_ctrl + region: ram_flash +mcuboot_secondary: + address: 0x0 + size: 0xec000 + device: MX25R64 + region: external_flash +mcuboot_secondary_1: + address: 0xec000 + size: 0x40000 + device: MX25R64 + region: external_flash +external_flash: + address: 0x12C000 + size: 0x6D4000 + device: MX25R64 + region: external_flash +pcd_sram: + address: 0x20000000 + size: 0x2000 + region: sram_primary diff --git a/examples/light-switch-app/nrfconnect/main/AppTask.cpp b/examples/light-switch-app/nrfconnect/main/AppTask.cpp new file mode 100644 index 00000000000000..49605a58fdcf3a --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/AppTask.cpp @@ -0,0 +1,588 @@ +/* + * + * 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 "BindingHandler.h" +#include "LEDWidget.h" +#include "LightSwitch.h" +#include "ThreadUtil.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_CHIP_OTA_REQUESTOR +#include "OTAUtil.h" +#endif + +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + +LOG_MODULE_DECLARE(app); +namespace { +constexpr EndpointId kLightSwitchEndpointId = 1; +constexpr EndpointId kLightEndpointId = 1; +constexpr uint32_t kFactoryResetTriggerTimeout = 3000; +constexpr uint32_t kFactoryResetCancelWindow = 3000; +constexpr uint32_t kDimmerTriggeredTimeout = 500; +constexpr uint32_t kDimmerInterval = 300; +constexpr uint32_t kIdentifyBlinkRateMs = 500; +constexpr size_t kAppEventQueueSize = 10; + +K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); + +Identify sIdentify = { kLightEndpointId, AppTask::IdentifyStartHandler, AppTask::IdentifyStopHandler, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED }; + +LEDWidget sStatusLED; +LEDWidget sBleLED; +LEDWidget sIdentifyLED; +LEDWidget sUnusedLED; + +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadBLEAdvertising = false; +bool sIsSMPAdvertising = false; +bool sHaveBLEConnections = false; +bool sWasDimmerTriggered = false; + +k_timer sFunctionTimer; +k_timer sDimmerPressKeyTimer; +k_timer sDimmerTimer; + +} /* namespace */ + +AppTask AppTask::sAppTask; + +CHIP_ERROR AppTask::Init() +{ + // Initialize CHIP + LOG_INF("Init CHIP stack"); + + CHIP_ERROR err = Platform::MemoryInit(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("Platform::MemoryInit() failed"); + return err; + } + + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().InitChipStack() failed"); + return err; + } + + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ThreadStackMgr().InitThreadStack() failed: %s", ErrorStr(err)); + return err; + } + +#ifdef CONFIG_OPENTHREAD_MTD_SED + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); +#elif CONFIG_OPENTHREAD_MTD + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); +#else + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_FullEndDevice); +#endif + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed: %s", ErrorStr(err)); + return err; + } + + LightSwitch::GetInstance().Init(kLightSwitchEndpointId); + + // Initialize UI components + LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); + sStatusLED.Init(SYSTEM_STATE_LED); + sBleLED.Init(DFU_BLE_LED); + sIdentifyLED.Init(IDENTIFY_LED); + sUnusedLED.Init(DK_LED4); + UpdateStatusLED(); + + int ret = dk_buttons_init(ButtonEventHandler); + + if (ret) + { + LOG_ERR("dk_buttons_init() failed"); + return System::MapErrorZephyr(ret); + } + + // Initialize Timers + k_timer_init(&sFunctionTimer, AppTask::TimerEventHandler, nullptr); + k_timer_init(&sDimmerPressKeyTimer, AppTask::TimerEventHandler, nullptr); + k_timer_init(&sDimmerTimer, AppTask::TimerEventHandler, nullptr); + k_timer_user_data_set(&sDimmerTimer, this); + k_timer_user_data_set(&sDimmerPressKeyTimer, this); + k_timer_user_data_set(&sFunctionTimer, this); + + // Initialize DFU +#ifdef CONFIG_MCUMGR_SMP_BT + GetDFUOverSMP().Init(RequestSMPAdvertisingStart); + GetDFUOverSMP().ConfirmNewImage(); +#endif + + // Print initial configs + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + ReturnErrorOnFailure(Server::GetInstance().Init()); +#if CONFIG_CHIP_OTA_REQUESTOR + InitBasicOTARequestor(); +#endif + ConfigurationMgr().LogDeviceConfig(); + PrintOnboardingCodes(RendezvousInformationFlags(RendezvousInformationFlag::kBLE)); + + // Add CHIP event handler and start CHIP thread. + // Note that all the initialization code should happen prior to this point + // to avoid data races between the main and the CHIP threads. + PlatformMgr().AddEventHandler(ChipEventHandler, 0); + + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().StartEventLoopTask() failed"); + return err; + } + + return err; +} + +CHIP_ERROR AppTask::StartApp() +{ + ReturnErrorOnFailure(Init()); + + AppEvent event{}; + + while (true) + { + k_msgq_get(&sAppEventQueue, &event, K_FOREVER); + DispatchEvent(&event); + } + + return CHIP_NO_ERROR; +} + +void AppTask::ButtonPushHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_Button) + { + switch (aEvent->ButtonEvent.PinNo) + { + case FUNCTION_BUTTON: + sAppTask.StartTimer(Timer::Function, kFactoryResetTriggerTimeout); + sAppTask.mFunction = TimerFunction::SoftwareUpdate; + break; + case SWITCH_BUTTON: + LOG_INF("Button has been pressed, keep in this state for at least 500 ms to change light sensitivity of binded " + "lighting devices."); + sAppTask.StartTimer(Timer::DimmerTrigger, kDimmerTriggeredTimeout); + break; + default: + break; + } + } +} + +void AppTask::ButtonReleaseHandler(AppEvent * aEvent) +{ + + if (aEvent->Type == AppEvent::kEventType_Button) + { + switch (aEvent->ButtonEvent.PinNo) + { + case FUNCTION_BUTTON: + if (sAppTask.mFunction == TimerFunction::SoftwareUpdate) + { + sAppTask.CancelTimer(Timer::Function); + sAppTask.mFunction = TimerFunction::NoneSelected; + +#ifdef CONFIG_MCUMGR_SMP_BT + GetDFUOverSMP().StartServer(); + sIsSMPAdvertising = true; + UpdateStatusLED(); +#else + LOG_INF("Software update is disabled"); +#endif + } + else if (sAppTask.mFunction == TimerFunction::FactoryReset) + { + UpdateStatusLED(); + + sAppTask.CancelTimer(Timer::Function); + sAppTask.mFunction = TimerFunction::NoneSelected; + LOG_INF("Factory Reset has been canceled"); + } + break; + case SWITCH_BUTTON: + if (!sWasDimmerTriggered) + { + LightSwitch::GetInstance().InitiateActionSwitch(LightSwitch::Action::Toggle); + } + sAppTask.CancelTimer(Timer::Dimmer); + sAppTask.CancelTimer(Timer::DimmerTrigger); + sWasDimmerTriggered = false; + break; + default: + break; + } + } +} + +void AppTask::TimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_Timer) + { + switch ((Timer) aEvent->TimerEvent.TimerType) + { + case Timer::Function: + if (sAppTask.mFunction == TimerFunction::SoftwareUpdate) + { + LOG_INF("Factory Reset has been triggered. Release button within %u ms to cancel.", kFactoryResetCancelWindow); + sAppTask.StartTimer(Timer::Function, kFactoryResetCancelWindow); + sAppTask.mFunction = TimerFunction::FactoryReset; + +#ifdef CONFIG_STATE_LEDS + // reset all LEDs to synchronize factory reset blinking + sStatusLED.Set(false); + sIdentifyLED.Set(false); + sBleLED.Set(false); + sUnusedLED.Set(false); + + sStatusLED.Blink(500); + sIdentifyLED.Blink(500); + sBleLED.Blink(500); + sUnusedLED.Blink(500); +#endif + } + else if (sAppTask.mFunction == TimerFunction::FactoryReset) + { + sAppTask.mFunction = TimerFunction::NoneSelected; + LOG_INF("Factory Reset triggered"); + ConfigurationMgr().InitiateFactoryReset(); + } + break; + case Timer::DimmerTrigger: + LOG_INF("Dimming started..."); + sWasDimmerTriggered = true; + LightSwitch::GetInstance().InitiateActionSwitch(LightSwitch::Action::On); + sAppTask.StartTimer(Timer::Dimmer, kDimmerInterval); + sAppTask.CancelTimer(Timer::DimmerTrigger); + break; + case Timer::Dimmer: + LightSwitch::GetInstance().DimmerChangeBrightness(); + break; + default: + break; + } + } +} + +void AppTask::IdentifyStartHandler(Identify *) +{ + AppEvent event; + event.Type = AppEvent::kEventType_IdentifyStart; + event.Handler = [](AppEvent *) { sIdentifyLED.Blink(kIdentifyBlinkRateMs); }; + sAppTask.PostEvent(&event); +} + +void AppTask::IdentifyStopHandler(Identify *) +{ + AppEvent event; + event.Type = AppEvent::kEventType_IdentifyStop; + event.Handler = [](AppEvent *) { sIdentifyLED.Set(false); }; + sAppTask.PostEvent(&event); +} + +void AppTask::StartBLEAdvertisingHandler(AppEvent * aEvent) +{ + /// Don't allow on starting Matter service BLE advertising after Thread provisioning. + if (Server::GetInstance().GetFabricTable().FabricCount() != 0) + { + LOG_INF("Matter service BLE advertising not started - device is already commissioned"); + return; + } + + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + LOG_INF("BLE advertising is already enabled"); + return; + } + + LOG_INF("Enabling BLE advertising..."); + if (Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR) + { + LOG_ERR("OpenBasicCommissioningWindow() failed"); + } +} + +void AppTask::ChipEventHandler(const ChipDeviceEvent * aEvent, intptr_t /* arg */) +{ + switch (aEvent->Type) + { + case DeviceEventType::kCHIPoBLEAdvertisingChange: + sIsThreadBLEAdvertising = true; + UpdateStatusLED(); +#ifdef CONFIG_CHIP_NFC_COMMISSIONING + if (aEvent->CHIPoBLEAdvertisingChange.Result == kActivity_Started) + { + if (NFCMgr().IsTagEmulationStarted()) + { + LOG_INF("NFC Tag emulation is already started"); + } + else + { + ShareQRCodeOverNFC(RendezvousInformationFlags(RendezvousInformationFlag::kBLE)); + } + } + else if (aEvent->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) + { + NFCMgr().StopTagEmulation(); + } +#endif + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + UpdateStatusLED(); + break; + default: + if ((ConnectivityMgr().NumBLEConnections() == 0) && (!sIsThreadProvisioned || !sIsThreadEnabled)) + { + LOG_ERR("Commissioning with a Thread network has not been done. An error occurred..."); + sIsThreadBLEAdvertising = false; + sHaveBLEConnections = false; + UpdateStatusLED(); + } + break; + } +} + +void AppTask::UpdateStatusLED() +{ +#ifdef CONFIG_STATE_LEDS + sUnusedLED.Set(false); + + // Status LED indicates: + // - blinking 1 s - advertising, ready to commission + // - blinking 200 ms - commissioning in progress + // - constant lightning means commissioned with Thread network + if (sIsThreadBLEAdvertising && !sHaveBLEConnections) + { + sStatusLED.Blink(50, 950); + } + else if (sIsThreadProvisioned && sIsThreadEnabled) + { + sStatusLED.Set(true); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(30, 170); + } + else + { + sStatusLED.Set(false); + } + + // Ble LED indicates BLE connectivity: + //- blinking 200 ms means BLE advertising + if (sIsSMPAdvertising) + { + sBleLED.Blink(30, 170); + } + else + { + sBleLED.Set(false); + } +#endif +} + +void AppTask::ButtonEventHandler(uint32_t aButtonState, uint32_t aHasChanged) +{ + + AppEvent buttonEvent; + buttonEvent.Type = AppEvent::kEventType_Button; + + if (FUNCTION_BUTTON_MASK & aButtonState & aHasChanged) + { + buttonEvent.ButtonEvent.PinNo = FUNCTION_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonPushEvent; + buttonEvent.Handler = ButtonPushHandler; + sAppTask.PostEvent(&buttonEvent); + } + else if (FUNCTION_BUTTON_MASK & aHasChanged) + { + buttonEvent.ButtonEvent.PinNo = FUNCTION_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonReleaseEvent; + buttonEvent.Handler = ButtonReleaseHandler; + sAppTask.PostEvent(&buttonEvent); + } + + if (SWITCH_BUTTON_MASK & aButtonState & aHasChanged) + { + buttonEvent.ButtonEvent.PinNo = SWITCH_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonPushEvent; + buttonEvent.Handler = ButtonPushHandler; + sAppTask.PostEvent(&buttonEvent); + } + else if (SWITCH_BUTTON_MASK & aHasChanged) + { + buttonEvent.ButtonEvent.PinNo = SWITCH_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonReleaseEvent; + buttonEvent.Handler = ButtonReleaseHandler; + sAppTask.PostEvent(&buttonEvent); + } + + if (BLE_ADVERTISEMENT_START_BUTTON_MASK & aHasChanged & aButtonState) + { + buttonEvent.ButtonEvent.PinNo = BLE_ADVERTISEMENT_START_BUTTON; + buttonEvent.ButtonEvent.Action = AppEvent::kButtonPushEvent; + buttonEvent.Handler = StartBLEAdvertisingHandler; + sAppTask.PostEvent(&buttonEvent); + } +} + +void AppTask::StartTimer(Timer aTimer, uint32_t aTimeoutMs) +{ + switch (aTimer) + { + case Timer::Function: + k_timer_start(&sFunctionTimer, K_MSEC(aTimeoutMs), K_NO_WAIT); + break; + case Timer::DimmerTrigger: + k_timer_start(&sDimmerPressKeyTimer, K_MSEC(aTimeoutMs), K_NO_WAIT); + break; + case Timer::Dimmer: + k_timer_start(&sDimmerTimer, K_MSEC(aTimeoutMs), K_MSEC(aTimeoutMs)); + break; + default: + break; + } +} + +void AppTask::CancelTimer(Timer aTimer) +{ + switch (aTimer) + { + case Timer::Function: + k_timer_stop(&sFunctionTimer); + break; + case Timer::DimmerTrigger: + k_timer_stop(&sDimmerPressKeyTimer); + break; + case Timer::Dimmer: + k_timer_stop(&sDimmerTimer); + break; + default: + break; + } +} + +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget & aLedWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = &aLedWidget; + sAppTask.PostEvent(&event); +} + +void AppTask::TimerEventHandler(k_timer * aTimer) +{ + AppEvent event; + if (aTimer == &sFunctionTimer) + { + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.TimerType = (uint8_t) Timer::Function; + event.TimerEvent.Context = k_timer_user_data_get(aTimer); + event.Handler = TimerEventHandler; + sAppTask.PostEvent(&event); + } + if (aTimer == &sDimmerPressKeyTimer) + { + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.TimerType = (uint8_t) Timer::DimmerTrigger; + event.TimerEvent.Context = k_timer_user_data_get(aTimer); + event.Handler = TimerEventHandler; + sAppTask.PostEvent(&event); + } + if (aTimer == &sDimmerTimer) + { + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.TimerType = (uint8_t) Timer::Dimmer; + event.TimerEvent.Context = k_timer_user_data_get(aTimer); + event.Handler = TimerEventHandler; + sAppTask.PostEvent(&event); + } +} + +#ifdef CONFIG_MCUMGR_SMP_BT +void AppTask::RequestSMPAdvertisingStart(void) +{ + AppEvent event; + event.Type = AppEvent::kEventType_StartSMPAdvertising; + event.Handler = [](AppEvent *) { GetDFUOverSMP().StartBLEAdvertising(); }; + sAppTask.PostEvent(&event); +} +#endif + +void AppTask::PostEvent(AppEvent * aEvent) +{ + if (k_msgq_put(&sAppEventQueue, aEvent, K_NO_WAIT) != 0) + { + LOG_INF("Failed to post event to app task event queue"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + LOG_INF("Event received with no handler. Dropping event."); + } +} diff --git a/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp b/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp new file mode 100644 index 00000000000000..7fb16ad754d005 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp @@ -0,0 +1,269 @@ +/* + * + * 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" +#ifdef CONFIG_CHIP_LIB_SHELL +#include "ShellCommands.h" +#endif + +#include +LOG_MODULE_DECLARE(app); + +using namespace chip; +using namespace chip::app; + +void BindingHandler::Init() +{ +#ifdef CONFIG_CHIP_LIB_SHELL + SwitchCommands::RegisterSwitchCommands(); +#endif + DeviceLayer::PlatformMgr().ScheduleWork(InitInternal); +} + +void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, DeviceProxy * aDevice, + void * aContext) +{ + CHIP_ERROR ret = CHIP_NO_ERROR; + + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + LOG_DBG("Binding command applied successfully!"); + }; + + auto onFailure = [](CHIP_ERROR error) { + LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format()); + }; + + 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 + { + + NodeId sourceNodeId = Server::GetInstance().GetFabricTable().FindFabricWithIndex(aBinding.fabricIndex)->GetNodeId(); + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, sourceNodeId, + 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 + { + NodeId sourceNodeId = Server::GetInstance().GetFabricTable().FindFabricWithIndex(aBinding.fabricIndex)->GetNodeId(); + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, sourceNodeId, + 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 + { + NodeId sourceNodeId = Server::GetInstance().GetFabricTable().FindFabricWithIndex(aBinding.fabricIndex)->GetNodeId(); + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, sourceNodeId, + onCommand); + } + break; + default: + LOG_DBG("Invalid binding command data - commandId is not supported"); + break; + } + if (CHIP_NO_ERROR != ret) + { + LOG_ERR("Invoke OnOff Command Request ERROR: %s", ErrorStr(ret)); + } +} + +void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, + DeviceProxy * aDevice, void * aContext) +{ + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + LOG_DBG("Binding command applied successfully!"); + }; + + auto onFailure = [](CHIP_ERROR error) { + LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format()); + }; + + CHIP_ERROR ret = CHIP_NO_ERROR; + + switch (aCommandId) + { + case Clusters::LevelControl::Commands::MoveToLevel::Id: { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + BindingData * data = reinterpret_cast(aContext); + moveToLevelCommand.level = data->Value; + if (aDevice) + { + ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(), + aBinding.remote, moveToLevelCommand, onSuccess, onFailure); + } + else + { + NodeId sourceNodeId = Server::GetInstance().GetFabricTable().FindFabricWithIndex(aBinding.fabricIndex)->GetNodeId(); + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, sourceNodeId, + moveToLevelCommand); + } + } + break; + default: + LOG_DBG("Invalid binding command data - commandId is not supported"); + break; + } + if (CHIP_NO_ERROR != ret) + { + LOG_ERR("Invoke Group Command Request ERROR: %s", ErrorStr(ret)); + } +} + +void BindingHandler::LightSwitchChangedHandler(const EmberBindingTableEntry & binding, DeviceProxy * deviceProxy, void * context) +{ + VerifyOrReturn(context != nullptr, LOG_ERR("Invalid context for Light switch handler");); + BindingData * data = static_cast(context); + + if (binding.type == EMBER_MULTICAST_BINDING && data->IsGroup) + { + switch (data->ClusterId) + { + case Clusters::OnOff::Id: + OnOffProcessCommand(data->CommandId, binding, nullptr, context); + break; + case Clusters::LevelControl::Id: + LevelControlProcessCommand(data->CommandId, binding, nullptr, context); + break; + default: + ChipLogError(NotSpecified, "Invalid binding group command data"); + break; + } + } + else if (binding.type == EMBER_UNICAST_BINDING && !data->IsGroup) + { + switch (data->ClusterId) + { + case Clusters::OnOff::Id: + OnOffProcessCommand(data->CommandId, binding, deviceProxy, context); + break; + case Clusters::LevelControl::Id: + LevelControlProcessCommand(data->CommandId, binding, deviceProxy, context); + break; + default: + ChipLogError(NotSpecified, "Invalid binding unicast command data"); + break; + } + } +} + +void BindingHandler::InitInternal(intptr_t aArg) +{ + LOG_INF("Initialize binding Handler"); + auto & server = Server::GetInstance(); + if (CHIP_NO_ERROR != + BindingManager::GetInstance().Init( + { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() })) + { + LOG_ERR("BindingHandler::InitInternal failed"); + } + + BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler); + 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(); + + LOG_INF("Binding Table size: [%d]:", bindingTable.Size()); + uint8_t i = 0; + for (auto & entry : bindingTable) + { + switch (entry.type) + { + case EMBER_UNICAST_BINDING: + LOG_INF("[%d] UNICAST:", i++); + LOG_INF("\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: + LOG_INF("[%d] GROUP:", i++); + LOG_INF("\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: + LOG_INF("[%d] UNUSED", i++); + break; + case EMBER_MANY_TO_ONE_BINDING: + LOG_INF("[%d] MANY TO ONE", i++); + break; + default: + break; + } + } +} + +void BindingHandler::SwitchWorkerHandler(intptr_t aContext) +{ + VerifyOrReturn(aContext != 0, LOG_ERR("Invalid Swich data")); + + BindingData * data = reinterpret_cast(aContext); + LOG_INF("Notify Bounded Cluster | endpoint: %d cluster: %d", data->EndpointId, data->ClusterId); + BindingManager::GetInstance().NotifyBoundClusterChanged(data->EndpointId, data->ClusterId, static_cast(data)); + + Platform::Delete(data); +} diff --git a/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp b/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp new file mode 100644 index 00000000000000..275dcdceccf1f4 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp @@ -0,0 +1,84 @@ +/* + * + * 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 + +using namespace chip; +using namespace chip::app; + +void LightSwitch::Init(chip::EndpointId aLightSwitchEndpoint) +{ + BindingHandler::Init(); + mLightSwitchEndpoint = aLightSwitchEndpoint; +} + +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::IsGroupBound(); + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + Platform::Delete(data); + } +} + +void LightSwitch::DimmerChangeBrightness() +{ + static 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; + // add to brightness 3 to approximate 1% step of brightness after each call dimmer change. + sBrightness += kOnePercentBrightnessApproximation; + if (sBrightness > kMaximumBrightness) + { + sBrightness = 0; + } + data->Value = (uint8_t) sBrightness; + data->IsGroup = BindingHandler::IsGroupBound(); + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + Platform::Delete(data); + } +} diff --git a/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp b/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp new file mode 100644 index 00000000000000..4dc0a3db58258c --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp @@ -0,0 +1,225 @@ +/* + * + * 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 "ShellCommands.h" +#include "LightSwitch.h" +#include + +#include "BindingHandler.h" + +#ifdef CONFIG_CHIP_LIB_SHELL + +using namespace chip; +using namespace chip::app; + +namespace SwitchCommands { +using Shell::Engine; +using Shell::shell_command_t; +using Shell::streamer_get; +using Shell::streamer_printf; + +Engine sShellSwitchSubCommands; +Engine sShellSwitchOnOffSubCommands; +Engine sShellSwitchGroupsSubCommands; +Engine sShellSwitchGroupsOnOffSubCommands; + +static CHIP_ERROR SwitchHelpHandler(int argc, char ** argv) +{ + sShellSwitchSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +static CHIP_ERROR SwitchCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return SwitchHelpHandler(argc, argv); + } + return sShellSwitchSubCommands.ExecCommand(argc, argv); +} + +static CHIP_ERROR TableCommandHelper(int argc, char ** argv) +{ + BindingHandler::PrintBindingTable(); + return CHIP_NO_ERROR; +} + +namespace Unicast { + +static CHIP_ERROR OnOffHelpHandler(int argc, char ** argv) +{ + sShellSwitchOnOffSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +static CHIP_ERROR OnOffCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return OnOffHelpHandler(argc, argv); + } + return sShellSwitchOnOffSubCommands.ExecCommand(argc, argv); +} + +static CHIP_ERROR OnCommandHandler(int argc, char ** argv) +{ + BindingHandler::BindingData * data = Platform::New(); + data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId(); + data->CommandId = Clusters::OnOff::Commands::On::Id; + data->ClusterId = Clusters::OnOff::Id; + + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +static CHIP_ERROR OffCommandHandler(int argc, char ** argv) +{ + BindingHandler::BindingData * data = Platform::New(); + data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId(); + data->CommandId = Clusters::OnOff::Commands::Off::Id; + data->ClusterId = Clusters::OnOff::Id; + + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +static CHIP_ERROR ToggleCommandHandler(int argc, char ** argv) +{ + BindingHandler::BindingData * data = Platform::New(); + data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId(); + data->CommandId = Clusters::OnOff::Commands::Toggle::Id; + data->ClusterId = Clusters::OnOff::Id; + + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} +} // namespace Unicast + +namespace Group { + +CHIP_ERROR SwitchHelpHandler(int argc, char ** argv) +{ + sShellSwitchGroupsSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR SwitchCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return SwitchHelpHandler(argc, argv); + } + + return sShellSwitchGroupsSubCommands.ExecCommand(argc, argv); +} + +static CHIP_ERROR OnOffHelpHandler(int argc, char ** argv) +{ + sShellSwitchGroupsOnOffSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +static CHIP_ERROR OnOffCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return OnOffHelpHandler(argc, argv); + } + + return sShellSwitchGroupsOnOffSubCommands.ExecCommand(argc, argv); +} + +CHIP_ERROR OnCommandHandler(int argc, char ** argv) +{ + BindingHandler::BindingData * data = Platform::New(); + data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId(); + data->CommandId = Clusters::OnOff::Commands::On::Id; + data->ClusterId = Clusters::OnOff::Id; + data->IsGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OffCommandHandler(int argc, char ** argv) +{ + BindingHandler::BindingData * data = Platform::New(); + data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId(); + data->CommandId = Clusters::OnOff::Commands::Off::Id; + data->ClusterId = Clusters::OnOff::Id; + data->IsGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ToggleCommandHandler(int argc, char ** argv) +{ + BindingHandler::BindingData * data = Platform::New(); + data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId(); + data->CommandId = Clusters::OnOff::Commands::Toggle::Id; + data->ClusterId = Clusters::OnOff::Id; + data->IsGroup = true; + + DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); + return CHIP_NO_ERROR; +} + +} // namespace Group + +void RegisterSwitchCommands() +{ + static const shell_command_t sSwitchSubCommands[] = { + { &SwitchHelpHandler, "help", "Switch commands" }, + { &Unicast::OnOffCommandHandler, "onoff", "Usage: switch onoff [on|off|toggle]" }, + { &Group::SwitchCommandHandler, "groups", "Usage: switch groups onoff [on|off|toggle]" }, + { &TableCommandHelper, "table", "Print a binding table" } + }; + + static const shell_command_t sSwitchOnOffSubCommands[] = { + { &Unicast::OnOffHelpHandler, "help", "Usage : switch ononff [on|off|toggle]" }, + { &Unicast::OnCommandHandler, "on", "Sends on command to bound lighting app" }, + { &Unicast::OffCommandHandler, "off", "Sends off command to bound lighting app" }, + { &Unicast::ToggleCommandHandler, "toggle", "Sends toggle command to bound lighting app" } + }; + + static const shell_command_t sSwitchGroupsSubCommands[] = { + { &Group::SwitchHelpHandler, "help", "switch a group of bounded lightning apps" }, + { &Group::OnOffCommandHandler, "onoff", "Usage: switch groups onoff [on|off|toggle]" } + }; + + static const shell_command_t sSwichGroupsOnOffSubCommands[] = { + { &Group::OnOffHelpHandler, "help", "Usage: switch groups onoff [on|off|toggle]" }, + { &Group::OnCommandHandler, "on", "Sends on command to bound Group" }, + { &Group::OffCommandHandler, "off", "Sends off command to bound Group" }, + { &Group::ToggleCommandHandler, "toggle", "Sends toggle command to bound Group" } + }; + + static const shell_command_t sSwitchCommand = { &SwitchCommandHandler, "switch", + "Light-switch commands. Usage: switch [onoff|groups]" }; + + sShellSwitchGroupsOnOffSubCommands.RegisterCommands(sSwichGroupsOnOffSubCommands, ArraySize(sSwichGroupsOnOffSubCommands)); + sShellSwitchOnOffSubCommands.RegisterCommands(sSwitchOnOffSubCommands, ArraySize(sSwitchOnOffSubCommands)); + sShellSwitchGroupsSubCommands.RegisterCommands(sSwitchGroupsSubCommands, ArraySize(sSwitchGroupsSubCommands)); + sShellSwitchSubCommands.RegisterCommands(sSwitchSubCommands, ArraySize(sSwitchSubCommands)); + + Engine::Root().RegisterCommands(&sSwitchCommand, 1); +} + +} // namespace SwitchCommands +#endif diff --git a/examples/light-switch-app/nrfconnect/main/include/AppConfig.h b/examples/light-switch-app/nrfconnect/main/include/AppConfig.h new file mode 100644 index 00000000000000..4981ca6aadfc04 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/AppConfig.h @@ -0,0 +1,32 @@ +/* + * + * 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 + +// ---- Lighting Example App Config ---- + +#define FUNCTION_BUTTON DK_BTN1 +#define FUNCTION_BUTTON_MASK DK_BTN1_MSK +#define SWITCH_BUTTON DK_BTN2 +#define SWITCH_BUTTON_MASK DK_BTN2_MSK +#define BLE_ADVERTISEMENT_START_BUTTON DK_BTN4 +#define BLE_ADVERTISEMENT_START_BUTTON_MASK DK_BTN4_MSK + +#define SYSTEM_STATE_LED DK_LED1 +#define DFU_BLE_LED DK_LED2 +#define IDENTIFY_LED DK_LED3 diff --git a/examples/light-switch-app/nrfconnect/main/include/AppEvent.h b/examples/light-switch-app/nrfconnect/main/include/AppEvent.h new file mode 100644 index 00000000000000..4a2bd347290703 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/AppEvent.h @@ -0,0 +1,67 @@ +/* + * + * 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 "LEDWidget.h" + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + + constexpr static uint8_t kButtonPushEvent = 1; + constexpr static uint8_t kButtonReleaseEvent = 0; + + enum AppEventTypes : uint8_t + { + kEventType_StartBLEAdvertising, + kEventType_Button, + kEventType_Timer, + kEventType_UpdateLedState, + kEventType_IdentifyStart, + kEventType_IdentifyStop, +#ifdef CONFIG_MCUMGR_SMP_BT + kEventType_StartSMPAdvertising, +#endif + }; + + uint8_t Type; + + union + { + struct + { + uint8_t PinNo; + uint8_t Action; + } ButtonEvent; + struct + { + uint8_t TimerType; + void * Context; + } TimerEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/light-switch-app/nrfconnect/main/include/AppTask.h b/examples/light-switch-app/nrfconnect/main/include/AppTask.h new file mode 100644 index 00000000000000..2f72dd5758b6c2 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/AppTask.h @@ -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. + */ + +#pragma once + +#include "AppEvent.h" +#include "LEDWidget.h" + +#include +#include + +#ifdef CONFIG_MCUMGR_SMP_BT +#include "DFUOverSMP.h" +#endif + +#include + +struct k_timer; +struct Identify; + +class AppTask +{ +public: + CHIP_ERROR StartApp(); + void PostEvent(AppEvent *); + void UpdateClusterState(); + static void IdentifyStartHandler(Identify *); + static void IdentifyStopHandler(Identify *); + +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(); + static AppTask sAppTask; + + CHIP_ERROR Init(); + + void DispatchEvent(AppEvent *); + + static void ButtonPushHandler(AppEvent *); + static void ButtonReleaseHandler(AppEvent *); + static void TimerEventHandler(AppEvent *); + static void StartBLEAdvertisingHandler(AppEvent *); + static void UpdateLedStateEventHandler(AppEvent *); + + static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *, intptr_t); + static void UpdateStatusLED(); + static void ButtonEventHandler(uint32_t, uint32_t); + static void LEDStateUpdateHandler(LEDWidget &); + + static void StartTimer(Timer, uint32_t); + static void CancelTimer(Timer); + static void TimerEventHandler(k_timer *); + +#ifdef CONFIG_MCUMGR_SMP_BT + static void RequestSMPAdvertisingStart(void); +#endif +}; + +inline AppTask & GetAppTask() +{ + return AppTask::sAppTask; +} diff --git a/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h b/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h new file mode 100644 index 00000000000000..02aed9d7aedc49 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h @@ -0,0 +1,50 @@ +/* + * + * 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 +#include +#include + +class BindingHandler +{ +public: + static void Init(); + static void SwitchWorkerHandler(intptr_t); + static void PrintBindingTable(); + static bool IsGroupBound(); + + struct BindingData + { + chip::EndpointId EndpointId; + chip::CommandId CommandId; + chip::ClusterId ClusterId; + uint8_t Value; + bool IsGroup{ false }; + }; + +private: + static void OnOffProcessCommand(chip::CommandId, const EmberBindingTableEntry &, chip::DeviceProxy *, void *); + static void LevelControlProcessCommand(chip::CommandId, const EmberBindingTableEntry &, chip::DeviceProxy *, void *); + static void LightSwitchChangedHandler(const EmberBindingTableEntry &, chip::DeviceProxy *, void *); + static void InitInternal(intptr_t); +}; diff --git a/examples/light-switch-app/nrfconnect/main/include/CHIPProjectConfig.h b/examples/light-switch-app/nrfconnect/main/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..b5a27150a26404 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/CHIPProjectConfig.h @@ -0,0 +1,33 @@ +/* + * + * 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. */ +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#define CHIP_DEVICE_CONFIG_SED_SLOW_POLLING_INTERVAL 2000_ms32 diff --git a/examples/light-switch-app/nrfconnect/main/include/LightSwitch.h b/examples/light-switch-app/nrfconnect/main/include/LightSwitch.h new file mode 100644 index 00000000000000..222bb5216f4fae --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/LightSwitch.h @@ -0,0 +1,50 @@ +/* + * + * 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 InitiateActionSwitch(Action); + void DimmerChangeBrightness(); + chip::EndpointId GetLightSwitchEndpointId() { return mLightSwitchEndpoint; } + + static LightSwitch & GetInstance() + { + static LightSwitch sLightSwitch; + return sLightSwitch; + } + +private: + constexpr static auto kOnePercentBrightnessApproximation = 3; + constexpr static auto kMaximumBrightness = 254; + + chip::EndpointId mLightSwitchEndpoint; +}; diff --git a/examples/light-switch-app/nrfconnect/main/include/ShellCommands.h b/examples/light-switch-app/nrfconnect/main/include/ShellCommands.h new file mode 100644 index 00000000000000..915d90437bdcb0 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/include/ShellCommands.h @@ -0,0 +1,31 @@ +/* + * + * 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 CONFIG_CHIP_LIB_SHELL +#include +#include +#include + +namespace SwitchCommands { + +void RegisterSwitchCommands(); + +} // namespace SwitchCommands + +#endif diff --git a/examples/light-switch-app/nrfconnect/main/main.cpp b/examples/light-switch-app/nrfconnect/main/main.cpp new file mode 100644 index 00000000000000..68db7f7f258fa8 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/main/main.cpp @@ -0,0 +1,33 @@ +/* + * + * 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 + +LOG_MODULE_REGISTER(app); + +using namespace ::chip; + +int main() +{ + CHIP_ERROR err = GetAppTask().StartApp(); + + LOG_ERR("Exited with code %" CHIP_ERROR_FORMAT, err.Format()); + return err == CHIP_NO_ERROR ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/examples/light-switch-app/nrfconnect/overlay-low_power.conf b/examples/light-switch-app/nrfconnect/overlay-low_power.conf new file mode 100644 index 00000000000000..c962425f6ef937 --- /dev/null +++ b/examples/light-switch-app/nrfconnect/overlay-low_power.conf @@ -0,0 +1,30 @@ +# +# 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. +# + +# Enable MTD Sleepy End Device +CONFIG_CHIP_ENABLE_SLEEPY_END_DEVICE_SUPPORT=y + +# Disable UART console +CONFIG_SHELL=n +CONFIG_LOG=n +CONFIG_UART_CONSOLE=n +CONFIG_SERIAL=n + +# Suspend devices when the CPU goes to sleep +CONFIG_PM_DEVICE=y + +# Disable auxiliary state LEDs +CONFIG_STATE_LEDS=n diff --git a/examples/light-switch-app/nrfconnect/prj.conf b/examples/light-switch-app/nrfconnect/prj.conf new file mode 100644 index 00000000000000..e40660a99c276f --- /dev/null +++ b/examples/light-switch-app/nrfconnect/prj.conf @@ -0,0 +1,39 @@ +# +# 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. +# + +# This sample uses sample-defaults.conf to set options common for all +# samples. This file should contain only options specific for this sample +# or overrides of default values. + +# Add support for LEDs and buttons on Nordic development kits +CONFIG_DK_LIBRARY=y + +# OpenThread configs +CONFIG_OPENTHREAD_NORDIC_LIBRARY_MTD=y +CONFIG_OPENTHREAD_MTD=y +CONFIG_OPENTHREAD_FTD=n + +# Bluetooth overrides +CONFIG_BT_DEVICE_NAME="MatterSwitch" + +# Additional configs for debbugging experience. +CONFIG_THREAD_NAME=y +CONFIG_MPU_STACK_GUARD=y + +# CHIP configuration +CONFIG_CHIP_PROJECT_CONFIG="main/include/CHIPProjectConfig.h" +# 32772 == 0x8004 (example light-switch-app) +CONFIG_CHIP_DEVICE_PRODUCT_ID=32772 diff --git a/examples/light-switch-app/nrfconnect/third_party/connectedhomeip b/examples/light-switch-app/nrfconnect/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/light-switch-app/nrfconnect/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file