Add Air Quality Sensor App for silabs (#35488)
* getter for air quality
* Added Air Quality Sample app for silabs
* Restyled by whitespace
* Restyled by clang-format
* Restyled by prettier-markdown
* added build in CI
* minor fix
* Revert "added build in CI"
This reverts commit 5a1fcda96096a172f1e7fb36fdbe8d269fce741d.
* Revert "minor fix"
This reverts commit 8fa8df289dcbfe6840e425d2330d3ee740577e6b.
* added build for app
* added app to target
* resolved comments
* Restyled by whitespace
* Restyled by clang-format
* using schedulework
* using schedulework instead of chiplock
* Restyled by clang-format
* removing unneccessary loggs, resolved memory leak
---------
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml
index 75e4929..498a250 100644
--- a/.github/workflows/examples-efr32.yaml
+++ b/.github/workflows/examples-efr32.yaml
@@ -68,6 +68,7 @@
"./scripts/build/build_examples.py \
--enable-flashbundle \
--target efr32-brd4187c-thermostat-openthread-mtd \
+ --target efr32-brd4187c-air-quality-sensor-app-openthread-mtd \
--target efr32-brd4187c-switch-shell-use-ot-coap-lib \
--target efr32-brd4187c-unit-test \
build \
diff --git a/examples/air-quality-sensor-app/air-quality-sensor-common/include/air-quality-sensor-manager.h b/examples/air-quality-sensor-app/air-quality-sensor-common/include/air-quality-sensor-manager.h
index 93e7bff..a4d6367 100644
--- a/examples/air-quality-sensor-app/air-quality-sensor-common/include/air-quality-sensor-manager.h
+++ b/examples/air-quality-sensor-app/air-quality-sensor-common/include/air-quality-sensor-manager.h
@@ -30,6 +30,11 @@
};
/**
+ * @return The current AirQuality value.
+ */
+ AirQuality::AirQualityEnum GetAirQuality();
+
+ /**
* @brief Get an Air Quality Manager object - this class acts as a singleton device manager for the air quality device
* @param[in] aEndpointId Endpoint that the air quality is on
* @return mInstance The AirQualitySensorManager instance, note this this could be nullptr if InitInstance has not been
diff --git a/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp b/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp
index a6e9476..5fc8bd8 100644
--- a/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp
+++ b/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp
@@ -134,6 +134,11 @@
mFormaldehydeConcentrationMeasurementInstance.SetLevelValue(LevelValueEnum::kLow);
}
+AirQualityEnum AirQualitySensorManager::GetAirQuality()
+{
+ return mAirQualityInstance.GetAirQuality();
+}
+
void AirQualitySensorManager::OnAirQualityChangeHandler(AirQualityEnum newValue)
{
mAirQualityInstance.UpdateAirQuality(newValue);
diff --git a/examples/air-quality-sensor-app/silabs/.gn b/examples/air-quality-sensor-app/silabs/.gn
new file mode 100644
index 0000000..b05216f
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/.gn
@@ -0,0 +1,29 @@
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/build.gni")
+
+# The location of the build configuration file.
+buildconfig = "${build_root}/config/BUILDCONFIG.gn"
+
+# CHIP uses angle bracket includes.
+check_system_includes = true
+
+default_args = {
+ target_cpu = "arm"
+ target_os = "freertos"
+ chip_openthread_ftd = true
+
+ import("//openthread.gni")
+}
diff --git a/examples/air-quality-sensor-app/silabs/BUILD.gn b/examples/air-quality-sensor-app/silabs/BUILD.gn
new file mode 100644
index 0000000..ed3077a
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/BUILD.gn
@@ -0,0 +1,226 @@
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/build.gni")
+import("//build_overrides/chip.gni")
+import("//build_overrides/efr32_sdk.gni")
+import("//build_overrides/pigweed.gni")
+
+import("${build_root}/config/defaults.gni")
+import("${efr32_sdk_build_root}/silabs_executable.gni")
+
+import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni")
+import("${chip_root}/src/platform/device.gni")
+import("${chip_root}/third_party/silabs/silabs_board.gni")
+
+if (chip_enable_pw_rpc) {
+ import("//build_overrides/pigweed.gni")
+ import("$dir_pw_build/target_types.gni")
+}
+
+assert(current_os == "freertos")
+
+silabs_project_dir = "${chip_root}/examples/air-quality-sensor-app/silabs"
+examples_common_plat_dir = "${chip_root}/examples/platform/silabs"
+
+if (wifi_soc) {
+ import("${chip_root}/third_party/silabs/SiWx917_sdk.gni")
+ examples_plat_dir = "${chip_root}/examples/platform/silabs/SiWx917"
+} else {
+ import("${efr32_sdk_build_root}/efr32_sdk.gni")
+ examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32"
+}
+
+import("${examples_common_plat_dir}/args.gni")
+
+declare_args() {
+ # Dump memory usage at link time.
+ chip_print_memory_usage = false
+
+ # Enable the air quality sensor
+ # Some boards do not have a air quality sensor
+ use_air_quality_sensor = false
+}
+
+if (wifi_soc) {
+ siwx917_sdk("sdk") {
+ sources = [
+ "${examples_common_plat_dir}/FreeRTOSConfig.h",
+ "${silabs_project_dir}/include/CHIPProjectConfig.h",
+ ]
+
+ include_dirs = [
+ "${chip_root}/src/platform/silabs/SiWx917",
+ "${silabs_project_dir}/include",
+ "${examples_plat_dir}",
+ "${chip_root}/src/lib",
+ "${examples_common_plat_dir}",
+ ]
+
+ defines = []
+ if (chip_enable_pw_rpc) {
+ defines += [
+ "HAL_VCOM_ENABLE=1",
+ "PW_RPC_ENABLED",
+ ]
+ }
+ }
+} else {
+ efr32_sdk("sdk") {
+ sources = [
+ "${examples_common_plat_dir}/FreeRTOSConfig.h",
+ "${silabs_project_dir}/include/CHIPProjectConfig.h",
+ ]
+
+ include_dirs = [
+ "${chip_root}/src/platform/silabs/efr32",
+ "${silabs_project_dir}/include",
+ "${examples_plat_dir}",
+ "${chip_root}/src/lib",
+ "${examples_common_plat_dir}",
+ ]
+
+ defines = []
+ if (chip_enable_pw_rpc) {
+ defines += [
+ "HAL_VCOM_ENABLE=1",
+ "PW_RPC_ENABLED",
+ ]
+ }
+
+ #TODO: This is a placeholder for the actual implementation
+ if (use_air_quality_sensor) {
+ include_dirs +=
+ [ "${efr32_sdk_root}/examples/platform/silabs/sensors/AirQuality" ]
+
+ defines += [ "USE_AIR_QUALITY_SENSOR" ]
+ }
+ }
+}
+
+#ENDTODO
+
+silabs_executable("air_quality_sensor_app") {
+ output_name = "matter-silabs-air-quality-sensor-example.out"
+ include_dirs = [
+ "include",
+ "${chip_root}/examples/air-quality-sensor-app/air-quality-sensor-common/include",
+ ]
+ defines = []
+
+ sources = [
+ "${chip_root}/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp",
+ "${examples_common_plat_dir}/main.cpp",
+ "src/AppTask.cpp",
+ "src/SensorManager.cpp",
+ "src/ZclCallbacks.cpp",
+ ]
+
+ #TODO: This is a placeholder for the actual implementation
+ if (use_air_quality_sensor) {
+ sources += [ "${efr32_sdk_root}/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp" ]
+ }
+
+ #ENDTODO
+
+ if (!disable_lcd) {
+ sources += [ "src/AirQualitySensorUI.cpp" ]
+ }
+
+ deps = [
+ ":sdk",
+ "${chip_root}/src/platform/logging:default",
+ app_data_model,
+ ]
+
+ if (wifi_soc) {
+ deps += [ "${examples_plat_dir}:siwx917-common" ]
+ } else {
+ deps += [ "${examples_plat_dir}:efr32-common" ]
+ }
+
+ if (chip_enable_pw_rpc) {
+ defines += [
+ "PW_RPC_ENABLED",
+ "PW_RPC_ATTRIBUTE_SERVICE=1",
+ "PW_RPC_BUTTON_SERVICE=1",
+ "PW_RPC_DESCRIPTOR_SERVICE=1",
+ "PW_RPC_DEVICE_SERVICE=1",
+ "PW_RPC_LIGHTING_SERVICE=1",
+ ]
+
+ sources += [
+ "${chip_root}/examples/common/pigweed/RpcService.cpp",
+ "${chip_root}/examples/common/pigweed/efr32/PigweedLoggerMutex.cpp",
+ "${examples_common_plat_dir}/PigweedLogger.cpp",
+ "${examples_common_plat_dir}/Rpc.cpp",
+ ]
+
+ deps += [
+ "$dir_pw_hdlc:default_addresses",
+ "$dir_pw_hdlc:rpc_channel_output",
+ "$dir_pw_stream:sys_io_stream",
+ "${chip_root}/config/efr32/lib/pw_rpc:pw_rpc",
+ "${chip_root}/examples/common/pigweed:attributes_service.nanopb_rpc",
+ "${chip_root}/examples/common/pigweed:button_service.nanopb_rpc",
+ "${chip_root}/examples/common/pigweed:descriptor_service.nanopb_rpc",
+ "${chip_root}/examples/common/pigweed:device_service.nanopb_rpc",
+ "${chip_root}/examples/common/pigweed:lighting_service.nanopb_rpc",
+ ]
+
+ if (wifi_soc) {
+ deps += [ "${examples_plat_dir}/pw_sys_io:pw_sys_io_siwx917" ]
+ } else {
+ deps += [ "${examples_common_plat_dir}/pw_sys_io:pw_sys_io_silabs" ]
+ }
+
+ deps += pw_build_LINK_DEPS
+
+ include_dirs += [
+ "${chip_root}/examples/common",
+ "${chip_root}/examples/common/pigweed/efr32",
+ ]
+ }
+
+ ldscript = "${examples_common_plat_dir}/ldscripts/${silabs_family}.ld"
+
+ inputs = [ ldscript ]
+
+ ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ]
+
+ if (chip_print_memory_usage) {
+ ldflags += [
+ "-Wl,--print-memory-usage",
+ "-fstack-usage",
+ ]
+ }
+
+ # WiFi Settings
+ if (chip_enable_wifi) {
+ ldflags += [
+ "-Wl,--defsym",
+ "-Wl,SILABS_WIFI=1",
+ ]
+ }
+
+ output_dir = root_out_dir
+}
+
+group("silabs") {
+ deps = [ ":air_quality_sensor_app" ]
+}
+
+group("default") {
+ deps = [ ":silabs" ]
+}
diff --git a/examples/air-quality-sensor-app/silabs/README.md b/examples/air-quality-sensor-app/silabs/README.md
new file mode 100644
index 0000000..d0e89d3
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/README.md
@@ -0,0 +1,366 @@
+# Matter Air Quality Sensor Example
+
+An example showing the use of CHIP on the Silicon Labs EFR32 MG12 and MG24.
+
+<hr>
+
+- [Matter Air Quality Sensor Example](#matter-air-quality-sensor-example)
+ - [Introduction](#introduction)
+ - [Building](#building)
+ - [Linux](#linux)
+ - [Mac OS X](#mac-os-x)
+ - [Flashing the Application](#flashing-the-application)
+ - [Viewing Logging Output](#viewing-logging-output)
+ - [Running the Complete Example](#running-the-complete-example)
+ - [Notes](#notes)
+ - [On Border Router:](#on-border-router)
+ - [On PC(Linux):](#on-pclinux)
+ - [Running RPC console](#running-rpc-console)
+ - [Memory settings](#memory-settings)
+ - [OTA Software Update](#ota-software-update)
+ - [Building options](#building-options)
+ - [Disabling logging](#disabling-logging)
+ - [Debug build / release build](#debug-build--release-build)
+ - [Disabling LCD](#disabling-lcd)
+ - [KVS maximum entry count](#kvs-maximum-entry-count)
+
+<hr>
+
+> **NOTE:** Silicon Laboratories now maintains a public matter GitHub repo with
+> frequent releases thoroughly tested and validated. Developers looking to
+> develop matter products with silabs hardware are encouraged to use our latest
+> release with added tools and documentation.
+> [Silabs Matter Github](https://github.com/SiliconLabs/matter/releases)
+
+## Introduction
+
+The EFR32 Air Quality Sensor example provides a baseline demonstration of a air
+quality sensor device, built using Matter and the Silicon Labs gecko SDK. It can
+be controlled by a Chip controller over an Openthread or Wifi network.
+
+The EFR32 device can be commissioned over Bluetooth Low Energy where the device
+and the Chip controller will exchange security information with the Rendez-vous
+procedure. If using Thread, Thread Network credentials are then provided to the
+EFR32 device which will then join the Thread network.
+
+If the LCD is enabled, the LCD on the Silabs WSTK shows a QR Code containing the
+needed commissioning information for the BLE connection and starting the
+Rendez-vous procedure.
+
+The air quality sensor example is intended to serve both as a means to explore
+the workings of Matter as well as a template for creating real products based on
+the Silicon Labs platform.
+
+## Building
+
+- Download the
+ [Simplicity Commander](https://www.silabs.com/mcu/programming-options)
+ command line tool, and ensure that `commander` is your shell search path.
+ (For Mac OS X, `commander` is located inside
+ `Commander.app/Contents/MacOS/`.)
+
+- Download and install a suitable ARM gcc tool chain (For most Host, the
+ bootstrap already installs the toolchain):
+ [GNU Arm Embedded Toolchain 12.2 Rel1](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)
+
+- Install some additional tools(likely already present for CHIP developers):
+
+#### Linux
+
+ $ sudo apt-get install git ninja-build
+
+#### Mac OS X
+
+ $ brew install ninja
+
+- Supported hardware:
+
+ - > For the latest supported hardware please refer to the
+ > [Hardware Requirements](https://github.com/SiliconLabs/matter/blob/latest/docs/silabs/general/HARDWARE_REQUIREMENTS.md)
+ > in the Silicon Labs Matter Github Repo
+
+ MG21 boards: Currently not supported due to RAM limitation.
+
+ - BRD4180A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm
+
+ MG24 boards :
+
+ - BRD2601B / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm
+ - BRD2703A / SLWSTK6000B / Wireless Starter Kit / 2.4GHz@10dBm
+ - BRD4186A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@10dBm
+ - BRD4186C / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@10dBm
+ - BRD4187A / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm
+ - BRD4187C / SLWSTK6006A / Wireless Starter Kit / 2.4GHz@20dBm
+
+* Build the example application:
+
+ cd ~/connectedhomeip
+ ./scripts/examples/gn_silabs_example.sh ./examples/air-quality-sensor-app/silabs/ ./out/air-quality-sensor-app BRD4187C
+
+- To delete generated executable, libraries and object files use:
+
+ $ cd ~/connectedhomeip
+ $ rm -rf ./out/
+
+ OR use GN/Ninja directly
+
+ $ cd ~/connectedhomeip/examples/air-quality-sensor-app/silabs
+ $ git submodule update --init
+ $ source third_party/connectedhomeip/scripts/activate.sh
+ $ export SILABS_BOARD=BRD4187C
+ $ gn gen out/debug
+ $ ninja -C out/debug
+
+- To delete generated executable, libraries and object files use:
+
+ $ cd ~/connectedhomeip/examples/air-quality-sensor-app/silabs
+ $ rm -rf out/
+
+* Build the example with Matter shell
+
+ ./scripts/examples/gn_silabs_example.sh examples/air-quality-sensor-app/silabs/ out/air-quality-sensor-app-app BRD4187C chip_build_libshell=true
+
+* Build the example as Intermittently Connected Device (ICD)
+
+ $ ./scripts/examples/gn_silabs_example.sh ./examples/air-quality-sensor-app/silabs/ ./out/air-quality-sensor-app-app_ICD BRD4187C --icd
+
+ or use gn as previously mentioned but adding the following arguments:
+
+ $ gn gen out/debug '--args=SILABS_BOARD="BRD4187C" enable_sleepy_device=true chip_openthread_ftd=false chip_build_libshell=true'
+
+* Build the example with pigweed RCP
+
+ $ ./scripts/examples/gn_silabs_example.sh examples/air-quality-sensor-app/silabs/ out/air-quality-sensor-app-app_rpc BRD4187C 'import("//with_pw_rpc.gni")'
+
+ or use GN/Ninja Directly
+
+ $ cd ~/connectedhomeip/examples/air-quality-sensor-app/silabs
+ $ git submodule update --init
+ $ source third_party/connectedhomeip/scripts/activate.sh
+ $ export SILABS_BOARD=BRD4187C
+ $ gn gen out/debug --args='import("//with_pw_rpc.gni")'
+ $ ninja -C out/debug
+
+For more build options, help is provided when running the build script without
+arguments
+
+ ./scripts/examples/gn_silabs_example.sh
+
+## Flashing the Application
+
+- On the command line:
+
+ $ cd ~/connectedhomeip/examples/air-quality-sensor-app/silabs
+ $ python3 out/debug/matter-silabs-air-quality-sensor-app-switch-example.flash.py
+
+- Or with the Ozone debugger, just load the .out file.
+
+All EFR32 boards require a bootloader, see Silicon Labs documentation for more
+info. Pre-built bootloader binaries are available in the Assets section of the
+Releases page on
+[Silabs Matter Github](https://github.com/SiliconLabs/matter/releases) .
+
+## Viewing Logging Output
+
+The example application is built to use the SEGGER Real Time Transfer (RTT)
+facility for log output. RTT is a feature built-in to the J-Link Interface MCU
+on the WSTK development board. It allows bi-directional communication with an
+embedded application without the need for a dedicated UART.
+
+Using the RTT facility requires downloading and installing the _SEGGER J-Link
+Software and Documentation Pack_
+([web site](https://www.segger.com/downloads/jlink#J-LinkSoftwareAndDocumentationPack)).
+
+Alternatively, SEGGER Ozone J-Link debugger can be used to view RTT logs too
+after flashing the .out file.
+
+- Download the J-Link installer by navigating to the appropriate URL and
+ agreeing to the license agreement.
+
+- [JLink_Linux_x86_64.deb](https://www.segger.com/downloads/jlink/JLink_Linux_x86_64.deb)
+- [JLink_MacOSX.pkg](https://www.segger.com/downloads/jlink/JLink_MacOSX.pkg)
+
+* Install the J-Link software
+
+ $ cd ~/Downloads
+ $ sudo dpkg -i JLink_Linux_V*_x86_64.deb
+
+* In Linux, grant the logged in user the ability to talk to the development
+ hardware via the linux tty device (/dev/ttyACMx) by adding them to the
+ dialout group.
+
+ $ sudo usermod -a -G dialout ${USER}
+
+Once the above is complete, log output can be viewed using the JLinkExe tool in
+combination with JLinkRTTClient as follows:
+
+- Run the JLinkExe tool with arguments to autoconnect to the WSTK board:
+
+ For MG12 use:
+
+ $ JLinkExe -device EFR32MG12PXXXF1024 -if JTAG -speed 4000 -autoconnect 1
+
+ For MG21 use:
+
+ $ JLinkExe -device EFR32MG21AXXXF1024 -if SWD -speed 4000 -autoconnect 1
+
+- In a second terminal, run the JLinkRTTClient to view logs:
+
+ $ JLinkRTTClient
+
+## Running the Complete Example
+
+- It is assumed here that you already have an OpenThread border router
+ configured and running. If not see the following guide
+ [Openthread_border_router](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/openthread_border_router_pi.md)
+ for more information on how to setup a border router on a raspberryPi.
+
+ Take note that the RCP code is available directly through
+ [Simplicity Studio 5](https://www.silabs.com/products/development-tools/software/simplicity-studio/simplicity-studio-5)
+ under File->New->Project Wizard->Examples->Thread : ot-rcp
+
+- For this example to work, it is necessary to have a second efr32 device
+ running the
+ [air quality sensor app example](https://github.com/project-chip/connectedhomeip/blob/master/examples/air-quality-sensor-app/silabs/README.md)
+ commissioned on the same openthread network
+
+- User interface : **LCD** The LCD on Silabs WSTK shows a QR Code. This QR
+ Code is be scanned by the CHIP Tool app For the Rendez-vous procedure over
+ BLE
+
+ * On devices that do not have or support the LCD Display like the BRD4166A Thunderboard Sense 2,
+ a URL can be found in the RTT logs.
+
+ <info > [SVR] Copy/paste the below URL in a browser to see the QR Code:
+ <info > [SVR] https://project-chip.github.io/connectedhomeip/qrcode.html?data=CH%3AI34NM%20-00%200C9SS0
+
+ **LED 0** 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.
+
+ **Push Button 0**
+
+ - _Press and Release_ : Start, or restart, BLE advertisement in fast mode. It will advertise in this mode
+ for 30 seconds. The device will then switch to a slower interval advertisement.
+ After 15 minutes, the advertisement stops.
+
+ - _Pressed and hold for 6 s_ : Initiates the factory reset of the device.
+ Releasing the button within the 6-second window cancels the factory reset
+ procedure. **LEDs** blink in unison when the factory reset procedure is
+ initiated.
+
+* You can provision and control the Chip device using the python controller,
+ [CHIPTool](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md)
+ standalone, Android or iOS app
+
+ Here is an example with the CHIPTool:
+
+ ```
+ chip-tool pairing ble-thread 1 hex:<operationalDataset> 20202021 3840
+ ```
+
+### Notes
+
+- Depending on your network settings your router might not provide native ipv6
+ addresses to your devices (Border router / PC). If this is the case, you
+ need to add a static ipv6 addresses on both device and then an ipv6 route to
+ the border router on your PC
+
+#### On Border Router:
+
+`$ sudo ip addr add dev <Network interface> 2002::2/64`
+
+#### On PC(Linux):
+
+`$ sudo ip addr add dev <Network interface> 2002::1/64`
+
+#Add Ipv6 route on PC(Linux) \$ sudo ip route add <Thread global ipv6 prefix>/64
+via 2002::2
+
+## Running RPC console
+
+- As part of building the example with RPCs enabled the chip_rpc python
+ interactive console is installed into your venv. The python wheel files are
+ also created in the output folder: out/debug/chip_rpc_console_wheels. To
+ install the wheel files without rebuilding:
+
+ `pip3 install out/debug/chip_rpc_console_wheels/*.whl`
+
+- To use the chip-rpc console after it has been installed run:
+
+ `chip-console --device /dev/tty.<SERIALDEVICE> -b 115200 -o /<YourFolder>/pw_log.out`
+
+- Then you can simulate a button press or release using the following command
+ where : idx = 0 or 1 for Button PB0 or PB1 action = 0 for PRESSED, 1 for
+ RELEASE Test toggling the LED with
+
+ `rpcs.chip.rpc.Button.Event(idx=1, pushed=True)`
+
+## Memory settings
+
+While most of the RAM usage in CHIP is static, allowing easier debugging and
+optimization with symbols analysis, we still need some HEAP for the crypto and
+OpenThread. Size of the HEAP can be modified by changing the value of the
+`configTOTAL_HEAP_SIZE` define inside of the FreeRTOSConfig.h file of this
+example. Please take note that a HEAP size smaller than 13k can and will cause a
+Mbedtls failure during the BLE rendez-vous or CASE session
+
+To track memory usage you can set `enable_heap_monitoring = true` either in the
+BUILD.gn file or pass it as a build argument to gn. This will print on the RTT
+console the RAM usage of each individual task and the number of Memory
+allocation and Free. While this is not extensive monitoring you're welcome to
+modify `examples/platform/efr32/MemMonitoring.cpp` to add your own memory
+tracking code inside the `trackAlloc` and `trackFree` function
+
+## OTA Software Update
+
+For the description of Software Update process with EFR32 example applications
+see
+[EFR32 OTA Software Update](../../../docs/guides/silabs_efr32_software_update.md)
+
+## Building options
+
+All of Silabs's examples within the Matter repo have all the features enabled by
+default, as to provide the best end user experience. However some of those
+features can easily be toggled on or off. Here is a short list of options :
+
+### Disabling logging
+
+chip_progress_logging, chip_detail_logging, chip_automation_logging
+
+ $ ./scripts/examples/gn_silabs_example.sh ./examples/air-quality-sensor-app/silabs ./out/air-quality-sensor-app-app BRD4164A "chip_detail_logging=false chip_automation_logging=false chip_progress_logging=false"
+
+### Debug build / release build
+
+is_debug
+
+ $ ./scripts/examples/gn_silabs_example.sh ./examples/air-quality-sensor-app/silabs ./out/air-quality-sensor-app-app BRD4164A "is_debug=false"
+
+### Disabling LCD
+
+show_qr_code
+
+ $ ./scripts/examples/gn_silabs_example.sh ./examples/air-quality-sensor-app/silabs ./out/air-quality-sensor-app-app BRD4164A "show_qr_code=false"
+
+### KVS maximum entry count
+
+kvs_max_entries
+
+ Set the maximum Kvs entries that can be stored in NVM (Default 75)
+ Thresholds: 30 <= kvs_max_entries <= 255
+
+ $ ./scripts/examples/gn_silabs_example.sh ./examples/air-quality-sensor-app/silabs ./out/air-quality-sensor-app-app BRD4164A kvs_max_entries=50
diff --git a/examples/air-quality-sensor-app/silabs/build_for_wifi_args.gni b/examples/air-quality-sensor-app/silabs/build_for_wifi_args.gni
new file mode 100644
index 0000000..718600a
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/build_for_wifi_args.gni
@@ -0,0 +1,22 @@
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import("//build_overrides/chip.gni")
+import("${chip_root}/config/standalone/args.gni")
+
+silabs_sdk_target = get_label_info(":sdk", "label_no_toolchain")
+import("${chip_root}/src/platform/silabs/wifi_args.gni")
+chip_enable_wifi = true
+chip_enable_ota_requestor = true
+app_data_model =
+ "${chip_root}/examples/air-quality-sensor-app/air-quality-sensor-common"
diff --git a/examples/air-quality-sensor-app/silabs/build_for_wifi_gnfile.gn b/examples/air-quality-sensor-app/silabs/build_for_wifi_gnfile.gn
new file mode 100644
index 0000000..d391814
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/build_for_wifi_gnfile.gn
@@ -0,0 +1,28 @@
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/build.gni")
+
+# The location of the build configuration file.
+buildconfig = "${build_root}/config/BUILDCONFIG.gn"
+
+# CHIP uses angle bracket includes.
+check_system_includes = true
+
+default_args = {
+ target_cpu = "arm"
+ target_os = "freertos"
+ chip_enable_wifi = true
+ import("//build_for_wifi_args.gni")
+}
diff --git a/examples/air-quality-sensor-app/silabs/build_overrides b/examples/air-quality-sensor-app/silabs/build_overrides
new file mode 120000
index 0000000..e578e73
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/build_overrides
@@ -0,0 +1 @@
+../../build_overrides
\ No newline at end of file
diff --git a/examples/air-quality-sensor-app/silabs/include/AirQualityConfig.h b/examples/air-quality-sensor-app/silabs/include/AirQualityConfig.h
new file mode 100644
index 0000000..9cc9d77
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/AirQualityConfig.h
@@ -0,0 +1,41 @@
+#ifndef SL_MATTER_AIR_QUALITY_CONFIG_H
+#define SL_MATTER_AIR_QUALITY_CONFIG_H
+
+// <<< Use Configuration Wizard in Context Menu >>>
+
+// AirQualityConfig.h
+// This header file contains preprocessor directives to set air quality thresholds.
+// Users should modify these #define statements to customize thresholds for their application.
+// These thresholds are used to categorize air quality into various levels.
+
+// <o MIN_THRESHOLD> Minimum Threshold Value
+// <i> Default: 0
+#define MIN_THRESHOLD 0
+
+// <o GOOD_THRESHOLD> Good Threshold Value
+// <i> Default: 50
+#define GOOD_THRESHOLD 50
+
+// <o FAIR_THRESHOLD> Fair Threshold Value
+// <i> Default: 100
+#define FAIR_THRESHOLD 100
+
+// <o MODERATE_THRESHOLD> Moderate Threshold Value
+// <i> Default: 150
+#define MODERATE_THRESHOLD 150
+
+// <o POOR_THRESHOLD> Poor Threshold Value
+// <i> Default: 200
+#define POOR_THRESHOLD 200
+
+// <o VERY_POOR_THRESHOLD> Very Poor Threshold Value
+// <i> Default: 250
+#define VERY_POOR_THRESHOLD 250
+
+// <o EXTREMELY_POOR_THRESHOLD> Extremely Poor Threshold Value
+// <i> Default: 300
+#define EXTREMELY_POOR_THRESHOLD 300
+
+// <<< end of configuration section >>>
+
+#endif // SL_MATTER_AIR_QUALITY_CONFIG_H
diff --git a/examples/air-quality-sensor-app/silabs/include/AirQualitySensorUI.h b/examples/air-quality-sensor-app/silabs/include/AirQualitySensorUI.h
new file mode 100644
index 0000000..0ee7123
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/AirQualitySensorUI.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright (c) 2024 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 "demo-ui-bitmaps.h"
+#include "dmd.h"
+#include "glib.h"
+#include "lcd.h"
+
+class AirQualitySensorUI
+{
+
+public:
+ static void DrawUI(GLIB_Context_t * glibContext);
+
+private:
+ static void DrawHeader(GLIB_Context_t * glibContext);
+ static void DrawFooter(GLIB_Context_t * glibContext);
+ static void DrawCurrentAirQuality(GLIB_Context_t * glibContext);
+ static void DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data,
+ uint32_t size);
+};
diff --git a/examples/air-quality-sensor-app/silabs/include/AppConfig.h b/examples/air-quality-sensor-app/silabs/include/AppConfig.h
new file mode 100644
index 0000000..fafcfd3
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/AppConfig.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * Copyright (c) 2019-2024 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "silabs_utils.h"
+
+// ---- Air Quality Sensor Example App Config ----
+
+#define APP_TASK_NAME "AQS"
+
+#define BLE_DEV_NAME "SiLabs-Air-Quality-Sensor"
+
+// Time it takes in ms for the simulated actuator to move from one
+// APP Logo, boolean only. must be 64x64
+#define ON_DEMO_BITMAP \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x81, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, \
+ 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, \
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, \
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0x0F, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, \
+ 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+#define OFF_DEMO_BITMAP ON_DEMO_BITMAP
diff --git a/examples/air-quality-sensor-app/silabs/include/AppEvent.h b/examples/air-quality-sensor-app/silabs/include/AppEvent.h
new file mode 100644
index 0000000..f521829
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/AppEvent.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * Copyright (c) 2018-2024 Nest Labs, Inc.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <cstdint>
+
+struct AppEvent;
+typedef void (*EventHandler)(AppEvent *);
+
+struct AppEvent
+{
+ enum AppEventTypes
+ {
+ kEventType_Button = 0,
+ kEventType_Timer,
+ kEventType_AirQualitySensor,
+ kEventType_Install,
+ };
+
+ uint16_t Type;
+
+ union
+ {
+ struct
+ {
+ uint8_t Action;
+ } ButtonEvent;
+ struct
+ {
+ void * Context;
+ } TimerEvent;
+ struct
+ {
+ uint8_t Action;
+ int32_t Actor;
+ } AirQualitySensorEvent;
+ };
+
+ EventHandler Handler;
+};
diff --git a/examples/air-quality-sensor-app/silabs/include/AppTask.h b/examples/air-quality-sensor-app/silabs/include/AppTask.h
new file mode 100644
index 0000000..4a42295
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/AppTask.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * Copyright (c) 2019-2024 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**********************************************************
+ * Includes
+ *********************************************************/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef DISPLAY_ENABLED
+#include "AirQualitySensorUI.h"
+#endif
+
+#include "AppEvent.h"
+#include "BaseApplication.h"
+#include "SensorManager.h"
+#include <ble/BLEEndPoint.h>
+#include <cmsis_os2.h>
+#include <lib/core/CHIPError.h>
+#include <platform/CHIPDeviceLayer.h>
+
+/**********************************************************
+ * Defines
+ *********************************************************/
+
+// Application-defined error codes in the CHIP_ERROR space.
+#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01)
+#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02)
+#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03)
+#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04)
+#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05)
+#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06)
+
+/**********************************************************
+ * AppTask Declaration
+ *********************************************************/
+class AppTask : public BaseApplication
+{
+
+public:
+ AppTask() = default;
+
+ static AppTask & GetAppTask() { return sAppTask; }
+
+ /**
+ * @brief AppTask task main loop function
+ *
+ * @param pvParameter FreeRTOS task parameter
+ */
+ static void AppTaskMain(void * pvParameter);
+
+ CHIP_ERROR StartAppTask();
+
+ /**
+ * @brief Request an update of the Air Quality Senor LCD UI
+ */
+ void UpdateAirQualitySensorUI();
+
+ /**
+ * @brief Event handler when a button is pressed
+ * Function posts an event for button processing
+ *
+ * @param buttonHandle APP_CONTROL_BUTTON or APP_FUNCTION_BUTTON
+ * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED,
+ * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED
+ */
+ static void ButtonEventHandler(uint8_t button, uint8_t btnAction);
+
+private:
+ static AppTask sAppTask;
+
+ /**
+ * @brief AppTask initialisation function
+ *
+ * @return CHIP_ERROR
+ */
+ CHIP_ERROR Init();
+
+ /**
+ * @brief PB0 Button event processing function
+ * Press and hold will trigger a factory reset timer start
+ * Press and release will restart BLEAdvertising if not commisionned
+ *
+ * @param aEvent button event being processed
+ */
+ static void ButtonHandler(AppEvent * aEvent);
+
+ static void AirQualitySensorActionEventHandler(AppEvent * aEvent);
+};
diff --git a/examples/air-quality-sensor-app/silabs/include/CHIPProjectConfig.h b/examples/air-quality-sensor-app/silabs/include/CHIPProjectConfig.h
new file mode 100644
index 0000000..f4e9709
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/CHIPProjectConfig.h
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * Copyright (c) 2019-2024 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * Example project configuration file for CHIP.
+ *
+ * This is a place to put application or project-specific overrides
+ * to the default configuration values for general CHIP features.
+ *
+ */
+
+#pragma once
+
+// Use a default pairing code if one hasn't been provisioned in flash.
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00
+#endif
+
+// For convenience, Chip Security Test Mode can be enabled and the
+// requirement for authentication in various protocols can be disabled.
+//
+// WARNING: These options make it possible to circumvent basic Chip security functionality,
+// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS.
+//
+#define CHIP_CONFIG_SECURITY_TEST_MODE 0
+
+/**
+ * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID
+ *
+ * 0xFFF1: Test vendor
+ */
+#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1
+
+/**
+ * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID
+ *
+ * 0x800E: example Air Quality Sensor app
+ */
+#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x800E
+
+/**
+ * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+ *
+ * Enable support for Chip-over-BLE (CHIPoBLE).
+ */
+#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1
+
+/**
+ * CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC
+ *
+ * Enables synchronizing the device's real time clock with a remote Chip Time service
+ * using the Chip Time Sync protocol.
+ */
+#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0
+
+/**
+ * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER
+ *
+ * Enables the use of a hard-coded default serial number if none
+ * is found in Chip NV storage.
+ */
+#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN"
+
+/**
+ * CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
+ *
+ * Enable recording UTC timestamps.
+ */
+#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1
+
+/**
+ * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE
+ *
+ * A size, in bytes, of the individual debug event logging buffer.
+ */
+#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512)
+
+/**
+ * @def CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL
+ *
+ * @brief
+ * Active retransmit interval, or time to wait before retransmission after
+ * subsequent failures in milliseconds.
+ *
+ * This is the default value, that might be adjusted by end device depending on its
+ * needs (e.g. sleeping period) using Service Discovery TXT record CRA key.
+ *
+ */
+#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL (2000_ms32)
diff --git a/examples/air-quality-sensor-app/silabs/include/SensorManager.h b/examples/air-quality-sensor-app/silabs/include/SensorManager.h
new file mode 100644
index 0000000..52b753c
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/include/SensorManager.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (c) 2019-2024 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "AppEvent.h"
+#include <cmsis_os2.h>
+#include <lib/core/CHIPError.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+class SensorManager
+{
+public:
+ CHIP_ERROR Init();
+ static SensorManager & SensorMgr() { return sSensorManager; }
+
+private:
+ SensorManager() = default;
+ ~SensorManager() = default;
+
+ osTimerId_t mSensorTimer;
+
+ // Reads new generated sensor value, stores it, and updates local Air Quality attribute
+ static void SensorTimerEventHandler(void * arg);
+
+ static SensorManager sSensorManager;
+};
diff --git a/examples/air-quality-sensor-app/silabs/openthread.gn b/examples/air-quality-sensor-app/silabs/openthread.gn
new file mode 100644
index 0000000..b05216f
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/openthread.gn
@@ -0,0 +1,29 @@
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/build.gni")
+
+# The location of the build configuration file.
+buildconfig = "${build_root}/config/BUILDCONFIG.gn"
+
+# CHIP uses angle bracket includes.
+check_system_includes = true
+
+default_args = {
+ target_cpu = "arm"
+ target_os = "freertos"
+ chip_openthread_ftd = true
+
+ import("//openthread.gni")
+}
diff --git a/examples/air-quality-sensor-app/silabs/openthread.gni b/examples/air-quality-sensor-app/silabs/openthread.gni
new file mode 100644
index 0000000..c6a8cbf
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/openthread.gni
@@ -0,0 +1,27 @@
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/chip.gni")
+import("${chip_root}/config/standalone/args.gni")
+import("${chip_root}/src/platform/silabs/efr32/args.gni")
+
+silabs_sdk_target = get_label_info(":sdk", "label_no_toolchain")
+
+app_data_model =
+ "${chip_root}/examples/air-quality-sensor-app/air-quality-sensor-common"
+chip_enable_ota_requestor = true
+chip_enable_openthread = true
+
+openthread_external_platform =
+ "${chip_root}/third_party/openthread/platforms/efr32:libopenthread-efr32"
diff --git a/examples/air-quality-sensor-app/silabs/src/AirQualitySensorUI.cpp b/examples/air-quality-sensor-app/silabs/src/AirQualitySensorUI.cpp
new file mode 100644
index 0000000..ee2ceb3
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/src/AirQualitySensorUI.cpp
@@ -0,0 +1,184 @@
+/*
+ *
+ * Copyright (c) 2024 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 <stdio.h>
+#include <string.h>
+
+#include "AirQualitySensorUI.h"
+#include "AppTask.h"
+#include "SensorManager.h"
+#include "demo-ui-bitmaps.h"
+#include "dmd.h"
+#include <air-quality-sensor-manager.h>
+#if DISPLAY_ENABLED
+#include "glib.h"
+#include "lcd.h"
+#endif
+
+using namespace chip::app::Clusters;
+using namespace chip::app::Clusters::AirQuality;
+
+namespace {
+// Bitmap
+const uint8_t silabsLogo[] = { SILABS_LOGO_SMALL };
+const uint8_t matterLogoBitmap[] = { MATTER_LOGO_BITMAP };
+
+const uint8_t wifiLogo[] = { WIFI_BITMAP };
+const uint8_t threadLogo[] = { THREAD_BITMAP };
+const uint8_t bleLogo[] = { BLUETOOTH_ICON_SMALL };
+
+const unsigned char monaco_48pt[] = { MONACO_48PT };
+
+#ifdef SL_WIFI
+constexpr bool UI_WIFI = true;
+#else
+constexpr bool UI_WIFI = false;
+#endif
+} // namespace
+
+void AirQualitySensorUI::DrawUI(GLIB_Context_t * glibContext)
+{
+ if (glibContext == nullptr)
+ {
+ ChipLogDetail(AppServer, "Context is null");
+ return;
+ }
+
+ GLIB_clear(glibContext);
+ DrawHeader(glibContext);
+ DrawCurrentAirQuality(glibContext);
+ DrawFooter(glibContext);
+
+#if SL_LCDCTRL_MUX
+ sl_wfx_host_pre_lcd_spi_transfer();
+#endif // SL_LCDCTRL_MUX
+ DMD_updateDisplay();
+#if SL_LCDCTRL_MUX
+ sl_wfx_host_post_lcd_spi_transfer();
+#endif // SL_LCDCTRL_MUX
+}
+
+void AirQualitySensorUI::DrawHeader(GLIB_Context_t * glibContext)
+{
+ // Draw Silabs Corner icon
+ GLIB_drawBitmap(glibContext, SILABS_ICON_POSITION_X, STATUS_ICON_LINE, SILABS_LOGO_WIDTH, SILABS_LOGO_HEIGHT, silabsLogo);
+ // Draw BLE Icon
+ GLIB_drawBitmap(glibContext, BLE_ICON_POSITION_X, STATUS_ICON_LINE, BLUETOOTH_ICON_SIZE, BLUETOOTH_ICON_SIZE, bleLogo);
+ // Draw WiFi/OpenThread Icon
+ GLIB_drawBitmap(glibContext, NETWORK_ICON_POSITION_X, STATUS_ICON_LINE, (UI_WIFI) ? WIFI_BITMAP_HEIGHT : THREAD_BITMAP_WIDTH,
+ WIFI_BITMAP_HEIGHT, (UI_WIFI) ? wifiLogo : threadLogo);
+ // Draw Matter Icon
+ GLIB_drawBitmap(glibContext, MATTER_ICON_POSITION_X, STATUS_ICON_LINE, MATTER_LOGO_WIDTH, MATTER_LOGO_HEIGHT, matterLogoBitmap);
+#if SL_LCDCTRL_MUX
+ sl_wfx_host_pre_lcd_spi_transfer();
+#endif // SL_LCDCTRL_MUX
+ DMD_updateDisplay();
+#if SL_LCDCTRL_MUX
+ sl_wfx_host_post_lcd_spi_transfer();
+#endif // SL_LCDCTRL_MUX
+}
+
+void AirQualitySensorUI::DrawFooter(GLIB_Context_t * glibContext)
+{
+ switch (AirQualitySensorManager::GetInstance()->GetAirQuality())
+ {
+ case AirQualityEnum::kGood:
+ GLIB_drawStringOnLine(glibContext, "AQ : Good", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ case AirQualityEnum::kFair:
+ GLIB_drawStringOnLine(glibContext, "AQ : Fair", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ case AirQualityEnum::kModerate:
+ GLIB_drawStringOnLine(glibContext, "AQ : Moderate", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ case AirQualityEnum::kPoor:
+ GLIB_drawStringOnLine(glibContext, "AQ : Poor", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ case AirQualityEnum::kVeryPoor:
+ GLIB_drawStringOnLine(glibContext, "AQ : VPoor", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ case AirQualityEnum::kExtremelyPoor:
+ GLIB_drawStringOnLine(glibContext, "AQ : EPoor", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ case AirQualityEnum::kUnknown:
+ GLIB_drawStringOnLine(glibContext, "AQ : Unknown", 11, GLIB_ALIGN_LEFT, 0, 0, true);
+ break;
+ default:
+ break;
+ }
+
+#if SL_LCDCTRL_MUX
+ sl_wfx_host_pre_lcd_spi_transfer();
+#endif // SL_LCDCTRL_MUX
+ DMD_updateDisplay();
+#if SL_LCDCTRL_MUX
+ sl_wfx_host_post_lcd_spi_transfer();
+#endif // SL_LCDCTRL_MUX
+}
+
+/**
+ * @brief Draw a 2 digit Air Quality of screen. Because of this Celsius is used by default
+ * @param GLIB_Context_t * pointer to the context for the GLIB library
+ * @param int8_t current Air Quality
+ */
+void AirQualitySensorUI::DrawCurrentAirQuality(GLIB_Context_t * glibContext)
+{
+ // LCD line define
+ constexpr uint8_t kAirQualityLcdInitialX = 30;
+ uint8_t position_x = 10;
+ uint8_t * data;
+ uint8_t print_val;
+
+ // Print Current air quality
+ print_val = 0;
+ data = (uint8_t *) &monaco_48pt[print_val * MONACO_FONT_NB_LENGTH];
+ DrawFont(glibContext, position_x, kAirQualityLcdInitialX, MONACO_FONT_WIDTH, data, MONACO_FONT_NB_LENGTH);
+ position_x += MONACO_FONT_WIDTH;
+
+ print_val = static_cast<uint8_t>(AirQualitySensorManager::GetInstance()->GetAirQuality());
+ data = (uint8_t *) &monaco_48pt[print_val * MONACO_FONT_NB_LENGTH];
+ DrawFont(glibContext, position_x, kAirQualityLcdInitialX, MONACO_FONT_WIDTH, data, MONACO_FONT_NB_LENGTH);
+}
+
+void AirQualitySensorUI::DrawFont(GLIB_Context_t * glibContext, uint8_t initial_x, uint8_t initial_y, uint8_t width, uint8_t * data,
+ uint32_t size)
+{
+ uint8_t x = initial_x, y = initial_y;
+ for (uint16_t i = 0; i < size; i++)
+ {
+ for (uint8_t mask = 0; mask < 8; mask++)
+ {
+ if (!(data[i] & (0x01 << mask)))
+ {
+ GLIB_drawPixel(glibContext, x, y);
+ }
+ // Check line changes
+ if (((x - initial_x) % width) == 0 && x != initial_x)
+ {
+ x = initial_x;
+ y++;
+ // Font is 8 bit align with paddings bits;
+ mask = 8;
+ }
+ else
+ {
+ x++;
+ }
+ }
+ }
+}
diff --git a/examples/air-quality-sensor-app/silabs/src/AppTask.cpp b/examples/air-quality-sensor-app/silabs/src/AppTask.cpp
new file mode 100644
index 0000000..572ec66
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/src/AppTask.cpp
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright (c) 2024 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.
+ */
+
+/**********************************************************
+ * Includes
+ *********************************************************/
+
+#include "AppTask.h"
+#include "AppConfig.h"
+#include "AppEvent.h"
+
+#include "LEDWidget.h"
+
+#ifdef DISPLAY_ENABLED
+#include "AirQualitySensorUI.h"
+#include "lcd.h"
+#ifdef QR_CODE_ENABLED
+#include "qrcodegen.h"
+#endif // QR_CODE_ENABLED
+#endif // DISPLAY_ENABLED
+
+#include <air-quality-sensor-manager.h>
+#include <app-common/zap-generated/attributes/Accessors.h>
+#include <app-common/zap-generated/callback.h>
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app/server/OnboardingCodesUtil.h>
+#include <app/server/Server.h>
+#include <app/util/attribute-storage.h>
+#include <assert.h>
+#include <lib/support/CodeUtils.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <platform/silabs/platformAbstraction/SilabsPlatform.h>
+#include <setup_payload/QRCodeSetupPayloadGenerator.h>
+#include <setup_payload/SetupPayload.h>
+
+/**********************************************************
+ * Defines and Constants
+ *********************************************************/
+
+#define APP_FUNCTION_BUTTON 0
+
+using namespace chip;
+using namespace chip::app;
+using namespace chip::TLV;
+using namespace chip::DeviceLayer;
+using namespace chip::app::Clusters::AirQuality;
+using namespace chip::app::Clusters;
+
+/**********************************************************
+ * AppTask Definitions
+ *********************************************************/
+
+AppTask AppTask::sAppTask;
+
+CHIP_ERROR AppTask::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(AppTask::ButtonEventHandler);
+#ifdef DISPLAY_ENABLED
+ GetLCD().Init((uint8_t *) "Air-Quality-Sensor");
+ GetLCD().SetCustomUI(AirQualitySensorUI::DrawUI);
+#endif
+
+ err = BaseApplication::Init();
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogDetail(AppServer, "BaseApplication::Init() failed");
+ appError(err);
+ }
+ err = SensorManager::SensorMgr().Init();
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogDetail(AppServer, "SensorMgr::Init() failed");
+ appError(err);
+ }
+
+ return err;
+}
+
+CHIP_ERROR AppTask::StartAppTask()
+{
+ return BaseApplication::StartAppTask(AppTaskMain);
+}
+
+void AppTask::AppTaskMain(void * pvParameter)
+{
+ AppEvent event;
+ osMessageQueueId_t sAppEventQueue = *(static_cast<osMessageQueueId_t *>(pvParameter));
+
+ CHIP_ERROR err = sAppTask.Init();
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogDetail(AppServer, "AppTask.Init() failed");
+ appError(err);
+ }
+
+#if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER)
+ sAppTask.StartStatusLEDTimer();
+#endif
+
+ ChipLogDetail(AppServer, "App Task started");
+ while (true)
+ {
+ osStatus_t eventReceived = osMessageQueueGet(sAppEventQueue, &event, NULL, osWaitForever);
+ while (eventReceived == osOK)
+ {
+ sAppTask.DispatchEvent(&event);
+ eventReceived = osMessageQueueGet(sAppEventQueue, &event, NULL, 0);
+ }
+ }
+}
+
+void AppTask::UpdateAirQualitySensorUI()
+{
+// Update the LCD with the Stored value. Show QR Code if not provisioned
+#ifdef DISPLAY_ENABLED
+ GetLCD().WriteDemoUI(false);
+#ifdef QR_CODE_ENABLED
+ if (BaseApplication::GetProvisionStatus())
+ {
+ GetLCD().ShowQRCode(true);
+ }
+#endif // QR_CODE_ENABLED
+#endif
+}
+
+void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction)
+{
+ AppEvent aEvent = {};
+ aEvent.Type = AppEvent::kEventType_Button;
+ aEvent.ButtonEvent.Action = btnAction;
+
+ if (button == APP_FUNCTION_BUTTON)
+ {
+ aEvent.Handler = BaseApplication::ButtonHandler;
+ sAppTask.PostEvent(&aEvent);
+ }
+}
diff --git a/examples/air-quality-sensor-app/silabs/src/SensorManager.cpp b/examples/air-quality-sensor-app/silabs/src/SensorManager.cpp
new file mode 100644
index 0000000..3b76450
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/src/SensorManager.cpp
@@ -0,0 +1,180 @@
+/*
+ *
+ * Copyright (c) 2024 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.
+ */
+
+/**********************************************************
+ * Includes
+ *********************************************************/
+
+#include "SensorManager.h"
+#include "AppConfig.h"
+#include "AppEvent.h"
+#include "AppTask.h"
+#include <AirQualityConfig.h>
+#include <air-quality-sensor-manager.h>
+
+#ifdef USE_AIR_QUALITY_SENSOR
+#include "AirQualitySensor.h"
+#endif
+/**********************************************************
+ * Defines and Constants
+ *********************************************************/
+
+using namespace chip;
+using namespace chip::DeviceLayer;
+using namespace chip::app::Clusters;
+using namespace chip::app::Clusters::AirQuality;
+
+/**********************************************************
+ * Variable declarations
+ *********************************************************/
+SensorManager SensorManager::sSensorManager;
+namespace {
+constexpr uint16_t kSensorTImerPeriodMs = 30000; // 30s timer period
+
+#ifndef USE_AIR_QUALITY_SENSOR
+constexpr uint16_t kSimulatedReadingFrequency =
+ (60000 / kSensorTImerPeriodMs); // for every two timer cycles, a simulated sensor update is triggered.
+int32_t mSimulatedAirQuality[] = { 5, 55, 105, 155, 205, 255, 305, 355, 400 };
+#endif
+
+} // namespace
+
+/**
+ * @brief Classifies the air quality based on a given sensor value.
+ *
+ * This function compares the input value against predefined thresholds
+ * defined in the AirQualityConfig.h file. The thresholds are used
+ * to classify the air quality into categories defined by the AirQualityEnum.
+ * The thresholds are defined in the SensorThresholds enum.
+ *
+ * @param value The sensor value used to classify air quality.
+ * @return AirQualityEnum The classified air quality category.
+ */
+AirQualityEnum classifyAirQuality(int32_t value)
+{
+ if (value < MIN_THRESHOLD)
+ {
+ return AirQualityEnum::kUnknown;
+ }
+ else if (value < GOOD_THRESHOLD)
+ {
+ return AirQualityEnum::kGood;
+ }
+ else if (value < FAIR_THRESHOLD)
+ {
+ return AirQualityEnum::kFair;
+ }
+ else if (value < MODERATE_THRESHOLD)
+ {
+ return AirQualityEnum::kModerate;
+ }
+ else if (value < POOR_THRESHOLD)
+ {
+ return AirQualityEnum::kPoor;
+ }
+ else if (value < VERY_POOR_THRESHOLD)
+ {
+ return AirQualityEnum::kVeryPoor;
+ }
+ else
+ {
+ return AirQualityEnum::kExtremelyPoor;
+ }
+}
+
+void InitAirQualitySensorManager(intptr_t arg)
+{
+ AirQualitySensorManager::InitInstance();
+}
+
+CHIP_ERROR SensorManager::Init()
+{
+ DeviceLayer::PlatformMgr().ScheduleWork(InitAirQualitySensorManager);
+ // Create cmsisos sw timer for air quality sensor timer.
+ mSensorTimer = osTimerNew(SensorTimerEventHandler, osTimerPeriodic, nullptr, nullptr);
+ if (mSensorTimer == NULL)
+ {
+ ChipLogDetail(AppServer, "mSensorTimer timer create failed");
+ return APP_ERROR_CREATE_TIMER_FAILED;
+ }
+
+#ifdef USE_AIR_QUALITY_SENSOR
+ if (SL_STATUS_OK != AirQualitySensor::Init())
+ {
+ ChipLogDetail(AppServer, "Failed to Init Sensor");
+ return CHIP_ERROR_INTERNAL;
+ }
+#endif
+ // Update Air Quality immediatly at bootup
+ SensorTimerEventHandler(nullptr);
+ // Trigger periodic update
+ uint32_t delayTicks = ((uint64_t) osKernelGetTickFreq() * kSensorTImerPeriodMs) / 1000;
+
+ // Starts or restarts the function timer
+ if (osTimerStart(mSensorTimer, delayTicks))
+ {
+ ChipLogDetail(AppServer, "mSensor Timer start() failed");
+ appError(APP_ERROR_START_TIMER_FAILED);
+ }
+ return CHIP_NO_ERROR;
+}
+
+void writeAirQualityToAttribute(intptr_t context)
+{
+ int32_t * air_quality_ptr = reinterpret_cast<int32_t *>(context);
+ AirQualitySensorManager::GetInstance()->OnAirQualityChangeHandler(classifyAirQuality(*air_quality_ptr));
+ ChipLogDetail(AppServer, "RAW AirQuality value: %ld and corresponding Enum value : %d", *air_quality_ptr,
+ chip::to_underlying(AirQualitySensorManager::GetInstance()->GetAirQuality()));
+ AppTask::GetAppTask().UpdateAirQualitySensorUI();
+ delete air_quality_ptr;
+}
+
+void SensorManager::SensorTimerEventHandler(void * arg)
+{
+ int32_t air_quality;
+#ifdef USE_AIR_QUALITY_SENSOR
+ if (SL_STATUS_OK != AirQualitySensor::GetAirQuality(air_quality))
+ {
+ ChipLogDetail(AppServer, "Failed to read Air Quality !!!");
+ return;
+ }
+#else
+ // Initialize static variables to keep track of the current index and repetition count
+ static uint8_t nbOfRepetition = 0;
+ static uint8_t simulatedIndex = 0;
+
+ // Ensure the simulatedIndex wraps around the array size to avoid out-of-bounds access
+ simulatedIndex = simulatedIndex % ArraySize(mSimulatedAirQuality);
+ // Retrieve the current air quality value from the simulated data array using the simulatedIndex
+ air_quality = mSimulatedAirQuality[simulatedIndex];
+
+ // Increment the repetition count
+ nbOfRepetition++;
+ // Check if the number of repetitions has reached the threshold to simulate a new reading
+ if (nbOfRepetition >= kSimulatedReadingFrequency)
+ {
+ // Move to the next index for the next simulated reading
+ simulatedIndex++;
+ // Reset the repetition count
+ nbOfRepetition = 0;
+ }
+#endif // USE_AIR_QUALITY_SENSOR
+ // create pointer for the int32_t air_quality
+ int32_t * air_quality_ptr = new int32_t(air_quality);
+ DeviceLayer::PlatformMgr().ScheduleWork(writeAirQualityToAttribute, reinterpret_cast<intptr_t>(air_quality_ptr));
+}
diff --git a/examples/air-quality-sensor-app/silabs/src/ZclCallbacks.cpp b/examples/air-quality-sensor-app/silabs/src/ZclCallbacks.cpp
new file mode 100644
index 0000000..5bd4dd3
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/src/ZclCallbacks.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright (c) 2024 Project CHIP Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * This file implements the handler for data model messages.
+ */
+
+#include "AppConfig.h"
+
+#include <air-quality-sensor-manager.h>
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/ConcreteAttributePath.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+#ifdef DIC_ENABLE
+#include "dic_control.h"
+#endif // DIC_ENABLE
+
+using namespace ::chip;
+using namespace ::chip::app::Clusters;
+
+void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
+ uint8_t * value)
+{
+ ClusterId clusterId = attributePath.mClusterId;
+ [[maybe_unused]] AttributeId attributeId = attributePath.mAttributeId;
+ ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId));
+
+ if (clusterId == Identify::Id)
+ {
+ ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u",
+ ChipLogValueMEI(attributeId), type, *value, size);
+ }
+}
diff --git a/examples/air-quality-sensor-app/silabs/third_party/connectedhomeip b/examples/air-quality-sensor-app/silabs/third_party/connectedhomeip
new file mode 120000
index 0000000..c866b86
--- /dev/null
+++ b/examples/air-quality-sensor-app/silabs/third_party/connectedhomeip
@@ -0,0 +1 @@
+../../../..
\ No newline at end of file
diff --git a/examples/platform/silabs/display/demo-ui-bitmaps.h b/examples/platform/silabs/display/demo-ui-bitmaps.h
index 2a46413..fd2fff5 100644
--- a/examples/platform/silabs/display/demo-ui-bitmaps.h
+++ b/examples/platform/silabs/display/demo-ui-bitmaps.h
@@ -136,4 +136,162 @@
#define OFF_DEMO_BITMAP ON_DEMO_BITMAP
#endif
+#define SILABS_LOGO_WIDTH 47
+#define SILABS_LOGO_HEIGHT 18
+#define BLUETOOTH_ICON_SIZE 18
+
+// Status Icon defines
+#define STATUS_ICON_LINE 0
+#define SILABS_ICON_POSITION_X 0
+#define BLE_ICON_POSITION_X 72
+#define NETWORK_ICON_POSITION_X 90
+#define MATTER_ICON_POSITION_X 108
+
+#define BLUETOOTH_ICON_SMALL \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0x7F, 0xFE, 0xEF, 0xF1, 0x7F, 0x9F, 0xFF, 0x7B, 0xFF, 0x1F, 0xFE, 0xFF, 0xFC, 0xFF, \
+ 0xF3, 0xFF, 0x87, 0xFF, 0xEF, 0xFD, 0xDF, 0xE7, 0xBF, 0xC7, 0xFF, 0x9F, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F
+
+#define SILABS_LOGO_SMALL \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, \
+ 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0x9F, 0xFF, 0xE7, 0x3F, 0xE0, 0xF1, 0x83, \
+ 0xFF, 0xF9, 0xEF, 0xFF, 0x3F, 0xE0, 0x3F, 0xFC, 0xFF, 0xFF, 0x7F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFE, 0x03, 0xFC, \
+ 0xFF, 0xF7, 0x9F, 0xFF, 0x81, 0x07, 0x02, 0xF8, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0xFE, 0xFF, 0xFF, 0xF8, 0x03, 0xC0, 0xFF, \
+ 0xFF, 0xFF, 0xFE, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x3F
+
+#define MONACO_FONT_WIDTH 29
+#define MONACO_FONT_NB_LENGTH 232
+#define MONACO_FONT_CH_LENGTH 50
+
+#define MONACO_48PT \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, \
+ 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x1F, 0x60, 0x00, 0xFF, 0x1F, 0xF8, 0x03, 0xFF, 0x0F, \
+ 0xFC, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFC, 0x07, 0xFF, 0x03, 0xFC, 0x03, 0xFF, 0x03, 0xFC, 0x03, \
+ 0xFF, 0x01, 0xF8, 0x83, 0xFF, 0x00, 0xF8, 0x83, 0xFF, 0x00, 0xF8, 0x83, 0x7F, 0x30, 0xF8, 0x83, 0x3F, 0x30, 0xF8, 0x83, \
+ 0x3F, 0x38, 0xF8, 0x81, 0x1F, 0x3C, 0xF8, 0x81, 0x0F, 0x3C, 0xF8, 0x81, 0x0F, 0x3E, 0xF8, 0x81, 0x07, 0x3E, 0xF8, 0x81, \
+ 0x07, 0x3F, 0xF8, 0x83, 0x83, 0x3F, 0xF8, 0x83, 0x81, 0x3F, 0xF8, 0x83, 0xC1, 0x3F, 0xF8, 0x83, 0xE0, 0x1F, 0xF8, 0x03, \
+ 0xE0, 0x1F, 0xF8, 0x03, 0xF0, 0x1F, 0xF8, 0x03, 0xF8, 0x1F, 0xFC, 0x07, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x0F, 0xFC, 0x07, \
+ 0xFC, 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFE, 0x0F, 0xF8, 0x03, 0xFF, 0x1F, 0xE0, 0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x7F, \
+ 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x30 (48: '0')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0xFC, 0xFF, \
+ 0x1F, 0x00, 0xFC, 0xFF, 0x0F, 0x10, 0xFC, 0xFF, 0x0F, 0x1C, 0xFC, 0xFF, 0x0F, 0x1E, 0xFC, 0xFF, 0xCF, 0x1F, 0xFC, 0xFF, \
+ 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \
+ 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \
+ 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \
+ 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, \
+ 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, \
+ 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x31 (49: '1')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, \
+ 0x3F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xF8, 0x00, 0xFF, 0x0F, 0xFF, 0x03, 0xFE, \
+ 0xEF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, \
+ 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, \
+ 0xFF, 0x7F, 0xC0, 0xFF, 0xFF, 0x3F, 0xE0, 0xFF, 0xFF, 0x1F, 0xF0, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, \
+ 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, \
+ 0x3F, 0xF0, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, \
+ 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xFC, \
+ 0x07, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x32 (50: '2')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, \
+ 0x0F, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x7C, 0x80, 0xFF, 0x8F, 0xFF, 0x01, 0xFF, \
+ 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, \
+ 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x7F, 0xC0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, \
+ 0x7F, 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0xE0, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, \
+ 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \
+ 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \
+ 0xFF, 0xFF, 0x07, 0xFE, 0xF7, 0xFF, 0x07, 0xFE, 0x87, 0xFF, 0x01, 0xFF, 0x07, 0x7C, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0xFF, \
+ 0x07, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x33 (51: '3')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x3F, 0xE0, 0xFF, 0xFF, 0x1F, 0xE0, 0xFF, \
+ 0xFF, 0x1F, 0xE0, 0xFF, 0xFF, 0x0F, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x83, 0xE0, 0xFF, \
+ 0xFF, 0x81, 0xE0, 0xFF, 0xFF, 0xC0, 0xE0, 0xFF, 0xFF, 0xE0, 0xE0, 0xFF, 0x7F, 0xE0, 0xE0, 0xFF, 0x3F, 0xF0, 0xE0, 0xFF, \
+ 0x3F, 0xF8, 0xE0, 0xFF, 0x1F, 0xF8, 0xE0, 0xFF, 0x0F, 0xFC, 0xE0, 0xFF, 0x0F, 0xFE, 0xE0, 0xFF, 0x07, 0xFE, 0xE0, 0xFF, \
+ 0x03, 0xFF, 0xE0, 0xFF, 0x83, 0xFF, 0xE0, 0xFF, 0x81, 0xFF, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF0, \
+ 0x01, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, \
+ 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, \
+ 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x34 (52: '4')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, \
+ 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, \
+ 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xC0, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, \
+ 0x0F, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, \
+ 0xFF, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \
+ 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, \
+ 0xFF, 0xFF, 0x07, 0xFE, 0xEF, 0xFF, 0x03, 0xFE, 0x07, 0xFF, 0x00, 0xFF, 0x07, 0x00, 0x80, 0xFF, 0x07, 0x00, 0xC0, 0xFF, \
+ 0x07, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x35 (53: '5')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xC0, 0xFF, \
+ 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0x7F, 0x80, 0x07, 0xFE, 0x3F, 0xE0, 0x7F, 0xFE, \
+ 0x1F, 0xF0, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, \
+ 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x03, 0x0F, 0xE0, 0xFF, \
+ 0x83, 0x03, 0x80, 0xFF, 0x83, 0x01, 0x00, 0xFF, 0x83, 0x00, 0x00, 0xFE, 0x03, 0xC0, 0x07, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, \
+ 0x03, 0xF8, 0x1F, 0xF8, 0x03, 0xFC, 0x3F, 0xF8, 0x03, 0xFC, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, \
+ 0x07, 0xFE, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, 0x07, 0xFE, 0x3F, 0xF8, 0x0F, 0xFE, 0x3F, 0xF8, 0x0F, 0xFC, 0x1F, 0xF8, \
+ 0x0F, 0xFC, 0x1F, 0xFC, 0x1F, 0xF8, 0x0F, 0xFC, 0x1F, 0xF0, 0x07, 0xFE, 0x3F, 0xC0, 0x01, 0xFE, 0x7F, 0x00, 0x00, 0xFF, \
+ 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x36 (54: '6')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, \
+ 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x0F, 0xFE, \
+ 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, \
+ 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x3F, 0xF0, 0xFF, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, \
+ 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, \
+ 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, \
+ 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xE0, 0xFF, 0xFF, 0x7F, 0xF0, 0xFF, 0xFF, \
+ 0x7F, 0xF0, 0xFF, 0xFF, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x37 (55: '7')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, \
+ 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0xE0, 0x00, 0xFF, 0x3F, 0xF8, 0x03, 0xFF, \
+ 0x1F, 0xFC, 0x07, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x1F, 0xFC, 0x07, 0xFE, \
+ 0x1F, 0xF8, 0x07, 0xFF, 0x3F, 0xF0, 0x03, 0xFF, 0x3F, 0xE0, 0x81, 0xFF, 0x7F, 0xC0, 0x80, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, \
+ 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, \
+ 0x3F, 0x60, 0x80, 0xFF, 0x1F, 0xF0, 0x00, 0xFF, 0x1F, 0xF8, 0x01, 0xFE, 0x0F, 0xFC, 0x03, 0xFE, 0x0F, 0xFC, 0x07, 0xFC, \
+ 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFF, 0x1F, 0xFC, 0x07, 0xFF, 0x1F, 0xFC, 0x07, 0xFF, 0x1F, 0xFC, \
+ 0x07, 0xFE, 0x0F, 0xFC, 0x07, 0xFC, 0x0F, 0xFC, 0x0F, 0xF8, 0x07, 0xFE, 0x0F, 0xE0, 0x01, 0xFE, 0x1F, 0x00, 0x00, 0xFF, \
+ 0x3F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x38 (56: '8')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFE, 0xFF, \
+ 0xFF, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0xC0, 0xFF, 0x0F, 0x70, 0x80, 0xFF, 0x07, 0xFC, 0x01, 0xFF, \
+ 0x07, 0xFE, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x83, 0xFF, 0x07, 0xFE, 0x83, 0xFF, 0x0F, 0xFC, \
+ 0xC1, 0xFF, 0x0F, 0xFC, 0xC1, 0xFF, 0x0F, 0xFC, 0xC1, 0xFF, 0x0F, 0xFC, 0x83, 0xFF, 0x07, 0xFC, 0x83, 0xFF, 0x07, 0xFC, \
+ 0x83, 0xFF, 0x07, 0xFC, 0x03, 0xFF, 0x03, 0xF8, 0x03, 0xFE, 0x01, 0xF8, 0x07, 0x7C, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF8, \
+ 0x1F, 0x00, 0x10, 0xF8, 0x3F, 0x00, 0x1C, 0xFC, 0xFF, 0x00, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFC, \
+ 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, \
+ 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xCF, 0xFF, 0x80, 0xFF, 0x0F, 0x3E, 0xC0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, \
+ 0x0F, 0x00, 0xF0, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x39 (57: '9')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0x1F, 0xE0, 0x0F, 0xE3, 0xC7, 0xFF, \
+ 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0xC3, 0xFF, 0x87, 0xEF, 0x0F, 0xE0, 0x1F, 0xE0, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x63 (99: 'c')*/ \
+ 0xFF, 0xFB, 0x7F, 0xC0, 0x3F, 0xC0, 0x1F, 0xFF, 0x1F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x03, 0xF0, 0x03, 0xF0, \
+ 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, 0x9F, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x66 (102: 'f')*/ \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xDD, 0xFF, 0xDD, 0xFF, 0xDD, 0xFF, 0xE3, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Character 0x20 (32: 'degree')*/
+
#endif // SILABS_DEMO_UI_BITMAPS_H
diff --git a/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp b/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp
new file mode 100644
index 0000000..43c5a55
--- /dev/null
+++ b/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright (c) 2024 Project CHIP Authors
+ * Copyright (c) 2024 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AirQualitySensor.h"
+#include "sl_board_control.h"
+#include <platform/CHIPDeviceLayer.h>
+
+#ifdef USE_SPARKFUN_AIR_QUALITY_SENSOR
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <sparkfun_sgp40.h>
+#include <sparkfun_sgp40_i2c.h>
+}
+#include "sl_i2cspm_instances.h"
+#endif // USE_SPARKFUN_AIR_QUALITY_SENSOR
+
+namespace {
+bool initialized = false;
+}
+
+namespace AirQualitySensor {
+
+/**
+ * @brief Initializes the air quality sensor.
+ *
+ * This function initializes the air quality sensor, specifically supporting the SparkFun SGP40 air quality sensor.
+ * It uses the I2C protocol for communication and sets up the VOC (Volatile Organic Compounds) algorithm for air quality
+ * measurement.
+ *
+ * @note If the macro USE_SPARKFUN_AIR_QUALITY_SENSOR is defined, the SparkFun SGP40 sensor is initialized.
+ * If initialization is successful, the function returns SL_STATUS_OK, indicating the sensor is ready for use.
+ * If the initialization fails, it returns SL_STATUS_FAIL. If USE_SPARKFUN_AIR_QUALITY_SENSOR is not defined,
+ * it is expected that the user provides an implementation for their specific air quality sensor.
+ *
+ * @return sl_status_t Returns SL_STATUS_OK if the initialization is successful, otherwise returns SL_STATUS_FAIL.
+ */
+
+sl_status_t Init()
+{
+ sl_status_t status = SL_STATUS_FAIL;
+
+#ifdef USE_SPARKFUN_AIR_QUALITY_SENSOR
+ status = sparkfun_sgp40_init(sl_i2cspm_qwiic);
+ VerifyOrReturnError(status == SL_STATUS_OK, SL_STATUS_FAIL);
+ initialized = true;
+
+ sparkfun_sgp40_voc_algorithm_init();
+
+#else
+// User implementation of Init
+#endif // USE_SPARKFUN_AIR_QUALITY_SENSOR
+
+ return status;
+}
+
+/**
+ * @brief Retrieves the air quality measurement.
+ *
+ * This function fetches the current air quality measurement from the air quality sensor. It is designed to work
+ * with the SparkFun SGP40 air quality sensor when the USE_SPARKFUN_AIR_QUALITY_SENSOR macro is defined. The function
+ * calculates the VOC (Volatile Organic Compounds) index, which is used as a measure of air quality.
+ *
+ * @note The function requires the sensor to be initialized before calling. If the sensor is not initialized,
+ * SL_STATUS_NOT_INITIALIZED is returned. For the SparkFun SGP40 sensor, the function uses hardcoded
+ * values for humidity and temperature (50% and 25°C, respectively) as part of the VOC index calculation.
+ * It is recommended to replace these magic numbers with actual sensor readings.
+ *
+ * @param air_quality A pointer to an integer where the air quality measurement will be stored.
+ *
+ * @return sl_status_t Returns SL_STATUS_OK if the air quality measurement is successfully retrieved,
+ * SL_STATUS_NOT_INITIALIZED if the sensor has not been initialized, or other error codes as defined.
+ */
+
+sl_status_t GetAirQuality(int32_t & air_quality)
+{
+ sl_status_t status = SL_STATUS_FAIL;
+ VerifyOrReturnError(initialized, SL_STATUS_NOT_INITIALIZED);
+
+#ifdef USE_SPARKFUN_AIR_QUALITY_SENSOR
+ constexpr float relativeHumidity = 50; // 50%
+ constexpr float temperature = 25; // 25°C
+
+ status = sparkfun_sgp40_get_voc_index(&air_quality, relativeHumidity, temperature);
+ VerifyOrReturnError(status == SL_STATUS_OK, status);
+
+#else
+ // User implementation of GetAirQuality
+#endif // USE_SPARKFUN_AIR_QUALITY_SENSOR
+
+ return status;
+}
+}; // namespace AirQualitySensor
diff --git a/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.h b/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.h
new file mode 100644
index 0000000..0ec2b9b
--- /dev/null
+++ b/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * Copyright (c) 2024 Project CHIP Authors
+ * Copyright (c) 2024 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sl_status.h>
+#include <stdint.h>
+
+namespace AirQualitySensor {
+sl_status_t Init();
+sl_status_t GetAirQuality(int32_t & air_quality);
+}; // namespace AirQualitySensor
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index 5f230e7..8d1b302 100755
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -267,7 +267,8 @@
TargetPart('light', app=Efr32App.LIGHT),
TargetPart('lock', app=Efr32App.LOCK),
TargetPart('thermostat', app=Efr32App.THERMOSTAT),
- TargetPart('pump', app=Efr32App.PUMP)
+ TargetPart('pump', app=Efr32App.PUMP),
+ TargetPart('air-quality-sensor-app', app=Efr32App.AIR_QUALITY_SENSOR)
])
target.AppendModifier('rpc', enable_rpcs=True)
diff --git a/scripts/build/builders/efr32.py b/scripts/build/builders/efr32.py
index 3c15cd4..0ca8649 100644
--- a/scripts/build/builders/efr32.py
+++ b/scripts/build/builders/efr32.py
@@ -31,6 +31,7 @@
THERMOSTAT = auto()
PUMP = auto()
UNIT_TEST = auto()
+ AIR_QUALITY_SENSOR = auto()
def ExampleName(self):
if self == Efr32App.LIGHT:
@@ -45,6 +46,8 @@
return 'thermostat'
elif self == Efr32App.PUMP:
return 'pump-app'
+ elif self == Efr32App.AIR_QUALITY_SENSOR:
+ return 'air-quality-sensor-app'
else:
raise Exception('Unknown app type: %r' % self)
@@ -63,6 +66,8 @@
return 'matter-silabs-pump-example'
elif self == Efr32App.UNIT_TEST:
return 'matter-silabs-device_tests'
+ elif self == Efr32App.AIR_QUALITY_SENSOR:
+ return 'matter-silabs-air-quality-sensor-example'
else:
raise Exception('Unknown app type: %r' % self)
@@ -81,6 +86,8 @@
return 'pump_app.flashbundle.txt'
elif self == Efr32App.UNIT_TEST:
return os.path.join('tests', 'efr32_device_tests.flashbundle.txt')
+ elif self == Efr32App.AIR_QUALITY_SENSOR:
+ return 'air_quality_sensor_app.flashbundle.txt'
else:
raise Exception('Unknown app type: %r' % self)
diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt
index 4ace53b..93e375c 100644
--- a/scripts/build/testdata/all_targets_linux_x64.txt
+++ b/scripts/build/testdata/all_targets_linux_x64.txt
@@ -5,7 +5,7 @@
cc32xx-{lock,air-purifier}
ti-cc13x4_26x4-{lighting,lock,pump,pump-controller}[-mtd][-ftd]
cyw30739-{cyw30739b2_p5_evk_01,cyw30739b2_p5_evk_02,cyw30739b2_p5_evk_03,cyw930739m2evb_01,cyw930739m2evb_02}-{light,light-switch,lock,thermostat}
-efr32-{brd2704b,brd4316a,brd4317a,brd4318a,brd4319a,brd4186a,brd4187a,brd2601b,brd4187c,brd4186c,brd2703a,brd4338a,brd2605a}-{window-covering,switch,unit-test,light,lock,thermostat,pump}[-rpc][-with-ota-requestor][-icd][-low-power][-shell][-no-logging][-openthread-mtd][-heap-monitoring][-no-openthread-cli][-show-qr-code][-wifi][-rs9116][-wf200][-siwx917][-ipv4][-additional-data-advertising][-use-ot-lib][-use-ot-coap-lib][-no-version][-skip-rps-generation]
+efr32-{brd2704b,brd4316a,brd4317a,brd4318a,brd4319a,brd4186a,brd4187a,brd2601b,brd4187c,brd4186c,brd2703a,brd4338a,brd2605a}-{window-covering,switch,unit-test,light,lock,thermostat,pump,air-quality-sensor-app}[-rpc][-with-ota-requestor][-icd][-low-power][-shell][-no-logging][-openthread-mtd][-heap-monitoring][-no-openthread-cli][-show-qr-code][-wifi][-rs9116][-wf200][-siwx917][-ipv4][-additional-data-advertising][-use-ot-lib][-use-ot-coap-lib][-no-version][-skip-rps-generation]
esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing][-data-model-disabled][-data-model-enabled]
genio-lighting-app
linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang]