diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml index 366cf0857a484a..59bbf0e7398547 100644 --- a/.github/workflows/examples-telink.yaml +++ b/.github/workflows/examples-telink.yaml @@ -72,6 +72,15 @@ jobs: out/telink-tlsr9518adk80d-all-clusters-minimal/zephyr/zephyr.elf \ /tmp/bloat_reports/ + - name: Build example Telink Contact Sensor App + run: | + ./scripts/run_in_build_env.sh \ + "./scripts/build/build_examples.py --no-log-timestamps --target 'telink-tlsr9518adk80d-contact-sensor' build" + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + telink tlsr9518adk80d contact-sensor-app \ + out/telink-tlsr9518adk80d-contact-sensor/zephyr/zephyr.elf \ + /tmp/bloat_reports/ + - name: Build example Telink Lighting App run: | ./scripts/run_in_build_env.sh \ @@ -99,6 +108,15 @@ jobs: out/telink-tlsr9518adk80d-ota-requestor/zephyr/zephyr.elf \ /tmp/bloat_reports/ + - name: Build example Telink Thermostat App + run: | + ./scripts/run_in_build_env.sh \ + "./scripts/build/build_examples.py --no-log-timestamps --target 'telink-tlsr9518adk80d-thermostat' build" + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + telink tlsr9518adk80d thermostat \ + out/telink-tlsr9518adk80d-thermostat/zephyr/zephyr.elf \ + /tmp/bloat_reports/ + - name: Uploading Size Reports uses: actions/upload-artifact@v2 if: ${{ !env.ACT }} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c65b2ad9bd4915..5717b2302c57ca 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -443,9 +443,11 @@ "qpg-qpg6100-lock", "telink-tlsr9518adk80d-all-clusters", "telink-tlsr9518adk80d-all-clusters-minimal", + "telink-tlsr9518adk80d-contact-sensor", "telink-tlsr9518adk80d-light", "telink-tlsr9518adk80d-light-switch", "telink-tlsr9518adk80d-ota-requestor", + "telink-tlsr9518adk80d-thermostat", "tizen-arm-light" ] }, diff --git a/config/telink/app/zephyr.conf b/config/telink/app/zephyr.conf index c83f5aeccca9c4..bd920eff8b4d49 100644 --- a/config/telink/app/zephyr.conf +++ b/config/telink/app/zephyr.conf @@ -106,5 +106,6 @@ CONFIG_DYNAMIC_INTERRUPTS=y # nvs_sector_size = flash_page_size * mult = 256 * 8 = 2048 CONFIG_SETTINGS_NVS_SECTOR_SIZE_MULT=8 -# Shall settings +# Shell settings +CONFIG_SHELL=n CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=255 \ No newline at end of file diff --git a/examples/all-clusters-app/telink/include/AppEvent.h b/examples/all-clusters-app/telink/include/AppEvent.h index 000f3e8653d3ff..54250995e06ca8 100644 --- a/examples/all-clusters-app/telink/include/AppEvent.h +++ b/examples/all-clusters-app/telink/include/AppEvent.h @@ -23,11 +23,15 @@ struct AppEvent; typedef void (*EventHandler)(AppEvent *); +class LEDWidget; + struct AppEvent { enum AppEventTypes { kEventType_Button = 0, + kEventType_Timer, + kEventType_UpdateLedState, }; uint16_t Type; @@ -38,6 +42,14 @@ struct AppEvent { uint8_t Action; } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; }; EventHandler Handler; diff --git a/examples/all-clusters-app/telink/include/AppTask.h b/examples/all-clusters-app/telink/include/AppTask.h index d893794235fb47..7787968458b867 100644 --- a/examples/all-clusters-app/telink/include/AppTask.h +++ b/examples/all-clusters-app/telink/include/AppTask.h @@ -19,6 +19,7 @@ #pragma once #include "AppEvent.h" +#include "LEDWidget.h" #include @@ -43,15 +44,20 @@ class AppTask void DispatchEvent(AppEvent * event); static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); static void FactoryResetButtonEventHandler(void); static void StartThreadButtonEventHandler(void); static void StartBleAdvButtonEventHandler(void); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); static void FactoryResetHandler(AppEvent * aEvent); static void StartThreadHandler(AppEvent * aEvent); static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); static void InitButtons(void); diff --git a/examples/all-clusters-app/telink/src/AppTask.cpp b/examples/all-clusters-app/telink/src/AppTask.cpp index f0daf281889d5f..e9ea05c2d86f22 100644 --- a/examples/all-clusters-app/telink/src/AppTask.cpp +++ b/examples/all-clusters-app/telink/src/AppTask.cpp @@ -21,7 +21,6 @@ #include "AppConfig.h" #include "AppEvent.h" #include "ButtonManager.h" -#include "LEDWidget.h" #include "binding-handler.h" #include #include @@ -49,12 +48,13 @@ LOG_MODULE_DECLARE(app); namespace { - -constexpr int kAppEventQueueSize = 10; -constexpr uint8_t kButtonPushEvent = 1; -constexpr uint8_t kButtonReleaseEvent = 0; +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; LEDWidget sStatusLED; @@ -62,10 +62,11 @@ Button sFactoryResetButton; Button sThreadStartButton; Button sBleAdvStartButton; -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -bool sIsThreadAttached = false; -bool sHaveBLEConnections = false; +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; @@ -120,12 +121,17 @@ CHIP_ERROR AppTask::Init() // Initialize status LED LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(SYSTEM_STATE_LED_PIN); UpdateStatusLED(); InitButtons(); + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + // Init ZCL Data Model and start server static chip::CommonCaseDeviceServerInitParams initParams; (void) initParams.InitializeStaticResourcesBeforeServerInit(); @@ -194,8 +200,6 @@ CHIP_ERROR AppTask::StartApp() DispatchEvent(&event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - sStatusLED.Animate(); } } @@ -211,8 +215,16 @@ void AppTask::FactoryResetButtonEventHandler(void) void AppTask::FactoryResetHandler(AppEvent * aEvent) { - LOG_INF("Factory Reset triggered."); - chip::Server::GetInstance().ScheduleFactoryReset(); + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } } void AppTask::StartThreadButtonEventHandler(void) @@ -275,6 +287,23 @@ void AppTask::StartBleAdvHandler(AppEvent * aEvent) } } +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + void AppTask::UpdateStatusLED() { if (sIsThreadProvisioned && sIsThreadEnabled) @@ -345,11 +374,36 @@ void AppTask::DispatchEvent(AppEvent * aEvent) } } +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + void AppTask::InitButtons(void) { - sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, FactoryResetButtonEventHandler); - sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, StartThreadButtonEventHandler); - sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, StartBleAdvButtonEventHandler); + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, false, StartThreadButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); ButtonManagerInst().AddButton(sFactoryResetButton); ButtonManagerInst().AddButton(sThreadStartButton); diff --git a/examples/all-clusters-minimal-app/telink/include/AppEvent.h b/examples/all-clusters-minimal-app/telink/include/AppEvent.h index 000f3e8653d3ff..54250995e06ca8 100644 --- a/examples/all-clusters-minimal-app/telink/include/AppEvent.h +++ b/examples/all-clusters-minimal-app/telink/include/AppEvent.h @@ -23,11 +23,15 @@ struct AppEvent; typedef void (*EventHandler)(AppEvent *); +class LEDWidget; + struct AppEvent { enum AppEventTypes { kEventType_Button = 0, + kEventType_Timer, + kEventType_UpdateLedState, }; uint16_t Type; @@ -38,6 +42,14 @@ struct AppEvent { uint8_t Action; } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; }; EventHandler Handler; diff --git a/examples/all-clusters-minimal-app/telink/include/AppTask.h b/examples/all-clusters-minimal-app/telink/include/AppTask.h index d6a02734a40e74..7d0168759055d0 100644 --- a/examples/all-clusters-minimal-app/telink/include/AppTask.h +++ b/examples/all-clusters-minimal-app/telink/include/AppTask.h @@ -19,6 +19,7 @@ #pragma once #include "AppEvent.h" +#include "LEDWidget.h" #include @@ -43,13 +44,18 @@ class AppTask void DispatchEvent(AppEvent * event); static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); static void FactoryResetButtonEventHandler(void); static void StartBleAdvButtonEventHandler(void); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); static void FactoryResetHandler(AppEvent * aEvent); static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); static void InitButtons(void); diff --git a/examples/all-clusters-minimal-app/telink/src/AppTask.cpp b/examples/all-clusters-minimal-app/telink/src/AppTask.cpp index a08d81bf5b1a39..0a78a3073f763e 100644 --- a/examples/all-clusters-minimal-app/telink/src/AppTask.cpp +++ b/examples/all-clusters-minimal-app/telink/src/AppTask.cpp @@ -21,7 +21,6 @@ #include "AppConfig.h" #include "AppEvent.h" #include "ButtonManager.h" -#include "LEDWidget.h" #include "binding-handler.h" #include #include @@ -46,22 +45,24 @@ LOG_MODULE_DECLARE(app); namespace { - -constexpr int kAppEventQueueSize = 10; -constexpr uint8_t kButtonPushEvent = 1; -constexpr uint8_t kButtonReleaseEvent = 0; +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; LEDWidget sStatusLED; Button sFactoryResetButton; Button sBleAdvStartButton; -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -bool sIsThreadAttached = false; -bool sHaveBLEConnections = false; +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; } // namespace @@ -83,12 +84,17 @@ CHIP_ERROR AppTask::Init() // Initialize status LED LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(SYSTEM_STATE_LED_PIN); UpdateStatusLED(); InitButtons(); + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + // Init ZCL Data Model and start server static chip::CommonCaseDeviceServerInitParams initParams; (void) initParams.InitializeStaticResourcesBeforeServerInit(); @@ -154,8 +160,6 @@ CHIP_ERROR AppTask::StartApp() DispatchEvent(&event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - sStatusLED.Animate(); } } @@ -171,8 +175,16 @@ void AppTask::FactoryResetButtonEventHandler(void) void AppTask::FactoryResetHandler(AppEvent * aEvent) { - LOG_INF("Factory Reset triggered."); - chip::Server::GetInstance().ScheduleFactoryReset(); + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } } void AppTask::StartBleAdvButtonEventHandler(void) @@ -208,6 +220,23 @@ void AppTask::StartBleAdvHandler(AppEvent * aEvent) } } +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + void AppTask::UpdateStatusLED() { if (sIsThreadProvisioned && sIsThreadEnabled) @@ -278,10 +307,35 @@ void AppTask::DispatchEvent(AppEvent * aEvent) } } +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + void AppTask::InitButtons(void) { - sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, FactoryResetButtonEventHandler); - sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, StartBleAdvButtonEventHandler); + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); ButtonManagerInst().AddButton(sFactoryResetButton); ButtonManagerInst().AddButton(sBleAdvStartButton); diff --git a/examples/contact-sensor-app/telink/.gitignore b/examples/contact-sensor-app/telink/.gitignore new file mode 100644 index 00000000000000..84c048a73cc2e5 --- /dev/null +++ b/examples/contact-sensor-app/telink/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/examples/contact-sensor-app/telink/CMakeLists.txt b/examples/contact-sensor-app/telink/CMakeLists.txt new file mode 100755 index 00000000000000..c9deb365f165d2 --- /dev/null +++ b/examples/contact-sensor-app/telink/CMakeLists.txt @@ -0,0 +1,67 @@ +# +# Copyright (c) 2022 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +cmake_minimum_required(VERSION 3.13.1) + +set(BOARD tlsr9518adk80d) + +get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH) +get_filename_component(NLIO_ROOT ${CHIP_ROOT}/third_party/nlio/repo/include REALPATH) +get_filename_component(TELINK_COMMON ${CHIP_ROOT}/examples/platform/telink REALPATH) +get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH) + +set(CONF_FILE ${CHIP_ROOT}/config/telink/app/zephyr.conf prj.conf) + +# Load NCS/Zephyr build system +list(APPEND ZEPHYR_EXTRA_MODULES ${CHIP_ROOT}/config/telink/chip-module) +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) + +project(chip-telink-contact-sensor-example) + +include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake) +include(${CHIP_ROOT}/src/app/chip_data_model.cmake) + +target_compile_options(app PRIVATE -fpermissive) + +target_include_directories(app PRIVATE + include + ${GEN_DIR}/app-common + ${GEN_DIR}/contact-sensor-app + ${NLIO_ROOT} + ${TELINK_COMMON}/util/include) + +add_definitions( + "-DCHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER=" +) + +target_sources(app PRIVATE + src/AppTask.cpp + src/ContactSensorManager.cpp + src/main.cpp + src/ZclCallbacks.cpp + ${GEN_DIR}/thermostat/zap-generated/callback-stub.cpp + ${GEN_DIR}/contact-sensor-app/zap-generated/IMClusterCommandHandler.cpp + ${TELINK_COMMON}/util/src/LEDWidget.cpp + ${TELINK_COMMON}/util/src/ButtonManager.cpp + ${TELINK_COMMON}/util/src/ThreadUtil.cpp) + +chip_configure_data_model(app + INCLUDE_SERVER + ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../contact-sensor-common/contact-sensor-app.zap +) + +if(CONFIG_CHIP_OTA_REQUESTOR) + target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp) +endif() diff --git a/examples/contact-sensor-app/telink/Readme.md b/examples/contact-sensor-app/telink/Readme.md new file mode 100755 index 00000000000000..31b004dd7aaa5b --- /dev/null +++ b/examples/contact-sensor-app/telink/Readme.md @@ -0,0 +1,159 @@ +# Matter Telink Contact Sensor Example Application + +You can use this example as a reference for creating your own application. + +![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) + +## Build and flash + +1. Pull docker image from repository: + + ```bash + $ docker pull connectedhomeip/chip-build-telink:latest + ``` + +1. Run docker container: + + ```bash + $ docker run -it --rm -v ${CHIP_BASE}:/root/chip -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" connectedhomeip/chip-build-telink:latest + ``` + + here `${CHIP_BASE}` is directory which contains CHIP repo files **!!!Pay + attention that OUTPUT_DIR should contains ABSOLUTE path to output dir** + +1. Activate the build environment: + + ```bash + $ source ./scripts/activate.sh + ``` + +1. In the example dir run: + + ```bash + $ west build + ``` + +1. Flash binary: + + ``` + $ west flash --erase + ``` + +## Usage + +### UART + +To get output from device, connect UART to following pins: + +| Name | Pin | +| :--: | :---------------------------- | +| RX | PB3 (pin 17 of J34 connector) | +| TX | PB2 (pin 16 of J34 connector) | +| GND | GND | + +### Buttons + +The following buttons are available on **tlsr9518adk80d** board: + +| Name | Function | Description | +| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | +| Button 2 | Toggle Contact State | Manually triggers the Contact Sensor State | +| Button 3 | NA | NA | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | + +### LEDs + +**Red** LED indicates current state of Thread network. It ables to be in +following states: + +| State | Description | +| :-------------------------- | :--------------------------------------------------------------------------- | +| Blinks with short pulses | Device is not commissioned to Thread, Thread is disabled | +| Blinls with frequent pulses | Device is commissioned, Thread enabled. Device trying to JOIN thread network | +| Blinks with whde pulses | Device commissioned and joined to thread network as CHILD | + +**Blue** LED shows current state of Contact Sensor + +### CHIP tool commands + +1. Build + [chip-tool cli](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) + +2. Pair with device + + ``` + ${CHIP_TOOL_DIR}/chip-tool pairing ble-thread ${NODE_ID} hex:${DATASET} ${PIN_CODE} ${DISCRIMINATOR} + ``` + + Example: + + ``` + ./chip-tool pairing ble-thread 1234 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd61f77bd3df233e051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f010212340410445f2b5ca6f2a93a55ce570a70efeecb0c0402a0fff8 20202021 3840 + ``` + +### OTA with Linux OTA Provider + +OTA feature enabled by default only for ota-requestor-app example. To enable OTA +feature for another Telink example: + +- set CONFIG_CHIP_OTA_REQUESTOR=y in corresponding "prj.conf" configuration + file. + +After build application with enabled OTA feature, use next binary files: + +- zephyr.bin - main binary to flash PCB (Use 2MB PCB). +- zephyr-ota.bin - binary for OTA Provider + +All binaries has the same SW version. To test OTA “zephyr-ota.bin” should have +higher SW version than base SW. Set CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=2 in +corresponding “prj.conf” configuration file. + +Usage of OTA: + +- Build the [Linux OTA Provider](../../ota-provider-app/linux) + + ``` + ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false + ``` + +- Run the Linux OTA Provider with OTA image. + + ``` + ./chip-ota-provider-app -f zephyr-ota.bin + ``` + +- Provision the Linux OTA Provider using chip-tool + + ``` + ./chip-tool pairing onnetwork ${OTA_PROVIDER_NODE_ID} 20202021 + ``` + + here: + + - \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider + +- Configure the ACL of the ota-provider-app to allow access + + ``` + ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' ${OTA_PROVIDER_NODE_ID} 0 + ``` + + here: + + - \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider + +- Use the chip-tool to announce the ota-provider-app to start the OTA process + + ``` + ./chip-tool otasoftwareupdaterequestor announce-ota-provider ${OTA_PROVIDER_NODE_ID} 0 0 0 ${DEVICE_NODE_ID} 0 + ``` + + here: + + - \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider + - \${DEVICE_NODE_ID} is the node id of paired device + +Once the transfer is complete, OTA requestor sends ApplyUpdateRequest command to +OTA provider for applying the image. Device will restart on successful +application of OTA image. diff --git a/examples/contact-sensor-app/telink/include/AppConfig.h b/examples/contact-sensor-app/telink/include/AppConfig.h new file mode 100755 index 00000000000000..01128b76e4d929 --- /dev/null +++ b/examples/contact-sensor-app/telink/include/AppConfig.h @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// ---- Contact Sensor Example App Config ---- + +// Buttons config +#define BUTTON_PORT DEVICE_DT_GET(DT_NODELABEL(gpioc)) + +#define BUTTON_PIN_1 2 +#define BUTTON_PIN_3 3 +#define BUTTON_PIN_4 1 +#define BUTTON_PIN_2 0 + +// LEDs config +// System led config +#define SYSTEM_STATE_LED_PORT DEVICE_DT_GET(DT_NODELABEL(gpiob)) +#define SYSTEM_STATE_LED_PIN 7 + +// Contact state led +#define CONTACT_STATE_LED_PIN 4 diff --git a/examples/contact-sensor-app/telink/include/AppEvent.h b/examples/contact-sensor-app/telink/include/AppEvent.h new file mode 100755 index 00000000000000..4051ba31cbb465 --- /dev/null +++ b/examples/contact-sensor-app/telink/include/AppEvent.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +class LEDWidget; + +struct AppEvent +{ + enum AppEventTypes + { + kEventType_Button = 0, + kEventType_Timer, + kEventType_UpdateLedState, + kEventType_Contact, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t Action; + } ButtonEvent; + struct + { + uint8_t Action; + } ContactEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/contact-sensor-app/telink/include/AppTask.h b/examples/contact-sensor-app/telink/include/AppTask.h new file mode 100644 index 00000000000000..206a0276f809d9 --- /dev/null +++ b/examples/contact-sensor-app/telink/include/AppTask.h @@ -0,0 +1,107 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppEvent.h" +#include "ContactSensorManager.h" +#include "LEDWidget.h" + +#include + +#include + +#if CONFIG_CHIP_FACTORY_DATA +#include +#endif + +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) + +struct k_timer; + +class AppTask +{ +public: + CHIP_ERROR StartApp(void); + + void PostContactActionRequest(ContactSensorManager::Action aAction); + void PostEvent(AppEvent * event); + void UpdateClusterState(void); + void UpdateDeviceState(void); + + bool IsSyncClusterToButtonAction(void); + void SetSyncClusterToButtonAction(bool value); + +private: + friend AppTask & GetAppTask(void); + CHIP_ERROR Init(void); + + void DispatchEvent(AppEvent * event); + + static void OnStateChanged(ContactSensorManager::State aState); + + static void UpdateClusterStateInternal(intptr_t arg); + static void UpdateDeviceStateInternal(intptr_t arg); + + static void UpdateStatusLED(void); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); + static void FactoryResetButtonEventHandler(void); + static void StartBleAdvButtonEventHandler(void); + static void ToggleContactStateButtonEventHandler(void); + + static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); + static void FactoryResetHandler(AppEvent * aEvent); + static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); + static void ContactActionEventHandler(AppEvent * aEvent); + + static void InitButtons(void); + + static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + + bool mSyncClusterToButtonAction = false; + + static AppTask sAppTask; + +#if CONFIG_CHIP_FACTORY_DATA + // chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; + chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; +#endif +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} + +inline bool AppTask::IsSyncClusterToButtonAction() +{ + return mSyncClusterToButtonAction; +} + +inline void AppTask::SetSyncClusterToButtonAction(bool value) +{ + mSyncClusterToButtonAction = value; +} diff --git a/examples/contact-sensor-app/telink/include/CHIPProjectConfig.h b/examples/contact-sensor-app/telink/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..e0c02df64c163a --- /dev/null +++ b/examples/contact-sensor-app/telink/include/CHIPProjectConfig.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// Use a default pairing code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE + * + * Reduce packet buffer pool size to 8 (default 15) to reduce ram consumption + */ +#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE 8 diff --git a/examples/contact-sensor-app/telink/include/ContactSensorManager.h b/examples/contact-sensor-app/telink/include/ContactSensorManager.h new file mode 100644 index 00000000000000..0f735288b6ee39 --- /dev/null +++ b/examples/contact-sensor-app/telink/include/ContactSensorManager.h @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +class ContactSensorManager +{ +public: + enum class Action : uint8_t + { + kSignalDetected = 0, + kSignalLost, + kInvalid + }; + + enum class State : uint8_t + { + kContactClosed = 0, + kContactOpened, + kInvalid + }; + + int Init(); + bool IsContactClosed(); + void InitiateAction(Action aAction); + + typedef void (*CallbackStateChanged)(State aState); + void SetCallback(CallbackStateChanged aCallbackStateChanged); + + static void HandleAction(AppEvent * aEvent); + +private: + friend ContactSensorManager & ContactSensorMgr(void); + State mState; + CallbackStateChanged mCallbackStateChanged; + static ContactSensorManager sContactSensor; +}; + +inline ContactSensorManager & ContactSensorMgr(void) +{ + return ContactSensorManager::sContactSensor; +} diff --git a/examples/contact-sensor-app/telink/prj.conf b/examples/contact-sensor-app/telink/prj.conf new file mode 100755 index 00000000000000..84f3fd49622e95 --- /dev/null +++ b/examples/contact-sensor-app/telink/prj.conf @@ -0,0 +1,58 @@ +# +# Copyright (c) 2022 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This sample uses sample-defaults.conf to set options common for all +# samples. This file should contain only options specific for this sample +# or overrides of default values. + +# enable GPIO +CONFIG_GPIO=y + +# OpenThread configs +CONFIG_OPENTHREAD_MTD=y +CONFIG_OPENTHREAD_FTD=n + +# Default OpenThread network settings +CONFIG_OPENTHREAD_PANID=4660 +CONFIG_OPENTHREAD_CHANNEL=15 +CONFIG_OPENTHREAD_NETWORK_NAME="OpenThreadDemo" +CONFIG_OPENTHREAD_XPANID="11:11:11:11:22:22:22:22" +CONFIG_NET_CONFIG_IEEE802154_DEV_NAME="IEEE802154_b91" + +# Disable Matter OTA DFU +CONFIG_CHIP_OTA_REQUESTOR=n + +# CHIP configuration +CONFIG_CHIP_PROJECT_CONFIG="include/CHIPProjectConfig.h" +CONFIG_CHIP_OPENTHREAD_CONFIG="../../platform/telink/project_include/OpenThreadConfig.h" + +CONFIG_CHIP_DEVICE_VENDOR_ID=65521 +# 32774 == 0x8006 (example contact-sensor-app) +CONFIG_CHIP_DEVICE_PRODUCT_ID=32769 +CONFIG_CHIP_DEVICE_TYPE=65535 + +CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=1 +CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING="2022" + +# Enable CHIP pairing automatically on application start. +CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y + +# CHIP shell +CONFIG_CHIP_LIB_SHELL=n + +# Disable factory data support. +CONFIG_CHIP_FACTORY_DATA=n +CONFIG_CHIP_FACTORY_DATA_BUILD=n diff --git a/examples/contact-sensor-app/telink/src/AppTask.cpp b/examples/contact-sensor-app/telink/src/AppTask.cpp new file mode 100644 index 00000000000000..177080b069391c --- /dev/null +++ b/examples/contact-sensor-app/telink/src/AppTask.cpp @@ -0,0 +1,506 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" + +#include "AppConfig.h" +#include "AppEvent.h" +#include "ButtonManager.h" + +#include "ThreadUtil.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if CONFIG_CHIP_OTA_REQUESTOR +#include "OTAUtil.h" +#endif + +#include +#include + +LOG_MODULE_DECLARE(app); + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + +namespace { +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; + +// NOTE! This key is for test/certification only and should not be available in production devices! +// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + +K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; + +LEDWidget sStatusLED; +LEDWidget sContactSensorLED; + +Button sFactoryResetButton; +Button sToggleContactStateButton; +Button sBleAdvStartButton; + +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; + +chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; + +void OnIdentifyTriggerEffect(Identify * identify) +{ + switch (identify->mCurrentEffectIdentifier) + { + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK"); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE"); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY"); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE"); + break; + default: + ChipLogProgress(Zcl, "No identifier effect"); + break; + } + return; +} + +Identify sIdentify = { + chip::EndpointId{ 1 }, + [](Identify *) { ChipLogProgress(Zcl, "OnIdentifyStart"); }, + [](Identify *) { ChipLogProgress(Zcl, "OnIdentifyStop"); }, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, + OnIdentifyTriggerEffect, +}; + +} // namespace + +AppTask AppTask::sAppTask; + +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err; + + LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION, + CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + // Initialize status LED + LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); + sStatusLED.Init(SYSTEM_STATE_LED_PIN); + + UpdateStatusLED(); + + sContactSensorLED.Init(CONTACT_STATE_LED_PIN); + sContactSensorLED.Set(ContactSensorMgr().IsContactClosed()); + + UpdateDeviceState(); + + InitButtons(); + + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + + // Initialize CHIP server +#if CONFIG_CHIP_FACTORY_DATA + ReturnErrorOnFailure(mFactoryDataProvider.Init()); + SetDeviceInstanceInfoProvider(&mFactoryDataProvider); + SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider); + SetCommissionableDataProvider(&mFactoryDataProvider); + // Read EnableKey from the factory data. + MutableByteSpan enableKey(sTestEventTriggerEnableKey); + err = mFactoryDataProvider.GetEnableKey(enableKey); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger"); + memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); + } +#else + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + + static CommonCaseDeviceServerInitParams initParams; + // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + // initParams.testEventTriggerDelegate = &testEventTriggerDelegate; + ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams)); + + gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); + chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); + +#if CONFIG_CHIP_OTA_REQUESTOR + InitBasicOTARequestor(); +#endif + + ConfigurationMgr().LogDeviceConfig(); + PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + + // Add CHIP event handler and start CHIP thread. + // Note that all the initialization code should happen prior to this point to avoid data races + // between the main and the CHIP threads. + PlatformMgr().AddEventHandler(ChipEventHandler, 0); + + ContactSensorMgr().SetCallback(OnStateChanged); + + err = ConnectivityMgr().SetBLEDeviceName("TelinkSensor"); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("Fail to set BLE device name"); + return err; + } + + return err; +} + +void AppTask::OnStateChanged(ContactSensorManager::State aState) +{ + // If the contact state was changed, update LED state and cluster state (only if button was pressed). + // - turn on the contact LED if contact sensor is in closed state. + // - turn off the lock LED if contact sensor is in opened state. + if (ContactSensorManager::State::kContactClosed == aState) + { + LOG_INF("Contact state changed to CLOSED"); + sContactSensorLED.Set(true); + } + else if (ContactSensorManager::State::kContactOpened == aState) + { + LOG_INF("Contact state changed to OPEN"); + sContactSensorLED.Set(false); + } + + if (sAppTask.IsSyncClusterToButtonAction()) + { + sAppTask.UpdateClusterState(); + } +} + +CHIP_ERROR AppTask::StartApp(void) +{ + CHIP_ERROR err = Init(); + + if (err != CHIP_NO_ERROR) + { + LOG_ERR("AppTask.Init() failed"); + return err; + } + + AppEvent event = {}; + + while (true) + { + int ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10)); + + while (!ret) + { + DispatchEvent(&event); + ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); + } + } +} + +void AppTask::PostContactActionRequest(ContactSensorManager::Action aAction) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Contact; + event.ContactEvent.Action = static_cast(aAction); + event.Handler = ContactActionEventHandler; + + sAppTask.PostEvent(&event); +} + +void AppTask::ToggleContactStateButtonEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = ContactActionEventHandler; + + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetButtonEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = FactoryResetHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetHandler(AppEvent * aEvent) +{ + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } +} + +void AppTask::UpdateClusterStateInternal(intptr_t arg) +{ + uint8_t newValue = ContactSensorMgr().IsContactClosed(); + + ChipLogProgress(NotSpecified, "emberAfWriteAttribute : %d", newValue); + + // write the new boolean state value + EmberAfStatus status = emberAfWriteAttribute(1, ZCL_BOOLEAN_STATE_CLUSTER_ID, ZCL_STATE_VALUE_ATTRIBUTE_ID, + (uint8_t *) &newValue, ZCL_BOOLEAN_ATTRIBUTE_TYPE); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(NotSpecified, "ERR: updating boolean status value %x", status); + } +} + +void AppTask::ContactActionEventHandler(AppEvent * aEvent) +{ + ContactSensorManager::Action action = ContactSensorManager::Action::kInvalid; + CHIP_ERROR err = CHIP_NO_ERROR; + + ChipLogProgress(NotSpecified, "ContactActionEventHandler"); + + if (aEvent->Type == AppEvent::kEventType_Contact) + { + action = static_cast(aEvent->ContactEvent.Action); + } + else if (aEvent->Type == AppEvent::kEventType_Button) + { + if (ContactSensorMgr().IsContactClosed()) + { + action = ContactSensorManager::Action::kSignalLost; + } + else + { + action = ContactSensorManager::Action::kSignalDetected; + } + + sAppTask.SetSyncClusterToButtonAction(true); + } + else + { + err = APP_ERROR_UNHANDLED_EVENT; + action = ContactSensorManager::Action::kInvalid; + } + + if (err == CHIP_NO_ERROR) + { + ContactSensorMgr().InitiateAction(action); + } +} + +void AppTask::StartBleAdvButtonEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = StartBleAdvHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::StartBleAdvHandler(AppEvent * aEvent) +{ + LOG_INF("BLE advertising start button pressed"); + + // Don't allow on starting Matter service BLE advertising after Thread provisioning. + if (ConnectivityMgr().IsThreadProvisioned()) + { + LOG_INF("Matter service BLE advertising not started - device is commissioned to a Thread network."); + return; + } + + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + LOG_INF("BLE advertising is already enabled"); + return; + } + + if (chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR) + { + LOG_ERR("OpenBasicCommissioningWindow() failed"); + } +} + +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + +void AppTask::UpdateStatusLED(void) +{ + if (sIsThreadProvisioned && sIsThreadEnabled) + { + if (sIsThreadAttached) + { + sStatusLED.Blink(950, 50); + } + else + { + sStatusLED.Blink(100, 100); + } + } + else + { + sStatusLED.Blink(50, 950); + } +} + +void AppTask::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLEAdvertisingChange: + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + sIsThreadAttached = ConnectivityMgr().IsThreadAttached(); + UpdateStatusLED(); + break; + case DeviceEventType::kThreadConnectivityChange: +#if CONFIG_CHIP_OTA_REQUESTOR + if (event->ThreadConnectivityChange.Result == kConnectivity_Established) + { + InitBasicOTARequestor(); + } +#endif + break; + default: + break; + } +} + +void AppTask::PostEvent(AppEvent * aEvent) +{ + if (k_msgq_put(&sAppEventQueue, aEvent, K_NO_WAIT) != 0) + { + LOG_INF("Failed to post event to app task event queue"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + LOG_INF("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateClusterState(void) +{ + PlatformMgr().ScheduleWork(UpdateClusterStateInternal, 0); +} + +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + +void AppTask::InitButtons(void) +{ + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sToggleContactStateButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_1, false, ToggleContactStateButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); + + ButtonManagerInst().AddButton(sFactoryResetButton); + ButtonManagerInst().AddButton(sToggleContactStateButton); + ButtonManagerInst().AddButton(sBleAdvStartButton); +} + +void AppTask::UpdateDeviceState(void) +{ + PlatformMgr().ScheduleWork(UpdateDeviceStateInternal, 0); +} + +void AppTask::UpdateDeviceStateInternal(intptr_t arg) +{ + bool stateValueAttrValue = 0; + + /* get boolean state attribute value */ + (void) emberAfReadAttribute(1, ZCL_BOOLEAN_STATE_CLUSTER_ID, ZCL_STATE_VALUE_ATTRIBUTE_ID, (uint8_t *) &stateValueAttrValue, 1); + + ChipLogProgress(NotSpecified, "emberAfReadAttribute : %d", stateValueAttrValue); + sContactSensorLED.Set(stateValueAttrValue); +} diff --git a/examples/contact-sensor-app/telink/src/ContactSensorManager.cpp b/examples/contact-sensor-app/telink/src/ContactSensorManager.cpp new file mode 100644 index 00000000000000..b555e4e0a2c958 --- /dev/null +++ b/examples/contact-sensor-app/telink/src/ContactSensorManager.cpp @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ContactSensorManager.h" + +#include "AppConfig.h" +#include "AppTask.h" + +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(app); + +ContactSensorManager ContactSensorManager::sContactSensor; + +int ContactSensorManager::Init() +{ + int err = 0; + + mState = State::kContactOpened; + mCallbackStateChanged = nullptr; + + return err; +} + +void ContactSensorManager::SetCallback(CallbackStateChanged aCallbackStateChanged) +{ + mCallbackStateChanged = aCallbackStateChanged; +} + +bool ContactSensorManager::IsContactClosed() +{ + return mState == State::kContactClosed; +} + +void ContactSensorManager::InitiateAction(Action aAction) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Contact; + event.ContactEvent.Action = static_cast(aAction); + event.Handler = HandleAction; + GetAppTask().PostEvent(&event); +} + +void ContactSensorManager::HandleAction(AppEvent * aEvent) +{ + Action action = static_cast(aEvent->ContactEvent.Action); + // Change current state based on action: + // - if state is closed and action is signal lost, change state to opened + // - if state is opened and action is signal detected, change state to closed + // - else, the state/action combination does not change the state. + if (sContactSensor.mState == State::kContactClosed && action == Action::kSignalLost) + { + sContactSensor.mState = State::kContactOpened; + } + else if (sContactSensor.mState == State::kContactOpened && action == Action::kSignalDetected) + { + sContactSensor.mState = State::kContactClosed; + } + + if (sContactSensor.mCallbackStateChanged != nullptr) + { + sContactSensor.mCallbackStateChanged(sContactSensor.mState); + } + else + { + LOG_ERR("Callback for state change was not set. Please set an appropriate callback."); + } +} diff --git a/examples/contact-sensor-app/telink/src/ZclCallbacks.cpp b/examples/contact-sensor-app/telink/src/ZclCallbacks.cpp new file mode 100644 index 00000000000000..89d6aed77f16d2 --- /dev/null +++ b/examples/contact-sensor-app/telink/src/ZclCallbacks.cpp @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" + +#include +#include +#include +#include + +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; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == BooleanState::Id && attributeId == BooleanState::Attributes::StateValue::Id) + { + ChipLogProgress(Zcl, "Cluster BooleanState: attribute StateValue set to %u", *value); + AppTask & task = GetAppTask(); + if (task.IsSyncClusterToButtonAction()) + { + task.SetSyncClusterToButtonAction(false); + } + else + { + task.PostContactActionRequest(*value ? ContactSensorManager::Action::kSignalDetected + : ContactSensorManager::Action::kSignalLost); + } + } +} + +void emberAfBooleanStateClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "emberAfBooleanStateClusterInitCallback"); + GetAppTask().UpdateClusterState(); +} diff --git a/examples/contact-sensor-app/telink/src/main.cpp b/examples/contact-sensor-app/telink/src/main.cpp new file mode 100755 index 00000000000000..a1a89a0d6865ad --- /dev/null +++ b/examples/contact-sensor-app/telink/src/main.cpp @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" + +#include +#include + +#include + +LOG_MODULE_REGISTER(app); + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +int main(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + err = chip::Platform::MemoryInit(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("Platform::MemoryInit() failed"); + goto exit; + } + + LOG_INF("Init CHIP stack"); + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().InitChipStack() failed"); + goto exit; + } + + LOG_INF("Starting CHIP task"); + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().StartEventLoopTask() failed"); + goto exit; + } + + LOG_INF("Init Thread stack"); + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ThreadStackMgr().InitThreadStack() failed"); + goto exit; + } + +#ifdef CONFIG_OPENTHREAD_MTD_SED + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); +#elif CONFIG_OPENTHREAD_MTD + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); +#else + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router); +#endif + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed"); + goto exit; + } + + err = GetAppTask().StartApp(); + +exit: + LOG_ERR("Exited with code %" CHIP_ERROR_FORMAT, err.Format()); + return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/examples/contact-sensor-app/telink/third_party/connectedhomeip b/examples/contact-sensor-app/telink/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/contact-sensor-app/telink/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/examples/light-switch-app/telink/include/AppEvent.h b/examples/light-switch-app/telink/include/AppEvent.h index ed69564c270adb..9a6fd3060c1685 100755 --- a/examples/light-switch-app/telink/include/AppEvent.h +++ b/examples/light-switch-app/telink/include/AppEvent.h @@ -23,12 +23,15 @@ struct AppEvent; typedef void (*EventHandler)(AppEvent *); +class LEDWidget; + struct AppEvent { enum AppEventTypes { kEventType_Button = 0, kEventType_Timer, + kEventType_UpdateLedState, kEventType_Lighting, kEventType_Install, }; @@ -50,6 +53,10 @@ struct AppEvent uint8_t Action; int32_t Actor; } LightingEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; }; EventHandler Handler; diff --git a/examples/light-switch-app/telink/include/AppTask.h b/examples/light-switch-app/telink/include/AppTask.h index 6cf0a330cf2317..6509613e3741b8 100755 --- a/examples/light-switch-app/telink/include/AppTask.h +++ b/examples/light-switch-app/telink/include/AppTask.h @@ -19,6 +19,7 @@ #pragma once #include "AppEvent.h" +#include "LEDWidget.h" #include @@ -60,6 +61,7 @@ class AppTask void DispatchEvent(AppEvent * event); static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); static void SwitchActionButtonEventHandler(void); static void FactoryResetButtonEventHandler(void); static void StartThreadButtonEventHandler(void); @@ -67,10 +69,14 @@ class AppTask static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); static void FactoryResetHandler(AppEvent * aEvent); static void StartThreadHandler(AppEvent * aEvent); static void SwitchActionEventHandler(AppEvent * aEvent); static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); static void InitButtons(void); diff --git a/examples/light-switch-app/telink/src/AppTask.cpp b/examples/light-switch-app/telink/src/AppTask.cpp index 7e1c792018b885..1548c6913397e6 100644 --- a/examples/light-switch-app/telink/src/AppTask.cpp +++ b/examples/light-switch-app/telink/src/AppTask.cpp @@ -21,7 +21,6 @@ #include "AppConfig.h" #include "AppEvent.h" #include "ButtonManager.h" -#include "LEDWidget.h" #include "binding-handler.h" #include "ThreadUtil.h" @@ -55,10 +54,10 @@ using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; namespace { - -constexpr int kAppEventQueueSize = 10; -constexpr uint8_t kButtonPushEvent = 1; -constexpr uint8_t kButtonReleaseEvent = 0; +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; // NOTE! This key is for test/certification only and should not be available in production devices! // If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. @@ -66,6 +65,7 @@ uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; LEDWidget sStatusLED; @@ -74,10 +74,11 @@ Button sSwitchButton; Button sThreadStartButton; Button sBleAdvStartButton; -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -bool sIsThreadAttached = false; -bool sHaveBLEConnections = false; +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; @@ -125,12 +126,17 @@ CHIP_ERROR AppTask::Init() // Initialize status LED LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(SYSTEM_STATE_LED_PIN); UpdateStatusLED(); InitButtons(); + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + // Initialize CHIP server #if CONFIG_CHIP_FACTORY_DATA ReturnErrorOnFailure(mFactoryDataProvider.Init()); @@ -208,8 +214,6 @@ CHIP_ERROR AppTask::StartApp() DispatchEvent(&event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - sStatusLED.Animate(); } } @@ -247,8 +251,16 @@ void AppTask::FactoryResetButtonEventHandler(void) void AppTask::FactoryResetHandler(AppEvent * aEvent) { - LOG_INF("Factory Reset triggered."); - chip::Server::GetInstance().ScheduleFactoryReset(); + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } } void AppTask::StartThreadButtonEventHandler(void) @@ -311,6 +323,23 @@ void AppTask::StartBleAdvHandler(AppEvent * aEvent) } } +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + void AppTask::UpdateStatusLED() { if (sIsThreadProvisioned && sIsThreadEnabled) @@ -389,12 +418,37 @@ void AppTask::DispatchEvent(AppEvent * aEvent) void AppTask::UpdateClusterState() {} +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + void AppTask::InitButtons(void) { - sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, FactoryResetButtonEventHandler); - sSwitchButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_1, SwitchActionButtonEventHandler); - sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, StartThreadButtonEventHandler); - sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, StartBleAdvButtonEventHandler); + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sSwitchButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_1, false, SwitchActionButtonEventHandler); + sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, false, StartThreadButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); ButtonManagerInst().AddButton(sFactoryResetButton); ButtonManagerInst().AddButton(sSwitchButton); diff --git a/examples/light-switch-app/telink/src/ZclCallbacks.cpp b/examples/light-switch-app/telink/src/ZclCallbacks.cpp index 8510126c57e8cc..cb2b2ab490b48a 100644 --- a/examples/light-switch-app/telink/src/ZclCallbacks.cpp +++ b/examples/light-switch-app/telink/src/ZclCallbacks.cpp @@ -26,8 +26,8 @@ using namespace chip; using namespace chip::app::Clusters; -void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, - uint16_t size, uint8_t * value) +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) { ClusterId clusterId = attributePath.mClusterId; AttributeId attributeId = attributePath.mAttributeId; diff --git a/examples/lighting-app/telink/include/AppEvent.h b/examples/lighting-app/telink/include/AppEvent.h index 548d737f5c65d7..1766b5d77577a1 100644 --- a/examples/lighting-app/telink/include/AppEvent.h +++ b/examples/lighting-app/telink/include/AppEvent.h @@ -23,12 +23,15 @@ struct AppEvent; typedef void (*EventHandler)(AppEvent *); +class LEDWidget; + struct AppEvent { enum AppEventTypes { kEventType_Button = 0, kEventType_Timer, + kEventType_UpdateLedState, kEventType_Lighting, kEventType_Install, }; @@ -50,6 +53,10 @@ struct AppEvent uint8_t Action; int32_t Actor; } LightingEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; }; EventHandler Handler; diff --git a/examples/lighting-app/telink/include/AppTask.h b/examples/lighting-app/telink/include/AppTask.h index 0b1b588654aa13..079cf0cf3ede57 100644 --- a/examples/lighting-app/telink/include/AppTask.h +++ b/examples/lighting-app/telink/include/AppTask.h @@ -19,8 +19,8 @@ #pragma once #include "AppEvent.h" +#include "LEDWidget.h" #include "LightingManager.h" - #include #if CONFIG_CHIP_FACTORY_DATA @@ -50,6 +50,7 @@ class AppTask void DispatchEvent(AppEvent * event); static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); static void LightingActionButtonEventHandler(void); static void FactoryResetButtonEventHandler(void); static void StartThreadButtonEventHandler(void); @@ -57,10 +58,14 @@ class AppTask static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); static void FactoryResetHandler(AppEvent * aEvent); static void StartThreadHandler(AppEvent * aEvent); static void LightingActionEventHandler(AppEvent * aEvent); static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); static void InitButtons(void); diff --git a/examples/lighting-app/telink/src/AppTask.cpp b/examples/lighting-app/telink/src/AppTask.cpp index 00db77cd01c89a..6a08f11004e093 100644 --- a/examples/lighting-app/telink/src/AppTask.cpp +++ b/examples/lighting-app/telink/src/AppTask.cpp @@ -21,8 +21,6 @@ #include "AppConfig.h" #include "AppEvent.h" #include "ButtonManager.h" -#include "LEDWidget.h" -#include "LightingManager.h" #include "ThreadUtil.h" @@ -56,12 +54,12 @@ using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; namespace { - -constexpr int kAppEventQueueSize = 10; -constexpr uint8_t kButtonPushEvent = 1; -constexpr uint8_t kButtonReleaseEvent = 0; -constexpr uint8_t kDefaultMinLevel = 0; -constexpr uint8_t kDefaultMaxLevel = 254; +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; +constexpr uint8_t kDefaultMinLevel = 0; +constexpr uint8_t kDefaultMaxLevel = 254; // NOTE! This key is for test/certification only and should not be available in production devices! // If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. @@ -69,6 +67,7 @@ uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; LEDWidget sStatusLED; @@ -77,10 +76,11 @@ Button sLightingButton; Button sThreadStartButton; Button sBleAdvStartButton; -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -bool sIsThreadAttached = false; -bool sHaveBLEConnections = false; +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; @@ -126,12 +126,17 @@ CHIP_ERROR AppTask::Init() // Initialize status LED LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(SYSTEM_STATE_LED_PIN); UpdateStatusLED(); InitButtons(); + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + // Init lighting manager uint8_t minLightLevel = kDefaultMinLevel; Clusters::LevelControl::Attributes::MinLevel::Get(1, &minLightLevel); @@ -216,8 +221,6 @@ CHIP_ERROR AppTask::StartApp() DispatchEvent(&event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - sStatusLED.Animate(); } } @@ -263,8 +266,16 @@ void AppTask::FactoryResetButtonEventHandler(void) void AppTask::FactoryResetHandler(AppEvent * aEvent) { - LOG_INF("Factory Reset triggered."); - chip::Server::GetInstance().ScheduleFactoryReset(); + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } } void AppTask::StartThreadButtonEventHandler(void) @@ -327,6 +338,23 @@ void AppTask::StartBleAdvHandler(AppEvent * aEvent) } } +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + void AppTask::UpdateStatusLED() { if (sIsThreadProvisioned && sIsThreadEnabled) @@ -457,12 +485,37 @@ void AppTask::UpdateClusterState() } } +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + void AppTask::InitButtons(void) { - sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, FactoryResetButtonEventHandler); - sLightingButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_1, LightingActionButtonEventHandler); - sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, StartThreadButtonEventHandler); - sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, StartBleAdvButtonEventHandler); + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sLightingButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_1, false, LightingActionButtonEventHandler); + sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, false, StartThreadButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); ButtonManagerInst().AddButton(sFactoryResetButton); ButtonManagerInst().AddButton(sLightingButton); diff --git a/examples/ota-requestor-app/telink/include/AppEvent.h b/examples/ota-requestor-app/telink/include/AppEvent.h index ed69564c270adb..9a6fd3060c1685 100644 --- a/examples/ota-requestor-app/telink/include/AppEvent.h +++ b/examples/ota-requestor-app/telink/include/AppEvent.h @@ -23,12 +23,15 @@ struct AppEvent; typedef void (*EventHandler)(AppEvent *); +class LEDWidget; + struct AppEvent { enum AppEventTypes { kEventType_Button = 0, kEventType_Timer, + kEventType_UpdateLedState, kEventType_Lighting, kEventType_Install, }; @@ -50,6 +53,10 @@ struct AppEvent uint8_t Action; int32_t Actor; } LightingEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; }; EventHandler Handler; diff --git a/examples/ota-requestor-app/telink/include/AppTask.h b/examples/ota-requestor-app/telink/include/AppTask.h index 712212e38fd80d..a8b5c2dd3e7a93 100755 --- a/examples/ota-requestor-app/telink/include/AppTask.h +++ b/examples/ota-requestor-app/telink/include/AppTask.h @@ -19,6 +19,7 @@ #pragma once #include "AppEvent.h" +#include "LEDWidget.h" #include @@ -56,15 +57,20 @@ class AppTask void DispatchEvent(AppEvent * event); static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); static void FactoryResetButtonEventHandler(void); static void StartThreadButtonEventHandler(void); static void StartBleAdvButtonEventHandler(void); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); static void FactoryResetHandler(AppEvent * aEvent); static void StartThreadHandler(AppEvent * aEvent); static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); static void InitButtons(void); diff --git a/examples/ota-requestor-app/telink/src/AppTask.cpp b/examples/ota-requestor-app/telink/src/AppTask.cpp index 314e228772899b..adf780591eea83 100644 --- a/examples/ota-requestor-app/telink/src/AppTask.cpp +++ b/examples/ota-requestor-app/telink/src/AppTask.cpp @@ -21,7 +21,6 @@ #include "AppConfig.h" #include "AppEvent.h" #include "ButtonManager.h" -#include "LEDWidget.h" #include #include @@ -57,12 +56,13 @@ LOG_MODULE_DECLARE(app); namespace { - -constexpr int kAppEventQueueSize = 10; -constexpr uint8_t kButtonPushEvent = 1; -constexpr uint8_t kButtonReleaseEvent = 0; +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; LEDWidget sStatusLED; @@ -70,10 +70,11 @@ Button sFactoryResetButton; Button sThreadStartButton; Button sBleAdvStartButton; -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -bool sIsThreadAttached = false; -bool sHaveBLEConnections = false; +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; @@ -128,12 +129,17 @@ CHIP_ERROR AppTask::Init() // Initialize status LED LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(SYSTEM_STATE_LED_PIN); UpdateStatusLED(); InitButtons(); + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + // Init ZCL Data Model and start server static chip::CommonCaseDeviceServerInitParams initParams; (void) initParams.InitializeStaticResourcesBeforeServerInit(); @@ -193,8 +199,6 @@ CHIP_ERROR AppTask::StartApp() DispatchEvent(&event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - sStatusLED.Animate(); } } @@ -210,8 +214,16 @@ void AppTask::FactoryResetButtonEventHandler(void) void AppTask::FactoryResetHandler(AppEvent * aEvent) { - LOG_INF("Factory Reset triggered."); - chip::Server::GetInstance().ScheduleFactoryReset(); + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } } void AppTask::StartThreadButtonEventHandler(void) @@ -274,6 +286,23 @@ void AppTask::StartBleAdvHandler(AppEvent * aEvent) } } +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + void AppTask::UpdateStatusLED() { if (sIsThreadProvisioned && sIsThreadEnabled) @@ -344,11 +373,36 @@ void AppTask::DispatchEvent(AppEvent * aEvent) } } +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + void AppTask::InitButtons(void) { - sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, FactoryResetButtonEventHandler); - sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, StartThreadButtonEventHandler); - sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, StartBleAdvButtonEventHandler); + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, false, StartThreadButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); ButtonManagerInst().AddButton(sFactoryResetButton); ButtonManagerInst().AddButton(sThreadStartButton); diff --git a/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp b/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp index 74bc8f28a40585..159ce1f9326c6d 100644 --- a/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp +++ b/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp @@ -26,8 +26,8 @@ using namespace chip; using namespace chip::app::Clusters; -void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, - uint16_t size, uint8_t * value) +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) { ClusterId clusterId = attributePath.mClusterId; AttributeId attributeId = attributePath.mAttributeId; diff --git a/examples/platform/telink/util/include/ButtonManager.h b/examples/platform/telink/util/include/ButtonManager.h index 9c164fd7120c82..c728d59a5ea48d 100644 --- a/examples/platform/telink/util/include/ButtonManager.h +++ b/examples/platform/telink/util/include/ButtonManager.h @@ -26,7 +26,7 @@ class Button { public: - void Configure(const struct device * port, gpio_pin_t outPin, gpio_pin_t inPin, void (*callback)(void)); + void Configure(const struct device * port, gpio_pin_t outPin, gpio_pin_t inPin, bool intBothLevel, void (*callback)(void)); void Poll(Button * previous); void SetCallback(void (*callback)(void)); @@ -38,6 +38,7 @@ class Button gpio_pin_t mOutPin; gpio_pin_t mInPin; int mPreviousState = STATE_LOW; + bool mIntBothLevel = false; void (*mCallback)(void) = NULL; }; diff --git a/examples/platform/telink/util/include/LEDWidget.h b/examples/platform/telink/util/include/LEDWidget.h index e851c03ccc04e2..b1e25d4f91a703 100644 --- a/examples/platform/telink/util/include/LEDWidget.h +++ b/examples/platform/telink/util/include/LEDWidget.h @@ -19,25 +19,32 @@ #include #include +#include class LEDWidget { public: + typedef void (*LEDWidgetStateUpdateHandler)(LEDWidget * ledWidget); + static void InitGpio(const device * port); + static void SetStateUpdateCallback(LEDWidgetStateUpdateHandler stateUpdateCb); const static struct device * mPort; void Init(gpio_pin_t gpioNum); void Set(bool state); void Invert(void); void Blink(uint32_t changeRateMS); void Blink(uint32_t onTimeMS, uint32_t offTimeMS); - void Animate(); + void UpdateState(); private: - int64_t mLastChangeTimeMS; uint32_t mBlinkOnTimeMS; uint32_t mBlinkOffTimeMS; gpio_pin_t mGPIONum; bool mState; + k_timer mLedTimer; + + static void LedStateTimerHandler(k_timer * timer); void DoSet(bool state); + void ScheduleStateChange(); }; diff --git a/examples/platform/telink/util/src/ButtonManager.cpp b/examples/platform/telink/util/src/ButtonManager.cpp index 6a5d6055f53702..84578ca08fe676 100644 --- a/examples/platform/telink/util/src/ButtonManager.cpp +++ b/examples/platform/telink/util/src/ButtonManager.cpp @@ -29,14 +29,15 @@ LOG_MODULE_REGISTER(ButtonManager); ButtonManager ButtonManager::sInstance; -void Button::Configure(const struct device * port, gpio_pin_t outPin, gpio_pin_t inPin, void (*callback)(void)) +void Button::Configure(const struct device * port, gpio_pin_t outPin, gpio_pin_t inPin, bool intBothLevel, void (*callback)(void)) { __ASSERT(device_is_ready(port), "%s is not ready\n", port->name); - mPort = port; - mOutPin = outPin; - mInPin = inPin; - mCallback = callback; + mPort = port; + mOutPin = outPin; + mInPin = inPin; + mIntBothLevel = intBothLevel; + mCallback = callback; } int Button::Init(void) @@ -91,19 +92,15 @@ void Button::Poll(Button * previous) ret = gpio_pin_get(mPort, mInPin); assert(ret >= 0); - if (ret == STATE_HIGH && mPreviousState != STATE_HIGH) + if ((mIntBothLevel && ret != mPreviousState) || (!mIntBothLevel && ret == STATE_HIGH && ret != mPreviousState)) { - mPreviousState = STATE_HIGH; - if (mCallback != NULL) { mCallback(); } } - else if (ret == STATE_LOW) - { - mPreviousState = STATE_LOW; - } + + mPreviousState = ret; k_msleep(10); } diff --git a/examples/platform/telink/util/src/LEDWidget.cpp b/examples/platform/telink/util/src/LEDWidget.cpp index 3b97fe64375058..cefb8bbc1cb2a0 100644 --- a/examples/platform/telink/util/src/LEDWidget.cpp +++ b/examples/platform/telink/util/src/LEDWidget.cpp @@ -21,6 +21,7 @@ #include const struct device * LEDWidget::mPort = NULL; +static LEDWidget::LEDWidgetStateUpdateHandler sStateUpdateCallback; void LEDWidget::InitGpio(const device * port) { @@ -28,17 +29,25 @@ void LEDWidget::InitGpio(const device * port) __ASSERT(device_is_ready(mPort), "%s is not ready\n", mPort->name); } +void LEDWidget::SetStateUpdateCallback(LEDWidgetStateUpdateHandler stateUpdateCb) +{ + if (stateUpdateCb) + sStateUpdateCallback = stateUpdateCb; +} + void LEDWidget::Init(gpio_pin_t gpioNum) { - mLastChangeTimeMS = 0; - mBlinkOnTimeMS = 0; - mBlinkOffTimeMS = 0; - mGPIONum = gpioNum; - mState = false; + mBlinkOnTimeMS = 0; + mBlinkOffTimeMS = 0; + mGPIONum = gpioNum; + mState = false; int ret = gpio_pin_configure(mPort, mGPIONum, GPIO_OUTPUT_ACTIVE); __ASSERT(ret >= 0, "GPIO pin %d configure - fail. Status%d\n", mGPIONum, ret); + k_timer_init(&mLedTimer, &LEDWidget::LedStateTimerHandler, nullptr); + k_timer_user_data_set(&mLedTimer, this); + Set(false); } @@ -49,7 +58,8 @@ void LEDWidget::Invert(void) void LEDWidget::Set(bool state) { - mLastChangeTimeMS = mBlinkOnTimeMS = mBlinkOffTimeMS = 0; + k_timer_stop(&mLedTimer); + mBlinkOnTimeMS = mBlinkOffTimeMS = 0; DoSet(state); } @@ -60,29 +70,42 @@ void LEDWidget::Blink(uint32_t changeRateMS) void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) { + k_timer_stop(&mLedTimer); + mBlinkOnTimeMS = onTimeMS; mBlinkOffTimeMS = offTimeMS; - Animate(); -} -void LEDWidget::Animate() -{ if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) { - int64_t nowMS = k_uptime_get(); - int64_t stateDurMS = mState ? mBlinkOnTimeMS : mBlinkOffTimeMS; - - if (nowMS > mLastChangeTimeMS + stateDurMS) - { - DoSet(!mState); - mLastChangeTimeMS = nowMS; - } + DoSet(!mState); + ScheduleStateChange(); } } +void LEDWidget::ScheduleStateChange() +{ + k_timer_start(&mLedTimer, K_MSEC(mState ? mBlinkOnTimeMS : mBlinkOffTimeMS), K_NO_WAIT); +} + void LEDWidget::DoSet(bool state) { mState = state; int ret = gpio_pin_set(mPort, mGPIONum, state); __ASSERT(ret >= 0, "GPIO pin %d set -fail. Status: %d\n", mGPIONum, ret); } + +void LEDWidget::UpdateState() +{ + /* Prevent from keep updating the state if LED was set to solid On/Off value */ + if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) + { + DoSet(!mState); + ScheduleStateChange(); + } +} + +void LEDWidget::LedStateTimerHandler(k_timer * timer) +{ + if (sStateUpdateCallback) + sStateUpdateCallback(reinterpret_cast(timer->user_data)); +} diff --git a/examples/thermostat/telink/.gitignore b/examples/thermostat/telink/.gitignore new file mode 100644 index 00000000000000..84c048a73cc2e5 --- /dev/null +++ b/examples/thermostat/telink/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/examples/thermostat/telink/CMakeLists.txt b/examples/thermostat/telink/CMakeLists.txt new file mode 100755 index 00000000000000..86e40c22502d74 --- /dev/null +++ b/examples/thermostat/telink/CMakeLists.txt @@ -0,0 +1,69 @@ +# +# Copyright (c) 2022 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +cmake_minimum_required(VERSION 3.13.1) + +set(BOARD tlsr9518adk80d) + +get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH) +get_filename_component(NLIO_ROOT ${CHIP_ROOT}/third_party/nlio/repo/include REALPATH) +get_filename_component(TELINK_COMMON ${CHIP_ROOT}/examples/platform/telink REALPATH) +get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH) + +set(CONF_FILE ${CHIP_ROOT}/config/telink/app/zephyr.conf prj.conf) + +# Load NCS/Zephyr build system +list(APPEND ZEPHYR_EXTRA_MODULES ${CHIP_ROOT}/config/telink/chip-module) +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) + +project(chip-telink-thermostat-example) + +include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake) +include(${CHIP_ROOT}/src/app/chip_data_model.cmake) + +target_compile_options(app PRIVATE -fpermissive) + +target_include_directories(app PRIVATE + include + ${GEN_DIR}/app-common + ${GEN_DIR}/thermostat + ${NLIO_ROOT} + ${TELINK_COMMON}/util/include + ${TELINK_COMMON}/app/include) + +add_definitions( + "-DCHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER=" +) + +target_sources(app PRIVATE + src/AppTask.cpp + src/SensorManager.cpp + src/TemperatureManager.cpp + src/main.cpp + src/ZclCallbacks.cpp + ${GEN_DIR}/thermostat/zap-generated/callback-stub.cpp + ${GEN_DIR}/thermostat/zap-generated/IMClusterCommandHandler.cpp + ${TELINK_COMMON}/util/src/LEDWidget.cpp + ${TELINK_COMMON}/util/src/ButtonManager.cpp + ${TELINK_COMMON}/util/src/ThreadUtil.cpp) + +chip_configure_data_model(app + INCLUDE_SERVER + ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../thermostat-common/thermostat.zap +) + +if(CONFIG_CHIP_OTA_REQUESTOR) + target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp) +endif() diff --git a/examples/thermostat/telink/Readme.md b/examples/thermostat/telink/Readme.md new file mode 100755 index 00000000000000..18dd713f7ec07d --- /dev/null +++ b/examples/thermostat/telink/Readme.md @@ -0,0 +1,157 @@ +# Matter Telink Thermostat Example Application + +You can use this example as a reference for creating your own application. + +![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png) + +## Build and flash + +1. Pull docker image from repository: + + ```bash + $ docker pull connectedhomeip/chip-build-telink:latest + ``` + +1. Run docker container: + + ```bash + $ docker run -it --rm -v ${CHIP_BASE}:/root/chip -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" connectedhomeip/chip-build-telink:latest + ``` + + here `${CHIP_BASE}` is directory which contains CHIP repo files **!!!Pay + attention that OUTPUT_DIR should contains ABSOLUTE path to output dir** + +1. Activate the build environment: + + ```bash + $ source ./scripts/activate.sh + ``` + +1. In the example dir run: + + ```bash + $ west build + ``` + +1. Flash binary: + + ``` + $ west flash --erase + ``` + +## Usage + +### UART + +To get output from device, connect UART to following pins: + +| Name | Pin | +| :--: | :---------------------------- | +| RX | PB3 (pin 17 of J34 connector) | +| TX | PB2 (pin 16 of J34 connector) | +| GND | GND | + +### Buttons + +The following buttons are available on **tlsr9518adk80d** board: + +| Name | Function | Description | +| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- | +| Button 1 | Factory reset | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state | +| Button 2 | NA | NA | +| Button 3 | Thread start | Commission thread with static credentials and enables the Thread on device | +| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE | + +### LEDs + +**Red** LED indicates current state of Thread network. It ables to be in +following states: + +| State | Description | +| :-------------------------- | :--------------------------------------------------------------------------- | +| Blinks with short pulses | Device is not commissioned to Thread, Thread is disabled | +| Blinls with frequent pulses | Device is commissioned, Thread enabled. Device trying to JOIN thread network | +| Blinks with whde pulses | Device commissioned and joined to thread network as CHILD | + +### CHIP tool commands + +1. Build + [chip-tool cli](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) + +2. Pair with device + + ``` + ${CHIP_TOOL_DIR}/chip-tool pairing ble-thread ${NODE_ID} hex:${DATASET} ${PIN_CODE} ${DISCRIMINATOR} + ``` + + Example: + + ``` + ./chip-tool pairing ble-thread 1234 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd61f77bd3df233e051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f010212340410445f2b5ca6f2a93a55ce570a70efeecb0c0402a0fff8 20202021 3840 + ``` + +### OTA with Linux OTA Provider + +OTA feature enabled by default only for ota-requestor-app example. To enable OTA +feature for another Telink example: + +- set CONFIG_CHIP_OTA_REQUESTOR=y in corresponding "prj.conf" configuration + file. + +After build application with enabled OTA feature, use next binary files: + +- zephyr.bin - main binary to flash PCB (Use 2MB PCB). +- zephyr-ota.bin - binary for OTA Provider + +All binaries has the same SW version. To test OTA “zephyr-ota.bin” should have +higher SW version than base SW. Set CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=2 in +corresponding “prj.conf” configuration file. + +Usage of OTA: + +- Build the [Linux OTA Provider](../../ota-provider-app/linux) + + ``` + ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false + ``` + +- Run the Linux OTA Provider with OTA image. + + ``` + ./chip-ota-provider-app -f zephyr-ota.bin + ``` + +- Provision the Linux OTA Provider using chip-tool + + ``` + ./chip-tool pairing onnetwork ${OTA_PROVIDER_NODE_ID} 20202021 + ``` + + here: + + - \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider + +- Configure the ACL of the ota-provider-app to allow access + + ``` + ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' ${OTA_PROVIDER_NODE_ID} 0 + ``` + + here: + + - \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider + +- Use the chip-tool to announce the ota-provider-app to start the OTA process + + ``` + ./chip-tool otasoftwareupdaterequestor announce-ota-provider ${OTA_PROVIDER_NODE_ID} 0 0 0 ${DEVICE_NODE_ID} 0 + ``` + + here: + + - \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider + - \${DEVICE_NODE_ID} is the node id of paired device + +Once the transfer is complete, OTA requestor sends ApplyUpdateRequest command to +OTA provider for applying the image. Device will restart on successful +application of OTA image. diff --git a/examples/thermostat/telink/include/AppConfig.h b/examples/thermostat/telink/include/AppConfig.h new file mode 100755 index 00000000000000..d852da9edb0417 --- /dev/null +++ b/examples/thermostat/telink/include/AppConfig.h @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// ---- Thermostat Example App Config ---- + +// Buttons config +#define BUTTON_PORT DEVICE_DT_GET(DT_NODELABEL(gpioc)) + +#define BUTTON_PIN_1 2 +#define BUTTON_PIN_3 3 +#define BUTTON_PIN_4 1 +#define BUTTON_PIN_2 0 + +// LEDs config +// System led config +#define SYSTEM_STATE_LED_PORT DEVICE_DT_GET(DT_NODELABEL(gpiob)) +#define SYSTEM_STATE_LED_PIN 7 diff --git a/examples/thermostat/telink/include/AppEvent.h b/examples/thermostat/telink/include/AppEvent.h new file mode 100755 index 00000000000000..07a10228175763 --- /dev/null +++ b/examples/thermostat/telink/include/AppEvent.h @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +class LEDWidget; + +struct AppEvent +{ + enum AppEventTypes + { + kEventType_Button = 0, + kEventType_Timer, + kEventType_UpdateLedState, + kEventType_Thermostat, + kEventType_Install, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + LEDWidget * LedWidget; + } UpdateLedStateEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/thermostat/telink/include/AppTask.h b/examples/thermostat/telink/include/AppTask.h new file mode 100755 index 00000000000000..18edadc0436845 --- /dev/null +++ b/examples/thermostat/telink/include/AppTask.h @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "AppEvent.h" +#include "LEDWidget.h" +#include "SensorManager.h" +#include "TemperatureManager.h" + +#include + +#include + +#if CONFIG_CHIP_FACTORY_DATA +#include +#endif + +#include + +struct k_timer; + +class AppTask +{ +public: + CHIP_ERROR StartApp(); + + void PostEvent(AppEvent * event); + void UpdateClusterState(); + void UpdateThermoStatUI(); + +private: + friend AppTask & GetAppTask(void); + CHIP_ERROR Init(); + + void DispatchEvent(AppEvent * event); + + static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget * ledWidget); + static void FactoryResetButtonEventHandler(void); + static void StartThreadButtonEventHandler(void); + static void StartBleAdvButtonEventHandler(void); + + static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + + static void FactoryResetTimerTimeoutCallback(k_timer * timer); + + static void FactoryResetTimerEventHandler(AppEvent * aEvent); + static void FactoryResetHandler(AppEvent * aEvent); + static void StartThreadHandler(AppEvent * aEvent); + static void StartBleAdvHandler(AppEvent * aEvent); + static void UpdateLedStateEventHandler(AppEvent * aEvent); + + static void InitButtons(void); + + static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + + static AppTask sAppTask; + +#if CONFIG_CHIP_FACTORY_DATA + // chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; + chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; +#endif +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/thermostat/telink/include/CHIPProjectConfig.h b/examples/thermostat/telink/include/CHIPProjectConfig.h new file mode 100755 index 00000000000000..ade0219ab5da91 --- /dev/null +++ b/examples/thermostat/telink/include/CHIPProjectConfig.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// Use a default pairing code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE + * + * Reduce packet buffer pool size to 8 (default 15) to reduce ram consumption + */ +#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE 8 diff --git a/examples/thermostat/telink/include/SensorManager.h b/examples/thermostat/telink/include/SensorManager.h new file mode 100644 index 00000000000000..828b3ef01d6120 --- /dev/null +++ b/examples/thermostat/telink/include/SensorManager.h @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +#include +#include + +class SensorManager +{ +public: + CHIP_ERROR Init(); + +private: + friend SensorManager & SensorMgr(); + + // Reads new generated sensor value, stores it, and updates local temperature attribute + static void TimerEventHandler(k_timer * timer); + static void SensorTimerEventHandler(AppEvent * aEvent); + + static SensorManager sSensorManager; +}; + +inline SensorManager & SensorMgr() +{ + return SensorManager::sSensorManager; +} diff --git a/examples/thermostat/telink/include/TemperatureManager.h b/examples/thermostat/telink/include/TemperatureManager.h new file mode 100644 index 00000000000000..c55f064f8b8ecb --- /dev/null +++ b/examples/thermostat/telink/include/TemperatureManager.h @@ -0,0 +1,67 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +#include + +#include + +using namespace chip; + +// AppCluster Spec Table 85. +enum ThermMode +{ + OFF = 0, + AUTO, + NOT_USED, + COOL, + HEAT, +}; + +class TemperatureManager +{ +public: + CHIP_ERROR Init(); + void AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size); + uint8_t GetMode(); + int8_t GetCurrentTemp(); + int8_t GetHeatingSetPoint(); + int8_t GetCoolingSetPoint(); + +private: + friend TemperatureManager & TempMgr(); + + int8_t mCurrentTempCelsius; + int8_t mCoolingCelsiusSetPoint; + int8_t mHeatingCelsiusSetPoint; + uint8_t mThermMode; + + int8_t ConvertToPrintableTemp(int16_t temperature); + static TemperatureManager sTempMgr; +}; + +inline TemperatureManager & TempMgr() +{ + return TemperatureManager::sTempMgr; +} diff --git a/examples/thermostat/telink/prj.conf b/examples/thermostat/telink/prj.conf new file mode 100755 index 00000000000000..ad1e20d32e9b78 --- /dev/null +++ b/examples/thermostat/telink/prj.conf @@ -0,0 +1,58 @@ +# +# Copyright (c) 2022 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This sample uses sample-defaults.conf to set options common for all +# samples. This file should contain only options specific for this sample +# or overrides of default values. + +# enable GPIO +CONFIG_GPIO=y + +# OpenThread configs +CONFIG_OPENTHREAD_MTD=y +CONFIG_OPENTHREAD_FTD=n + +# Default OpenThread network settings +CONFIG_OPENTHREAD_PANID=4660 +CONFIG_OPENTHREAD_CHANNEL=15 +CONFIG_OPENTHREAD_NETWORK_NAME="OpenThreadDemo" +CONFIG_OPENTHREAD_XPANID="11:11:11:11:22:22:22:22" +CONFIG_NET_CONFIG_IEEE802154_DEV_NAME="IEEE802154_b91" + +# Disable Matter OTA DFU +CONFIG_CHIP_OTA_REQUESTOR=n + +# CHIP configuration +CONFIG_CHIP_PROJECT_CONFIG="include/CHIPProjectConfig.h" +CONFIG_CHIP_OPENTHREAD_CONFIG="../../platform/telink/project_include/OpenThreadConfig.h" + +CONFIG_CHIP_DEVICE_VENDOR_ID=65521 +# 32782 == 0x800E (example thermostat) +CONFIG_CHIP_DEVICE_PRODUCT_ID=32782 +CONFIG_CHIP_DEVICE_TYPE=65535 + +CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=1 +CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING="2022" + +# Enable CHIP pairing automatically on application start. +CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y + +# CHIP shell +CONFIG_CHIP_LIB_SHELL=n + +# Disable factory data support. +CONFIG_CHIP_FACTORY_DATA=n +CONFIG_CHIP_FACTORY_DATA_BUILD=n \ No newline at end of file diff --git a/examples/thermostat/telink/src/AppTask.cpp b/examples/thermostat/telink/src/AppTask.cpp new file mode 100644 index 00000000000000..066573e4fdce85 --- /dev/null +++ b/examples/thermostat/telink/src/AppTask.cpp @@ -0,0 +1,432 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" + +#include "AppConfig.h" +#include "AppEvent.h" +#include "ButtonManager.h" + +#include "ThreadUtil.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if CONFIG_CHIP_OTA_REQUESTOR +#include "OTAUtil.h" +#endif + +#include +#include + +#include + +LOG_MODULE_DECLARE(app); + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + +namespace { +constexpr int kFactoryResetTriggerTimeout = 2000; +constexpr int kAppEventQueueSize = 10; +constexpr uint8_t kButtonPushEvent = 1; +constexpr uint8_t kButtonReleaseEvent = 0; + +// NOTE! This key is for test/certification only and should not be available in production devices! +// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + +K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); +k_timer sFactoryResetTimer; + +LEDWidget sStatusLED; + +Button sFactoryResetButton; +Button sThreadStartButton; +Button sBleAdvStartButton; + +bool sIsThreadProvisioned = false; +bool sIsThreadEnabled = false; +bool sIsThreadAttached = false; +bool sHaveBLEConnections = false; +bool sIsFactoryResetTimerActive = false; + +chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; + +void OnIdentifyTriggerEffect(Identify * identify) +{ + switch (identify->mCurrentEffectIdentifier) + { + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK"); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE"); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY"); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE: + ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE"); + break; + default: + ChipLogProgress(Zcl, "No identifier effect"); + break; + } + return; +} + +Identify sIdentify = { + chip::EndpointId{ 1 }, + [](Identify *) { ChipLogProgress(Zcl, "OnIdentifyStart"); }, + [](Identify *) { ChipLogProgress(Zcl, "OnIdentifyStop"); }, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, + OnIdentifyTriggerEffect, +}; + +} // namespace + +AppTask AppTask::sAppTask; + +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err; + + LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION, + CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + // Initialize status LED + LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); + sStatusLED.Init(SYSTEM_STATE_LED_PIN); + + UpdateStatusLED(); + + InitButtons(); + + // Initialize function button timer + k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&sFactoryResetTimer, this); + + // Initialize CHIP server +#if CONFIG_CHIP_FACTORY_DATA + ReturnErrorOnFailure(mFactoryDataProvider.Init()); + SetDeviceInstanceInfoProvider(&mFactoryDataProvider); + SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider); + SetCommissionableDataProvider(&mFactoryDataProvider); + // Read EnableKey from the factory data. + MutableByteSpan enableKey(sTestEventTriggerEnableKey); + err = mFactoryDataProvider.GetEnableKey(enableKey); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger"); + memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); + } +#else + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + + static CommonCaseDeviceServerInitParams initParams; + // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + // initParams.testEventTriggerDelegate = &testEventTriggerDelegate; + ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams)); + + gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); + chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); + +#if CONFIG_CHIP_OTA_REQUESTOR + InitBasicOTARequestor(); +#endif + + ConfigurationMgr().LogDeviceConfig(); + PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + + // Add CHIP event handler and start CHIP thread. + // Note that all the initialization code should happen prior to this point to avoid data races + // between the main and the CHIP threads. + PlatformMgr().AddEventHandler(ChipEventHandler, 0); + + err = SensorMgr().Init(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("SensorMgr::Init() failed"); + return err; + } + err = TempMgr().Init(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("TempMgr::Init() failed"); + return err; + } + + err = ConnectivityMgr().SetBLEDeviceName("TelinkThermo"); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("Fail to set BLE device name"); + } + + return err; +} + +CHIP_ERROR AppTask::StartApp() +{ + CHIP_ERROR err = Init(); + + if (err != CHIP_NO_ERROR) + { + LOG_ERR("AppTask.Init() failed"); + return err; + } + + AppEvent event = {}; + + while (true) + { + int ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10)); + + while (!ret) + { + DispatchEvent(&event); + ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); + } + } +} + +void AppTask::UpdateThermoStatUI() +{ + LOG_INF("Thermostat Status - M:%d T:%d'C H:%d'C C:%d'C", TempMgr().GetMode(), TempMgr().GetCurrentTemp(), + TempMgr().GetHeatingSetPoint(), TempMgr().GetCoolingSetPoint()); +} + +void AppTask::FactoryResetButtonEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = FactoryResetHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetHandler(AppEvent * aEvent) +{ + if (!sIsFactoryResetTimerActive) + { + k_timer_start(&sFactoryResetTimer, K_MSEC(kFactoryResetTriggerTimeout), K_NO_WAIT); + sIsFactoryResetTimerActive = true; + } + else + { + k_timer_stop(&sFactoryResetTimer); + sIsFactoryResetTimerActive = false; + } +} + +void AppTask::StartThreadButtonEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = StartThreadHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::StartThreadHandler(AppEvent * aEvent) +{ + + if (!chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned()) + { + // Switch context from BLE to Thread + Internal::BLEManagerImpl sInstance; + sInstance.SwitchToIeee802154(); + StartDefaultThreadNetwork(); + LOG_INF("Device is not commissioned to a Thread network. Starting with the default configuration."); + } + else + { + LOG_INF("Device is commissioned to a Thread network."); + } +} + +void AppTask::StartBleAdvButtonEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = StartBleAdvHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::StartBleAdvHandler(AppEvent * aEvent) +{ + LOG_INF("BLE advertising start button pressed"); + + // Don't allow on starting Matter service BLE advertising after Thread provisioning. + if (ConnectivityMgr().IsThreadProvisioned()) + { + LOG_INF("Matter service BLE advertising not started - device is commissioned to a Thread network."); + return; + } + + if (ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + LOG_INF("BLE advertising is already enabled"); + return; + } + + if (chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR) + { + LOG_ERR("OpenBasicCommissioningWindow() failed"); + } +} + +void AppTask::UpdateLedStateEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateLedState) + { + aEvent->UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void AppTask::LEDStateUpdateHandler(LEDWidget * ledWidget) +{ + AppEvent event; + event.Type = AppEvent::kEventType_UpdateLedState; + event.Handler = UpdateLedStateEventHandler; + event.UpdateLedStateEvent.LedWidget = ledWidget; + sAppTask.PostEvent(&event); +} + +void AppTask::UpdateStatusLED() +{ + if (sIsThreadProvisioned && sIsThreadEnabled) + { + if (sIsThreadAttached) + { + sStatusLED.Blink(950, 50); + } + else + { + sStatusLED.Blink(100, 100); + } + } + else + { + sStatusLED.Blink(50, 950); + } +} + +void AppTask::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLEAdvertisingChange: + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + sIsThreadAttached = ConnectivityMgr().IsThreadAttached(); + UpdateStatusLED(); + break; + case DeviceEventType::kThreadConnectivityChange: +#if CONFIG_CHIP_OTA_REQUESTOR + if (event->ThreadConnectivityChange.Result == kConnectivity_Established) + { + InitBasicOTARequestor(); + } +#endif + break; + default: + break; + } +} + +void AppTask::PostEvent(AppEvent * aEvent) +{ + if (k_msgq_put(&sAppEventQueue, aEvent, K_NO_WAIT) != 0) + { + LOG_INF("Failed to post event to app task event queue"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + LOG_INF("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateClusterState() {} + +void AppTask::FactoryResetTimerTimeoutCallback(k_timer * timer) +{ + if (!timer) + { + return; + } + + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.Handler = FactoryResetTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FactoryResetTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + sIsFactoryResetTimerActive = false; + LOG_INF("FactoryResetHandler"); + chip::Server::GetInstance().ScheduleFactoryReset(); +} + +void AppTask::InitButtons(void) +{ + sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, true, FactoryResetButtonEventHandler); + sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, false, StartThreadButtonEventHandler); + sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, false, StartBleAdvButtonEventHandler); + + ButtonManagerInst().AddButton(sFactoryResetButton); + ButtonManagerInst().AddButton(sThreadStartButton); + ButtonManagerInst().AddButton(sBleAdvStartButton); +} diff --git a/examples/thermostat/telink/src/SensorManager.cpp b/examples/thermostat/telink/src/SensorManager.cpp new file mode 100644 index 00000000000000..c692ae9c95394c --- /dev/null +++ b/examples/thermostat/telink/src/SensorManager.cpp @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SensorManager.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "AppTask.h" + +LOG_MODULE_DECLARE(app); + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr EndpointId kThermostatEndpoint = 1; +constexpr uint16_t kSensorTimerPeriodMs = 30000; // 30s timer period +constexpr uint16_t kMinTemperatureDelta = 50; // 0.5 degree Celsius + +k_timer sSensorTimer; + +SensorManager SensorManager::sSensorManager; + +constexpr uint16_t kSimulatedReadingFrequency = (60000 / kSensorTimerPeriodMs); // Change Simulated number at each minutes +static int16_t mSimulatedTemp[] = { 2300, 2400, 2800, 2550, 2200, 2125, 2100, 2600, 1800, 2700 }; + +CHIP_ERROR SensorManager::Init() +{ + // Initialize temp sensor timer + k_timer_init(&sSensorTimer, &TimerEventHandler, nullptr); + k_timer_user_data_set(&sSensorTimer, this); + k_timer_start(&sSensorTimer, K_MSEC(kSensorTimerPeriodMs), K_NO_WAIT); + + return CHIP_NO_ERROR; +} + +void SensorManager::TimerEventHandler(k_timer * timer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Thermostat; + event.TimerEvent.Context = k_timer_user_data_get(timer); + event.Handler = SensorTimerEventHandler; + GetAppTask().PostEvent(&event); +} + +void SensorManager::SensorTimerEventHandler(AppEvent * aEvent) +{ + int16_t temperature = 0; + static int16_t lastTemperature = 0; + + static uint8_t nbOfRepetition = 0; + static uint8_t simulatedIndex = 0; + if (simulatedIndex >= sizeof(mSimulatedTemp)) + { + simulatedIndex = 0; + } + temperature = mSimulatedTemp[simulatedIndex]; + + nbOfRepetition++; + if (nbOfRepetition >= kSimulatedReadingFrequency) + { + simulatedIndex++; + nbOfRepetition = 0; + } + + LOG_INF("Sensor Temp is : %d", temperature); + + if ((temperature >= (lastTemperature + kMinTemperatureDelta)) || temperature <= (lastTemperature - kMinTemperatureDelta)) + { + lastTemperature = temperature; + PlatformMgr().LockChipStack(); + app::Clusters::Thermostat::Attributes::LocalTemperature::Set(kThermostatEndpoint, temperature); + PlatformMgr().UnlockChipStack(); + } + + // Start next timer to handle temp sensor. + k_timer_start(&sSensorTimer, K_MSEC(kSensorTimerPeriodMs), K_NO_WAIT); +} diff --git a/examples/thermostat/telink/src/TemperatureManager.cpp b/examples/thermostat/telink/src/TemperatureManager.cpp new file mode 100644 index 00000000000000..9798cc0d360e8b --- /dev/null +++ b/examples/thermostat/telink/src/TemperatureManager.cpp @@ -0,0 +1,139 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TemperatureManager.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "AppTask.h" +#include + +LOG_MODULE_DECLARE(app); + +using namespace chip; +using namespace ::chip::DeviceLayer; + +constexpr EndpointId kThermostatEndpoint = 1; + +namespace ThermAttr = chip::app::Clusters::Thermostat::Attributes; + +TemperatureManager TemperatureManager::sTempMgr; + +CHIP_ERROR TemperatureManager::Init() +{ + app::DataModel::Nullable temp; + int16_t heatingSetpoint, coolingSetpoint; + uint8_t systemMode; + + PlatformMgr().LockChipStack(); + ThermAttr::LocalTemperature::Get(kThermostatEndpoint, temp); + ThermAttr::OccupiedCoolingSetpoint::Get(kThermostatEndpoint, &coolingSetpoint); + ThermAttr::OccupiedHeatingSetpoint::Get(kThermostatEndpoint, &heatingSetpoint); + ThermAttr::SystemMode::Get(kThermostatEndpoint, &systemMode); + PlatformMgr().UnlockChipStack(); + + mCurrentTempCelsius = ConvertToPrintableTemp(temp.Value()); + mHeatingCelsiusSetPoint = ConvertToPrintableTemp(coolingSetpoint); + mCoolingCelsiusSetPoint = ConvertToPrintableTemp(heatingSetpoint); + mThermMode = systemMode; + + GetAppTask().UpdateThermoStatUI(); + + return CHIP_NO_ERROR; +} + +int8_t TemperatureManager::ConvertToPrintableTemp(int16_t temperature) +{ + constexpr uint8_t kRoundUpValue = 50; + + // Round up the temperature as we won't print decimals on LCD + // Is it a negative temperature + if (temperature < 0) + { + temperature -= kRoundUpValue; + } + else + { + temperature += kRoundUpValue; + } + + return static_cast(temperature / 100); +} + +void TemperatureManager::AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size) +{ + switch (attributeId) + { + case ThermAttr::LocalTemperature::Id: { + int8_t Temp = ConvertToPrintableTemp(*((int16_t *) value)); + LOG_INF("Local temp %d", Temp); + mCurrentTempCelsius = Temp; + } + break; + + case ThermAttr::OccupiedCoolingSetpoint::Id: { + int8_t coolingTemp = ConvertToPrintableTemp(*((int16_t *) value)); + LOG_INF("CoolingSetpoint %d", coolingTemp); + mCoolingCelsiusSetPoint = coolingTemp; + } + break; + + case ThermAttr::OccupiedHeatingSetpoint::Id: { + int8_t heatingTemp = ConvertToPrintableTemp(*((int16_t *) value)); + LOG_INF("HeatingSetpoint %d", heatingTemp); + mHeatingCelsiusSetPoint = heatingTemp; + } + break; + + case ThermAttr::SystemMode::Id: { + LOG_INF("SystemMode %d", static_cast(*value)); + uint8_t mode = static_cast(*value); + if (mThermMode != mode) + { + mThermMode = mode; + } + } + break; + + default: { + LOG_INF("Unhandled thermostat attribute %x", attributeId); + return; + } + break; + } + + GetAppTask().UpdateThermoStatUI(); +} + +uint8_t TemperatureManager::GetMode() +{ + return mThermMode; +} + +int8_t TemperatureManager::GetCurrentTemp() +{ + return mCurrentTempCelsius; +} +int8_t TemperatureManager::GetHeatingSetPoint() +{ + return mHeatingCelsiusSetPoint; +} + +int8_t TemperatureManager::GetCoolingSetPoint() +{ + return mCoolingCelsiusSetPoint; +} diff --git a/examples/thermostat/telink/src/ZclCallbacks.cpp b/examples/thermostat/telink/src/ZclCallbacks.cpp new file mode 100644 index 00000000000000..4dc43fb88c0834 --- /dev/null +++ b/examples/thermostat/telink/src/ZclCallbacks.cpp @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "TemperatureManager.h" + +#include +#include +#include +#include + +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; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == Identify::Id) + { + // Following print is used for printing single-byte value. Change it for printing non-single-byte values. + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + } + else if (clusterId == Thermostat::Id) + { + TempMgr().AttributeChangeHandler(attributePath.mEndpointId, attributeId, value, size); + } +} diff --git a/examples/thermostat/telink/src/main.cpp b/examples/thermostat/telink/src/main.cpp new file mode 100755 index 00000000000000..6fdd0367cbe006 --- /dev/null +++ b/examples/thermostat/telink/src/main.cpp @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" + +#include +#include + +#include + +LOG_MODULE_REGISTER(app); + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +int main(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + err = chip::Platform::MemoryInit(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("Platform::MemoryInit() failed"); + goto exit; + } + + LOG_INF("Init CHIP stack"); + err = PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().InitChipStack() failed"); + goto exit; + } + + LOG_INF("Starting CHIP task"); + err = PlatformMgr().StartEventLoopTask(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("PlatformMgr().StartEventLoopTask() failed"); + goto exit; + } + + LOG_INF("Init Thread stack"); + err = ThreadStackMgr().InitThreadStack(); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ThreadStackMgr().InitThreadStack() failed"); + goto exit; + } + +#ifdef CONFIG_OPENTHREAD_MTD_SED + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); +#elif CONFIG_OPENTHREAD_MTD + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); +#else + err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router); +#endif + if (err != CHIP_NO_ERROR) + { + LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed"); + goto exit; + } + + err = GetAppTask().StartApp(); + +exit: + LOG_ERR("Exited with code %" CHIP_ERROR_FORMAT, err.Format()); + return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/examples/thermostat/telink/third_party/connectedhomeip b/examples/thermostat/telink/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/thermostat/telink/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index c40dde4600d649..42598742f578e8 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -1436,6 +1436,16 @@ server cluster Thermostat = 513 { command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; } +server cluster ThermostatUserInterfaceConfiguration = 516 { + attribute enum8 temperatureDisplayMode = 0; + attribute access(write: manage) enum8 keypadLockout = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + endpoint 0 { device type rootdevice = 22; binding cluster OtaSoftwareUpdateProvider; @@ -1743,29 +1753,13 @@ endpoint 1 { ram attribute clusterRevision default = 4; } - server cluster Basic { - callback attribute dataModelRevision default = 10; - callback attribute vendorName; - callback attribute vendorID; - callback attribute productName; - callback attribute productID; - persist attribute nodeLabel; - callback attribute location default = "XX"; - callback attribute hardwareVersion; - callback attribute hardwareVersionString; - callback attribute softwareVersion; - callback attribute softwareVersionString; - callback attribute manufacturingDate default = "20210614123456ZZ"; - callback attribute partNumber; - callback attribute productURL; - callback attribute productLabel; - callback attribute serialNumber; - persist attribute localConfigDisabled; - ram attribute reachable default = 1; - callback attribute uniqueID; - callback attribute capabilityMinima; + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; ram attribute featureMap; - ram attribute clusterRevision default = 1; + callback attribute clusterRevision default = 1; } server cluster Thermostat { @@ -1774,21 +1768,31 @@ endpoint 1 { ram attribute absMaxHeatSetpointLimit default = 3000; ram attribute absMinCoolSetpointLimit default = 1600; ram attribute absMaxCoolSetpointLimit default = 3200; - ram attribute occupiedCoolingSetpoint default = 0x0A28; - ram attribute occupiedHeatingSetpoint default = 0x07D0; + persist attribute occupiedCoolingSetpoint default = 0x0A28; + persist attribute occupiedHeatingSetpoint default = 0x07D0; ram attribute minHeatSetpointLimit default = 700; ram attribute maxHeatSetpointLimit default = 3000; ram attribute minCoolSetpointLimit default = 1600; ram attribute maxCoolSetpointLimit default = 3200; ram attribute minSetpointDeadBand default = 0x19; ram attribute controlSequenceOfOperation default = 0x04; - ram attribute systemMode default = 0x01; + persist attribute systemMode default = 0x01; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0x23; ram attribute clusterRevision default = 5; } + + server cluster ThermostatUserInterfaceConfiguration { + ram attribute temperatureDisplayMode; + ram attribute keypadLockout; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap; + ram attribute clusterRevision default = 1; + } } diff --git a/examples/thermostat/thermostat-common/thermostat.zap b/examples/thermostat/thermostat-common/thermostat.zap index 42ea872d369602..88d4a07f2c3362 100644 --- a/examples/thermostat/thermostat-common/thermostat.zap +++ b/examples/thermostat/thermostat-common/thermostat.zap @@ -1,5 +1,5 @@ { - "featureLevel": 80, + "featureLevel": 81, "creator": "zap", "keyValuePairs": [ { @@ -8592,7 +8592,7 @@ "mfgCode": null, "define": "DESCRIPTOR_CLUSTER", "side": "server", - "enabled": 0, + "enabled": 1, "attributes": [ { "name": "DeviceTypeList", @@ -8658,6 +8658,22 @@ "maxInterval": 65344, "reportableChange": 0 }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "ClusterRevision", "code": 65533, @@ -8776,7 +8792,7 @@ "mfgCode": null, "define": "BASIC_CLUSTER", "side": "server", - "enabled": 1, + "enabled": 0, "attributes": [ { "name": "DataModelRevision", @@ -11119,7 +11135,7 @@ "side": "server", "type": "int16s", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x0A28", @@ -11135,7 +11151,7 @@ "side": "server", "type": "int16s", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x07D0", @@ -11247,7 +11263,7 @@ "side": "server", "type": "enum8", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x01", @@ -11386,6 +11402,186 @@ } ] }, + { + "name": "Thermostat User Interface Configuration", + "code": 516, + "mfgCode": null, + "define": "THERMOSTAT_UI_CONFIG_CLUSTER", + "side": "client", + "enabled": 0, + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat User Interface Configuration", + "code": 516, + "mfgCode": null, + "define": "THERMOSTAT_UI_CONFIG_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "temperature display mode", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "keypad lockout", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "schedule programming visibility", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "enum8", + "included": 0, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Color Control", "code": 768, @@ -14354,5 +14550,6 @@ "endpointVersion": 1, "deviceIdentifier": 769 } - ] + ], + "log": [] } \ No newline at end of file diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index e9743e736dd7cd..2f0e9f29a6e8bb 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -688,12 +688,16 @@ def GenioTargets(): board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.ALL_CLUSTERS)) ALL.append(Target('telink-tlsr9518adk80d-all-clusters-minimal', TelinkBuilder, board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.ALL_CLUSTERS_MINIMAL)) +ALL.append(Target('telink-tlsr9518adk80d-contact-sensor', TelinkBuilder, + board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.CONTACT_SENSOR)) ALL.append(Target('telink-tlsr9518adk80d-light', TelinkBuilder, board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.LIGHT)) ALL.append(Target('telink-tlsr9518adk80d-light-switch', TelinkBuilder, board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.SWITCH)) ALL.append(Target('telink-tlsr9518adk80d-ota-requestor', TelinkBuilder, board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.OTA_REQUESTOR)) +ALL.append(Target('telink-tlsr9518adk80d-thermostat', TelinkBuilder, + board=TelinkBoard.TLSR9518ADK80D, app=TelinkApp.THERMOSTAT)) # have a consistent order overall ALL.sort(key=lambda t: t.name) diff --git a/scripts/build/builders/telink.py b/scripts/build/builders/telink.py index 9b448e5b3f9023..02de34a809bc33 100644 --- a/scripts/build/builders/telink.py +++ b/scripts/build/builders/telink.py @@ -23,21 +23,27 @@ class TelinkApp(Enum): ALL_CLUSTERS = auto() ALL_CLUSTERS_MINIMAL = auto() + CONTACT_SENSOR = auto() LIGHT = auto() SWITCH = auto() OTA_REQUESTOR = auto() + THERMOSTAT = auto() def ExampleName(self): if self == TelinkApp.ALL_CLUSTERS: return 'all-clusters-app' elif self == TelinkApp.ALL_CLUSTERS_MINIMAL: return 'all-clusters-minimal-app' + elif self == TelinkApp.CONTACT_SENSOR: + return 'contact-sensor-app' elif self == TelinkApp.LIGHT: return 'lighting-app' elif self == TelinkApp.SWITCH: return 'light-switch-app' elif self == TelinkApp.OTA_REQUESTOR: return 'ota-requestor-app' + elif self == TelinkApp.THERMOSTAT: + return 'thermostat' else: raise Exception('Unknown app type: %r' % self) @@ -46,12 +52,16 @@ def AppNamePrefix(self): return 'chip-telink-all-clusters-example' elif self == TelinkApp.ALL_CLUSTERS_MINIMAL: return 'chip-telink-all-clusters-minimal-example' + elif self == TelinkApp.CONTACT_SENSOR: + return 'chip-telink-contact-sensor-example' elif self == TelinkApp.LIGHT: return 'chip-telink-lighting-example' elif self == TelinkApp.SWITCH: return 'chip-telink-light-switch-example' elif self == TelinkApp.OTA_REQUESTOR: return 'chip-telink-ota-requestor-example' + elif self == TelinkApp.THERMOSTAT: + return 'chip-telink-thermostat-example' else: raise Exception('Unknown app type: %r' % self) diff --git a/scripts/build/testdata/all_targets_except_host.txt b/scripts/build/testdata/all_targets_except_host.txt index 954ff337ce7ee0..8fa076eed3a915 100644 --- a/scripts/build/testdata/all_targets_except_host.txt +++ b/scripts/build/testdata/all_targets_except_host.txt @@ -255,9 +255,11 @@ qpg-persistent-storage qpg-shell telink-tlsr9518adk80d-all-clusters telink-tlsr9518adk80d-all-clusters-minimal +telink-tlsr9518adk80d-contact-sensor telink-tlsr9518adk80d-light telink-tlsr9518adk80d-light-switch telink-tlsr9518adk80d-ota-requestor +telink-tlsr9518adk80d-thermostat tizen-arm-all-clusters tizen-arm-all-clusters-asan (NOGLOB: Reduce default build variants) tizen-arm-all-clusters-minimal diff --git a/scripts/build/testdata/build_all_except_host.txt b/scripts/build/testdata/build_all_except_host.txt index 41906ef9092b8c..f446fb8471f389 100644 --- a/scripts/build/testdata/build_all_except_host.txt +++ b/scripts/build/testdata/build_all_except_host.txt @@ -1198,6 +1198,13 @@ export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" source "$ZEPHYR_BASE/zephyr-env.sh"; west build --cmake-only -d {out}/telink-tlsr9518adk80d-all-clusters-minimal -b tlsr9518adk80d {root}/examples/all-clusters-minimal-app/telink' +# Generating telink-tlsr9518adk80d-contact-sensor +bash -c 'export ZEPHYR_TOOLCHAIN_VARIANT=zephyr +export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" +export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" +source "$ZEPHYR_BASE/zephyr-env.sh"; +west build --cmake-only -d {out}/telink-tlsr9518adk80d-contact-sensor -b tlsr9518adk80d {root}/examples/contact-sensor-app/telink' + # Generating telink-tlsr9518adk80d-light bash -c 'export ZEPHYR_TOOLCHAIN_VARIANT=zephyr export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" @@ -1219,6 +1226,13 @@ export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" source "$ZEPHYR_BASE/zephyr-env.sh"; west build --cmake-only -d {out}/telink-tlsr9518adk80d-ota-requestor -b tlsr9518adk80d {root}/examples/ota-requestor-app/telink' +# Generating telink-tlsr9518adk80d-thermostat +bash -c 'export ZEPHYR_TOOLCHAIN_VARIANT=zephyr +export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" +export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" +source "$ZEPHYR_BASE/zephyr-env.sh"; +west build --cmake-only -d {out}/telink-tlsr9518adk80d-thermostat -b tlsr9518adk80d {root}/examples/thermostat/telink' + # Generating tizen-arm-all-clusters gn gen --check --fail-on-unused-args --export-compile-commands --root={root}/examples/all-clusters-app/tizen '--args=target_os="tizen" target_cpu="arm" tizen_sdk_root="TEST_TIZEN_SDK_ROOT" tizen_sdk_sysroot="TEST_TIZEN_SDK_SYSROOT"' {out}/tizen-arm-all-clusters @@ -2467,6 +2481,12 @@ export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" ninja -C {out}/telink-tlsr9518adk80d-all-clusters-minimal' +# Building telink-tlsr9518adk80d-contact-sensor +bash -c 'export ZEPHYR_TOOLCHAIN_VARIANT=zephyr +export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" +export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" +ninja -C {out}/telink-tlsr9518adk80d-contact-sensor' + # Building telink-tlsr9518adk80d-light bash -c 'export ZEPHYR_TOOLCHAIN_VARIANT=zephyr export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" @@ -2485,6 +2505,12 @@ export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" ninja -C {out}/telink-tlsr9518adk80d-ota-requestor' +# Building telink-tlsr9518adk80d-thermostat +bash -c 'export ZEPHYR_TOOLCHAIN_VARIANT=zephyr +export ZEPHYR_BASE="$TELINK_ZEPHYR_BASE" +export ZEPHYR_SDK_INSTALL_DIR="$TELINK_ZEPHYR_SDK_DIR" +ninja -C {out}/telink-tlsr9518adk80d-thermostat' + # Building tizen-arm-all-clusters ninja -C {out}/tizen-arm-all-clusters diff --git a/scripts/build/testdata/glob_star_targets_except_host.txt b/scripts/build/testdata/glob_star_targets_except_host.txt index 7350e77e5be29e..3dab0914aba67f 100644 --- a/scripts/build/testdata/glob_star_targets_except_host.txt +++ b/scripts/build/testdata/glob_star_targets_except_host.txt @@ -120,9 +120,11 @@ qpg-persistent-storage qpg-shell telink-tlsr9518adk80d-all-clusters telink-tlsr9518adk80d-all-clusters-minimal +telink-tlsr9518adk80d-contact-sensor telink-tlsr9518adk80d-light telink-tlsr9518adk80d-light-switch telink-tlsr9518adk80d-ota-requestor +telink-tlsr9518adk80d-thermostat tizen-arm-all-clusters tizen-arm-all-clusters-minimal tizen-arm-chip-tool diff --git a/src/lib/shell/MainLoopZephyr.cpp b/src/lib/shell/MainLoopZephyr.cpp index e70a29c52c9dce..17b5d8438499a5 100644 --- a/src/lib/shell/MainLoopZephyr.cpp +++ b/src/lib/shell/MainLoopZephyr.cpp @@ -14,8 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include +#include +#include #include #include diff --git a/src/lib/shell/streamer_zephyr.cpp b/src/lib/shell/streamer_zephyr.cpp index 40a16d56fbbd94..aad69438ab24b0 100644 --- a/src/lib/shell/streamer_zephyr.cpp +++ b/src/lib/shell/streamer_zephyr.cpp @@ -24,8 +24,8 @@ #include -#include -#include +#include +#include namespace chip { namespace Shell { diff --git a/zzz_generated/thermostat/zap-generated/PluginApplicationCallbacks.h b/zzz_generated/thermostat/zap-generated/PluginApplicationCallbacks.h index fc1f15a7696df2..0adc2ae1e1b04b 100644 --- a/zzz_generated/thermostat/zap-generated/PluginApplicationCallbacks.h +++ b/zzz_generated/thermostat/zap-generated/PluginApplicationCallbacks.h @@ -48,4 +48,5 @@ MatterGroupKeyManagementPluginServerInitCallback(); \ MatterFixedLabelPluginServerInitCallback(); \ MatterUserLabelPluginServerInitCallback(); \ - MatterThermostatPluginServerInitCallback(); + MatterThermostatPluginServerInitCallback(); \ + MatterThermostatUserInterfaceConfigurationPluginServerInitCallback(); diff --git a/zzz_generated/thermostat/zap-generated/access.h b/zzz_generated/thermostat/zap-generated/access.h index 8babb2f23818a1..794789b5c57838 100644 --- a/zzz_generated/thermostat/zap-generated/access.h +++ b/zzz_generated/thermostat/zap-generated/access.h @@ -54,6 +54,7 @@ /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: view */ \ /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: view */ \ /* Cluster: Thermostat, Attribute: SystemMode, Privilege: view */ \ + /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: view */ \ } // Parallel array data (cluster, *attribute*, privilege) for read attribute @@ -83,6 +84,7 @@ /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: view */ \ /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: view */ \ /* Cluster: Thermostat, Attribute: SystemMode, Privilege: view */ \ + /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: view */ \ } // Parallel array data (cluster, attribute, *privilege*) for read attribute @@ -112,6 +114,7 @@ /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: view */ \ /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: view */ \ /* Cluster: Thermostat, Attribute: SystemMode, Privilege: view */ \ + /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: view */ \ } //////////////////////////////////////////////////////////////////////////////// @@ -134,6 +137,7 @@ 513, /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: manage */ \ 513, /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: manage */ \ 513, /* Cluster: Thermostat, Attribute: SystemMode, Privilege: manage */ \ + 516, /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: manage */ \ } // Parallel array data (cluster, *attribute*, privilege) for write attribute @@ -154,6 +158,7 @@ 25, /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: manage */ \ 27, /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: manage */ \ 28, /* Cluster: Thermostat, Attribute: SystemMode, Privilege: manage */ \ + 1, /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: manage */ \ } // Parallel array data (cluster, attribute, *privilege*) for write attribute @@ -174,6 +179,7 @@ kMatterAccessPrivilegeManage, /* Cluster: Thermostat, Attribute: MinSetpointDeadBand, Privilege: manage */ \ kMatterAccessPrivilegeManage, /* Cluster: Thermostat, Attribute: ControlSequenceOfOperation, Privilege: manage */ \ kMatterAccessPrivilegeManage, /* Cluster: Thermostat, Attribute: SystemMode, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Thermostat User Interface Configuration, Attribute: keypad lockout, Privilege: manage */ \ } //////////////////////////////////////////////////////////////////////////////// diff --git a/zzz_generated/thermostat/zap-generated/callback-stub.cpp b/zzz_generated/thermostat/zap-generated/callback-stub.cpp index 46ed91ffbe0fef..49d2cd092efe0a 100644 --- a/zzz_generated/thermostat/zap-generated/callback-stub.cpp +++ b/zzz_generated/thermostat/zap-generated/callback-stub.cpp @@ -92,6 +92,9 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_THERMOSTAT_CLUSTER_ID: emberAfThermostatClusterInitCallback(endpoint); break; + case ZCL_THERMOSTAT_UI_CONFIG_CLUSTER_ID: + emberAfThermostatUserInterfaceConfigurationClusterInitCallback(endpoint); + break; case ZCL_THREAD_NETWORK_DIAGNOSTICS_CLUSTER_ID: emberAfThreadNetworkDiagnosticsClusterInitCallback(endpoint); break; @@ -218,6 +221,11 @@ void __attribute__((weak)) emberAfThermostatClusterInitCallback(EndpointId endpo // To prevent warning (void) endpoint; } +void __attribute__((weak)) emberAfThermostatUserInterfaceConfigurationClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} void __attribute__((weak)) emberAfThreadNetworkDiagnosticsClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/zzz_generated/thermostat/zap-generated/endpoint_config.h b/zzz_generated/thermostat/zap-generated/endpoint_config.h index e62831f2957e02..263d5dae3a8276 100644 --- a/zzz_generated/thermostat/zap-generated/endpoint_config.h +++ b/zzz_generated/thermostat/zap-generated/endpoint_config.h @@ -78,7 +78,7 @@ } // This is an array of EmberAfAttributeMinMaxValue structures. -#define GENERATED_MIN_MAX_DEFAULT_COUNT 11 +#define GENERATED_MIN_MAX_DEFAULT_COUNT 13 #define GENERATED_MIN_MAX_DEFAULTS \ { \ \ @@ -97,14 +97,18 @@ { (uint16_t) 0xC80, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxCoolSetpointLimit */ \ { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x19 }, /* MinSetpointDeadBand */ \ { (uint16_t) 0x4, (uint16_t) 0x0, (uint16_t) 0x5 }, /* ControlSequenceOfOperation */ \ + { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x7 }, /* SystemMode */ \ + \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x1 }, /* temperature display mode */ \ { \ - (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x7 \ - } /* SystemMode */ \ + (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x5 \ + } /* keypad lockout */ \ } #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 261 +#define GENERATED_ATTRIBUTE_COUNT 249 #define GENERATED_ATTRIBUTES \ { \ \ @@ -483,50 +487,13 @@ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(4) }, /* ClusterRevision */ \ \ - /* Endpoint: 1, Cluster: Basic (server) */ \ - { 0x00000000, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* DataModelRevision */ \ - { 0x00000001, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* VendorName */ \ - { 0x00000002, ZAP_TYPE(VENDOR_ID), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* VendorID */ \ - { 0x00000003, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductName */ \ - { 0x00000004, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductID */ \ - { 0x00000005, ZAP_TYPE(CHAR_STRING), 33, \ - ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(SINGLETON) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_EMPTY_DEFAULT() }, /* NodeLabel */ \ - { 0x00000006, ZAP_TYPE(CHAR_STRING), 3, \ - ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_EMPTY_DEFAULT() }, /* Location */ \ - { 0x00000007, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* HardwareVersion */ \ - { 0x00000008, ZAP_TYPE(CHAR_STRING), 65, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* HardwareVersionString */ \ - { 0x00000009, ZAP_TYPE(INT32U), 4, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* SoftwareVersion */ \ - { 0x0000000A, ZAP_TYPE(CHAR_STRING), 65, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* SoftwareVersionString */ \ - { 0x0000000B, ZAP_TYPE(CHAR_STRING), 17, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ManufacturingDate */ \ - { 0x0000000C, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* PartNumber */ \ - { 0x0000000D, ZAP_TYPE(LONG_CHAR_STRING), 258, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductURL */ \ - { 0x0000000E, ZAP_TYPE(CHAR_STRING), 65, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* ProductLabel */ \ - { 0x0000000F, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* SerialNumber */ \ - { 0x00000010, ZAP_TYPE(BOOLEAN), 1, \ - ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(SINGLETON) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_SIMPLE_DEFAULT(0) }, /* LocalConfigDisabled */ \ - { 0x00000011, ZAP_TYPE(BOOLEAN), 1, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_SIMPLE_DEFAULT(1) }, /* Reachable */ \ - { 0x00000012, ZAP_TYPE(CHAR_STRING), 33, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(SINGLETON), \ - ZAP_EMPTY_DEFAULT() }, /* UniqueID */ \ - { 0x00000013, ZAP_TYPE(STRUCT), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* CapabilityMinima */ \ + /* Endpoint: 1, Cluster: Descriptor (server) */ \ + { 0x00000000, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* DeviceTypeList */ \ + { 0x00000001, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* ServerList */ \ + { 0x00000002, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* ClientList */ \ + { 0x00000003, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* PartsList */ \ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ - { 0x0000FFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(SINGLETON), ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ + { 0x0000FFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* ClusterRevision */ \ \ /* Endpoint: 1, Cluster: Thermostat (server) */ \ { 0x00000000, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(NULLABLE), ZAP_EMPTY_DEFAULT() }, /* LocalTemperature */ \ @@ -534,9 +501,11 @@ { 0x00000004, ZAP_TYPE(INT16S), 2, 0, ZAP_SIMPLE_DEFAULT(3000) }, /* AbsMaxHeatSetpointLimit */ \ { 0x00000005, ZAP_TYPE(INT16S), 2, 0, ZAP_SIMPLE_DEFAULT(1600) }, /* AbsMinCoolSetpointLimit */ \ { 0x00000006, ZAP_TYPE(INT16S), 2, 0, ZAP_SIMPLE_DEFAULT(3200) }, /* AbsMaxCoolSetpointLimit */ \ - { 0x00000011, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + { 0x00000011, ZAP_TYPE(INT16S), 2, \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(2) }, /* OccupiedCoolingSetpoint */ \ - { 0x00000012, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + { 0x00000012, ZAP_TYPE(INT16S), 2, \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(3) }, /* OccupiedHeatingSetpoint */ \ { 0x00000015, ZAP_TYPE(INT16S), 2, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(4) }, /* MinHeatSetpointLimit */ \ @@ -550,10 +519,19 @@ ZAP_MIN_MAX_DEFAULTS_INDEX(8) }, /* MinSetpointDeadBand */ \ { 0x0000001B, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(9) }, /* ControlSequenceOfOperation */ \ - { 0x0000001C, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + { 0x0000001C, ZAP_TYPE(ENUM8), 1, \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ ZAP_MIN_MAX_DEFAULTS_INDEX(10) }, /* SystemMode */ \ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0x23) }, /* FeatureMap */ \ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(5) }, /* ClusterRevision */ \ + \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + { 0x00000000, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + ZAP_MIN_MAX_DEFAULTS_INDEX(11) }, /* temperature display mode */ \ + { 0x00000001, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE), \ + ZAP_MIN_MAX_DEFAULTS_INDEX(12) }, /* keypad lockout */ \ + { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ + { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ } // This is an array of EmberAfCluster structures. @@ -587,6 +565,9 @@ const EmberAfGenericClusterFunction chipFuncArrayThermostatServer[] = { \ (EmberAfGenericClusterFunction) emberAfThermostatClusterServerInitCallback, \ (EmberAfGenericClusterFunction) MatterThermostatClusterServerPreAttributeChangedCallback, \ + }; \ + const EmberAfGenericClusterFunction chipFuncArrayThermostatUserInterfaceConfigurationServer[] = { \ + (EmberAfGenericClusterFunction) MatterThermostatUserInterfaceConfigurationClusterServerPreAttributeChangedCallback, \ }; // clang-format off @@ -704,7 +685,7 @@ // clang-format on #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 29 +#define GENERATED_CLUSTER_COUNT 30 // clang-format off #define GENERATED_CLUSTERS { \ @@ -1006,20 +987,20 @@ .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 69 ) ,\ },\ { \ - /* Endpoint: 1, Cluster: Basic (server) */ \ - .clusterId = 0x00000028, \ + /* Endpoint: 1, Cluster: Descriptor (server) */ \ + .clusterId = 0x0000001D, \ .attributes = ZAP_ATTRIBUTE_INDEX(223), \ - .attributeCount = 22, \ - .clusterSize = 41, \ - .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ - .functions = chipFuncArrayBasicServer, \ + .attributeCount = 6, \ + .clusterSize = 4, \ + .mask = ZAP_CLUSTER_MASK(SERVER), \ + .functions = NULL, \ .acceptedCommandList = nullptr ,\ .generatedCommandList = nullptr ,\ },\ { \ /* Endpoint: 1, Cluster: Thermostat (server) */ \ .clusterId = 0x00000201, \ - .attributes = ZAP_ATTRIBUTE_INDEX(245), \ + .attributes = ZAP_ATTRIBUTE_INDEX(229), \ .attributeCount = 16, \ .clusterSize = 31, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ @@ -1027,18 +1008,29 @@ .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 76 ) ,\ .generatedCommandList = nullptr ,\ },\ + { \ + /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ + .clusterId = 0x00000204, \ + .attributes = ZAP_ATTRIBUTE_INDEX(245), \ + .attributeCount = 4, \ + .clusterSize = 8, \ + .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ + .functions = chipFuncArrayThermostatUserInterfaceConfigurationServer, \ + .acceptedCommandList = nullptr ,\ + .generatedCommandList = nullptr ,\ + },\ } // clang-format on #define ZAP_CLUSTER_INDEX(index) (&generatedClusters[index]) -#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 27 +#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 28 // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 23, 259 }, { ZAP_CLUSTER_INDEX(23), 6, 100 }, \ + { ZAP_CLUSTER_INDEX(0), 23, 259 }, { ZAP_CLUSTER_INDEX(23), 7, 71 }, \ } // Largest attribute size is needed for various buffers @@ -1047,10 +1039,10 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, "ATTRIBUTE_LARGEST larger than expected"); // Total size of singleton attributes -#define ATTRIBUTE_SINGLETONS_SIZE (74) +#define ATTRIBUTE_SINGLETONS_SIZE (37) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (359) +#define ATTRIBUTE_MAX_SIZE (330) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (2) diff --git a/zzz_generated/thermostat/zap-generated/gen_config.h b/zzz_generated/thermostat/zap-generated/gen_config.h index 35f4e7dd8ef7de..9138ba67e85224 100644 --- a/zzz_generated/thermostat/zap-generated/gen_config.h +++ b/zzz_generated/thermostat/zap-generated/gen_config.h @@ -33,10 +33,10 @@ #define EMBER_AF_IDENTIFY_CLUSTER_SERVER_ENDPOINT_COUNT (2) #define EMBER_AF_GROUPS_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_SCENES_CLUSTER_SERVER_ENDPOINT_COUNT (1) -#define EMBER_AF_DESCRIPTOR_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_DESCRIPTOR_CLUSTER_SERVER_ENDPOINT_COUNT (2) #define EMBER_AF_BINDING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_ACCESS_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT (1) -#define EMBER_AF_BASIC_CLUSTER_SERVER_ENDPOINT_COUNT (2) +#define EMBER_AF_BASIC_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_PROVIDER_CLUSTER_CLIENT_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_REQUESTOR_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_LOCALIZATION_CONFIGURATION_CLUSTER_SERVER_ENDPOINT_COUNT (1) @@ -56,6 +56,7 @@ #define EMBER_AF_FIXED_LABEL_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_USER_LABEL_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_THERMOSTAT_UI_CONFIG_CLUSTER_SERVER_ENDPOINT_COUNT (1) /**** Cluster Plugins ****/ @@ -203,3 +204,8 @@ #define ZCL_USING_THERMOSTAT_CLUSTER_SERVER #define EMBER_AF_PLUGIN_THERMOSTAT_SERVER #define EMBER_AF_PLUGIN_THERMOSTAT + +// Use this macro to check if the server side of the Thermostat User Interface Configuration cluster is included +#define ZCL_USING_THERMOSTAT_UI_CONFIG_CLUSTER_SERVER +#define EMBER_AF_PLUGIN_THERMOSTAT_USER_INTERFACE_CONFIGURATION_SERVER +#define EMBER_AF_PLUGIN_THERMOSTAT_USER_INTERFACE_CONFIGURATION