From bbd6b76d7413997de28ab060f5ff97da395186df Mon Sep 17 00:00:00 2001 From: Adam Bodurka Date: Thu, 27 Jun 2024 15:04:34 +0200 Subject: [PATCH 01/11] [QPG] Add TotalOperationalHours counter for switch and TRV --- .../light-switch-app/qpg/include/AppTask.h | 1 + examples/light-switch-app/qpg/src/AppTask.cpp | 44 +++++++++++++++++++ examples/lighting-app/qpg/src/AppTask.cpp | 15 +++++-- examples/lock-app/qpg/src/AppTask.cpp | 15 +++++-- examples/thermostat/qpg/include/AppTask.h | 1 + examples/thermostat/qpg/src/AppTask.cpp | 44 +++++++++++++++++++ 6 files changed, 114 insertions(+), 6 deletions(-) diff --git a/examples/light-switch-app/qpg/include/AppTask.h b/examples/light-switch-app/qpg/include/AppTask.h index 9284e068ab8509..a895ca8130bd24 100644 --- a/examples/light-switch-app/qpg/include/AppTask.h +++ b/examples/light-switch-app/qpg/include/AppTask.h @@ -58,6 +58,7 @@ class AppTask static void FunctionHandler(AppEvent * aEvent); static void TimerEventHandler(chip::System::Layer * aLayer, void * aAppState); + static void TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppState); static void MatterEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); static void UpdateLEDs(void); diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index 4be2f4eeefbf39..1cfe1dd9911558 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -61,6 +61,8 @@ using namespace ::chip::DeviceLayer; #define APP_TASK_STACK_SIZE (2 * 1024) #define APP_TASK_PRIORITY 2 #define APP_EVENT_QUEUE_SIZE 10 +#define SECONDS_IN_HOUR (3600) // we better keep this 3600 +#define TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS (1 * SECONDS_IN_HOUR) // increment every hour namespace { TaskHandle_t sAppTaskHandle; @@ -255,6 +257,14 @@ CHIP_ERROR AppTask::Init() sIsBLEAdvertisingEnabled = ConnectivityMgr().IsBLEAdvertisingEnabled(); UpdateLEDs(); + err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS), + TotalHoursTimerHandler, this); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "StartTimer failed %s: ", chip::ErrorStr(err)); + } + return err; } @@ -348,6 +358,40 @@ void AppTask::TimerEventHandler(chip::System::Layer * aLayer, void * aAppState) sAppTask.PostEvent(&event); } +void AppTask::TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppState) +{ + ChipLogProgress(NotSpecified, "HourlyTimer"); + + CHIP_ERROR err; + uint32_t totalOperationalHours = 0; + + err = ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours); + + if (err == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); + } + else if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + totalOperationalHours = 0; // set this explicitly to 0 for safety + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the Node"); + } + + err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS), + TotalHoursTimerHandler, nullptr); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "StartTimer failed %s: ", chip::ErrorStr(err)); + } +} + void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) { if (aEvent->Type != AppEvent::kEventType_Timer) diff --git a/examples/lighting-app/qpg/src/AppTask.cpp b/examples/lighting-app/qpg/src/AppTask.cpp index d870ea24deeb13..90f2e30ecb03c5 100644 --- a/examples/lighting-app/qpg/src/AppTask.cpp +++ b/examples/lighting-app/qpg/src/AppTask.cpp @@ -69,7 +69,8 @@ using namespace ::chip::DeviceLayer; #define APP_TASK_PRIORITY 2 #define APP_EVENT_QUEUE_SIZE 10 #define QPG_LIGHT_ENDPOINT_ID (1) -#define TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS (1 * 3600) // this value must be multiplication of 3600 +#define SECONDS_IN_HOUR (3600) // we better keep this 3600 +#define TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS (1 * SECONDS_IN_HOUR) // increment every hour static uint8_t countdown = 0; @@ -454,10 +455,18 @@ void AppTask::TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppSt CHIP_ERROR err; uint32_t totalOperationalHours = 0; - if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + err = ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours); + + if (err == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); + } + else if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) { + totalOperationalHours = 0; // set this explicitly to 0 for safety ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + - (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / 3600)); + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); } else { diff --git a/examples/lock-app/qpg/src/AppTask.cpp b/examples/lock-app/qpg/src/AppTask.cpp index d2f3298db9b779..8ae517dce2b7ad 100644 --- a/examples/lock-app/qpg/src/AppTask.cpp +++ b/examples/lock-app/qpg/src/AppTask.cpp @@ -64,7 +64,8 @@ using namespace ::chip::DeviceLayer; #define APP_TASK_PRIORITY 2 #define APP_EVENT_QUEUE_SIZE 10 #define QPG_LOCK_ENDPOINT_ID (1) -#define TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS (1 * 3600) // this value must be multiplication of 3600 +#define SECONDS_IN_HOUR (3600) // we better keep this 3600 +#define TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS (1 * SECONDS_IN_HOUR) // increment every hour #define NMBR_OF_RESETS_BLE_ADVERTISING (3) @@ -414,10 +415,18 @@ void AppTask::TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppSt CHIP_ERROR err; uint32_t totalOperationalHours = 0; - if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + err = ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours); + + if (err == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); + } + else if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) { + totalOperationalHours = 0; // set this explicitly to 0 for safety ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + - (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / 3600)); + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); } else { diff --git a/examples/thermostat/qpg/include/AppTask.h b/examples/thermostat/qpg/include/AppTask.h index 557f83d08636c9..2d2caac653aabc 100644 --- a/examples/thermostat/qpg/include/AppTask.h +++ b/examples/thermostat/qpg/include/AppTask.h @@ -61,6 +61,7 @@ class AppTask static void FunctionTimerEventHandler(AppEvent * aEvent); static void FunctionHandler(AppEvent * aEvent); static void TimerEventHandler(chip::System::Layer * aLayer, void * aAppState); + static void TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppState); static void MatterEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); static void UpdateLEDs(void); diff --git a/examples/thermostat/qpg/src/AppTask.cpp b/examples/thermostat/qpg/src/AppTask.cpp index 5bd1e9cc29ad9a..306661766a4af4 100644 --- a/examples/thermostat/qpg/src/AppTask.cpp +++ b/examples/thermostat/qpg/src/AppTask.cpp @@ -54,6 +54,8 @@ using namespace ::chip::DeviceLayer; #define APP_TASK_STACK_SIZE (2 * 1024) #define APP_TASK_PRIORITY 2 #define APP_EVENT_QUEUE_SIZE 10 +#define SECONDS_IN_HOUR (3600) // we better keep this 3600 +#define TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS (1 * SECONDS_IN_HOUR) // increment every hour namespace { TaskHandle_t sAppTaskHandle; @@ -233,6 +235,14 @@ CHIP_ERROR AppTask::Init() sIsBLEAdvertisingEnabled = ConnectivityMgr().IsBLEAdvertisingEnabled(); UpdateLEDs(); + err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS), + TotalHoursTimerHandler, this); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "StartTimer failed %s: ", chip::ErrorStr(err)); + } + return err; } @@ -312,6 +322,40 @@ void AppTask::TimerEventHandler(chip::System::Layer * aLayer, void * aAppState) sAppTask.PostEvent(&event); } +void AppTask::TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppState) +{ + ChipLogProgress(NotSpecified, "HourlyTimer"); + + CHIP_ERROR err; + uint32_t totalOperationalHours = 0; + + err = ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours); + + if (err == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); + } + else if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + totalOperationalHours = 0; // set this explicitly to 0 for safety + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + + (TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS / SECONDS_IN_HOUR)); + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the Node"); + } + + err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(TOTAL_OPERATIONAL_HOURS_SAVE_INTERVAL_SECONDS), + TotalHoursTimerHandler, nullptr); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "StartTimer failed %s: ", chip::ErrorStr(err)); + } +} + void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) { if (aEvent->Type != AppEvent::kEventType_Timer) From a31adb4c50d6b9dd83547335f0db28ce2bd7c206 Mon Sep 17 00:00:00 2001 From: Dieter Van der Meulen Date: Thu, 18 Jul 2024 08:39:51 +0200 Subject: [PATCH 02/11] [QPG] fix for switch to use correct previousPosition in ShortRelease event --- examples/light-switch-app/qpg/src/SwitchManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/light-switch-app/qpg/src/SwitchManager.cpp b/examples/light-switch-app/qpg/src/SwitchManager.cpp index 58b2f1d9bd8889..cb065cd9b3e732 100644 --- a/examples/light-switch-app/qpg/src/SwitchManager.cpp +++ b/examples/light-switch-app/qpg/src/SwitchManager.cpp @@ -129,7 +129,8 @@ void SwitchManager::GenericSwitchInitialPressHandler(AppEvent * aEvent) void SwitchManager::GenericSwitchReleasePressHandler(AppEvent * aEvent) { // Release moves Position from 1 (press) to 0 - uint8_t newPosition = 0; + uint8_t newPosition = 0; + uint8_t previousPosition = 1; if (aEvent->Type != AppEvent::kEventType_Button) { @@ -138,9 +139,9 @@ void SwitchManager::GenericSwitchReleasePressHandler(AppEvent * aEvent) } ChipLogProgress(NotSpecified, "GenericSwitchReleasePress new position %d", newPosition); - SystemLayer().ScheduleLambda([newPosition] { + SystemLayer().ScheduleLambda([newPosition, previousPosition] { chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(GENERICSWITCH_ENDPOINT_ID, newPosition); // Short Release event takes newPosition as event data - chip::app::Clusters::SwitchServer::Instance().OnShortRelease(GENERICSWITCH_ENDPOINT_ID, newPosition); + chip::app::Clusters::SwitchServer::Instance().OnShortRelease(GENERICSWITCH_ENDPOINT_ID, previousPosition); }); } From 6551d5ea6c44964252f968837956e6b500bfc875 Mon Sep 17 00:00:00 2001 From: Adam Bodurka Date: Thu, 18 Jul 2024 08:39:51 +0200 Subject: [PATCH 03/11] [QPG] Use identify cluster on endpoint 2 for switch --- examples/light-switch-app/qpg/src/AppTask.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index 1cfe1dd9911558..44b24e43133c99 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -143,11 +143,19 @@ void OnTriggerIdentifyEffect(Identify * identify) } } -Identify gIdentify = { +Identify gIdentifyEp1 = { chip::EndpointId{ 1 }, [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStart"); }, [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStop"); }, - Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator, + Clusters::Identify::IdentifyTypeEnum::kNone, + OnTriggerIdentifyEffect, +}; + +Identify gIdentifyEp2 = { + chip::EndpointId{ 2 }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStart"); }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStop"); }, + Clusters::Identify::IdentifyTypeEnum::kNone, OnTriggerIdentifyEffect, }; From 3dedc046e94f06597be31a64b457fc77a1e1be48 Mon Sep 17 00:00:00 2001 From: lucicop Date: Fri, 19 Jul 2024 15:27:46 +0200 Subject: [PATCH 04/11] feat(multicast): Add multicast binding for Matter Combo Switch Refs: APPSCS-4571 --- examples/light-switch-app/qpg/src/AppTask.cpp | 9 ++++ .../qpg/src/binding-handler.cpp | 44 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index 44b24e43133c99..0319fc252d4590 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -42,6 +42,8 @@ using namespace ::chip; #include #include +#include "qPinCfg.h" + #include #include @@ -233,6 +235,13 @@ void AppTask::OpenCommissioning(intptr_t arg) CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; + qResult_t res = Q_OK; + + res = qPinCfg_Init(NULL); + if (res != Q_OK) + { + ChipLogError(NotSpecified, "qPinCfg_Init failed: %d", res); + } PlatformMgr().AddEventHandler(MatterEventHandler, 0); diff --git a/examples/light-switch-app/qpg/src/binding-handler.cpp b/examples/light-switch-app/qpg/src/binding-handler.cpp index 4dae4e12b44155..eaf4c6cebfe9ae 100644 --- a/examples/light-switch-app/qpg/src/binding-handler.cpp +++ b/examples/light-switch-app/qpg/src/binding-handler.cpp @@ -67,13 +67,53 @@ static void ProcessSwitchUnicastBindingCommand(CommandId commandId, const EmberB } } +static void ProcessSwitchGroupBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding, BindingCommandData * data) +{ + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + + switch (commandId) + { + case Clusters::OnOff::Commands::Toggle::Id: { + Clusters::OnOff::Commands::Toggle::Type toggleCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, toggleCommand); + break; + } + case Clusters::LevelControl::Commands::MoveToLevel::Id: { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + moveToLevelCommand.level = data->level; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToLevelCommand); + break; + } + case Clusters::ColorControl::Commands::MoveToColor::Id: { + Clusters::ColorControl::Commands::MoveToColor::Type moveToColorCommand; + moveToColorCommand.colorX = data->colorXY.x; + moveToColorCommand.colorY = data->colorXY.y; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToColorCommand); + break; + } + default: + ChipLogError(NotSpecified, "Unsupported Command Id"); + break; + } +} + static void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context) { VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "nullptr pointer passed")); - BindingCommandData * data = static_cast(context); - if (binding.type == MATTER_UNICAST_BINDING) + if (binding.type == MATTER_MULTICAST_BINDING && data->isGroup) + { + switch (data->clusterId) + { + case Clusters::OnOff::Id: + case Clusters::LevelControl::Id: + case Clusters::ColorControl::Id: + ProcessSwitchGroupBindingCommand(data->commandId, binding, data); + break; + } + } + else if (binding.type == MATTER_UNICAST_BINDING && !data->isGroup) { switch (data->clusterId) { From c94e5f0717a27b7d2ae0be25d4ba5dc0d5262e9c Mon Sep 17 00:00:00 2001 From: Adam Bodurka Date: Sun, 21 Jul 2024 17:09:17 +0200 Subject: [PATCH 05/11] [QPG] MultiPress and LongPress implementation for switch --- .../light-switch-app/qpg/include/AppTask.h | 2 + .../qpg/include/SwitchManager.h | 6 +- examples/light-switch-app/qpg/src/AppTask.cpp | 92 +++++++++++++++++-- .../qpg/src/SwitchManager.cpp | 75 ++++++++++++++- .../light-switch-app/qpg/zap/switch.matter | 7 +- examples/light-switch-app/qpg/zap/switch.zap | 46 +++++++++- 6 files changed, 215 insertions(+), 13 deletions(-) diff --git a/examples/light-switch-app/qpg/include/AppTask.h b/examples/light-switch-app/qpg/include/AppTask.h index a895ca8130bd24..caf56977225280 100644 --- a/examples/light-switch-app/qpg/include/AppTask.h +++ b/examples/light-switch-app/qpg/include/AppTask.h @@ -59,6 +59,8 @@ class AppTask static void TimerEventHandler(chip::System::Layer * aLayer, void * aAppState); static void TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppState); + static void MultiPressTimeoutHandler(chip::System::Layer * aLayer, void * aAppState); + static void LongPressTimeoutHandler(chip::System::Layer * aLayer, void * aAppState); static void MatterEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); static void UpdateLEDs(void); diff --git a/examples/light-switch-app/qpg/include/SwitchManager.h b/examples/light-switch-app/qpg/include/SwitchManager.h index 41eedd10af4f13..df09260285c96d 100644 --- a/examples/light-switch-app/qpg/include/SwitchManager.h +++ b/examples/light-switch-app/qpg/include/SwitchManager.h @@ -55,7 +55,11 @@ class SwitchManager void Init(void); static void GenericSwitchInitialPressHandler(AppEvent * aEvent); - static void GenericSwitchReleasePressHandler(AppEvent * aEvent); + static void GenericSwitchShortReleaseHandler(AppEvent * aEvent); + static void GenericSwitchLongReleaseHandler(AppEvent * aEvent); + static void GenericSwitchLongPressHandler(AppEvent * aEvent); + static void GenericSwitchMultipressCompleteHandler(AppEvent * aEvent); + static void GenericSwitchMultipressOngoingHandler(AppEvent * aEvent); static void ToggleHandler(AppEvent * aEvent); static void LevelHandler(AppEvent * aEvent); static void ColorHandler(AppEvent * aEvent); diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index 0319fc252d4590..fa617c29747938 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -60,6 +60,11 @@ using namespace ::chip::DeviceLayer; #define FACTORY_RESET_TRIGGER_TIMEOUT 3000 #define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 +#define SWITCH_MULTIPRESS_WINDOW_MS 500 +#define SWITCH_LONGPRESS_WINDOW_MS 3000 +#define SWITCH_BUTTON_PRESSED 1 +#define SWITCH_BUTTON_UNPRESSED 0 + #define APP_TASK_STACK_SIZE (2 * 1024) #define APP_TASK_PRIORITY 2 #define APP_EVENT_QUEUE_SIZE 10 @@ -74,6 +79,9 @@ bool sIsThreadProvisioned = false; bool sIsThreadEnabled = false; bool sHaveBLEConnections = false; bool sIsBLEAdvertisingEnabled = false; +bool sIsMultipressOngoing = false; +bool sLongPressDetected = false; +uint8_t sSwitchButtonState = SWITCH_BUTTON_UNPRESSED; // NOTE! This key is for test/certification only and should not be available in production devices! uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, @@ -302,7 +310,9 @@ void AppTask::AppTaskMain(void * pvParameter) void AppTask::ButtonEventHandler(uint8_t btnIdx, bool btnPressed) { - ChipLogProgress(NotSpecified, "ButtonEventHandler %d, %d", btnIdx, btnPressed); + CHIP_ERROR err = CHIP_NO_ERROR; + + ChipLogDetail(NotSpecified, "ButtonEventHandler %d, %d", btnIdx, btnPressed); AppEvent button_event = {}; button_event.Type = AppEvent::kEventType_Button; @@ -324,13 +334,54 @@ void AppTask::ButtonEventHandler(uint8_t btnIdx, bool btnPressed) case APP_FUNCTION2_SWITCH: { if (!btnPressed) { - ChipLogProgress(NotSpecified, "Switch release press"); - button_event.Handler = SwitchMgr().GenericSwitchReleasePressHandler; + ChipLogDetail(NotSpecified, "Switch button released"); + + button_event.Handler = + sLongPressDetected ? SwitchMgr().GenericSwitchLongReleaseHandler : SwitchMgr().GenericSwitchShortReleaseHandler; + + sIsMultipressOngoing = true; + sSwitchButtonState = SWITCH_BUTTON_UNPRESSED; + sLongPressDetected = false; + + chip::DeviceLayer::SystemLayer().CancelTimer(MultiPressTimeoutHandler, NULL); + // we start the MultiPress feature window after releasing the button + err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(SWITCH_MULTIPRESS_WINDOW_MS), + MultiPressTimeoutHandler, NULL); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "StartTimer failed %s: ", chip::ErrorStr(err)); + } } else { - ChipLogProgress(NotSpecified, "Switch initial press"); - button_event.Handler = SwitchMgr().GenericSwitchInitialPressHandler; + ChipLogDetail(NotSpecified, "Switch button pressed"); + + sSwitchButtonState = SWITCH_BUTTON_PRESSED; + + chip::DeviceLayer::SystemLayer().CancelTimer(LongPressTimeoutHandler, NULL); + // we need to check if this is short or long press + err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(SWITCH_LONGPRESS_WINDOW_MS), + LongPressTimeoutHandler, NULL); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "StartTimer failed %s: ", chip::ErrorStr(err)); + } + + // if we have active multipress window we need to send extra event + if (sIsMultipressOngoing) + { + ChipLogDetail(NotSpecified, "Switch MultipressOngoing"); + button_event.Handler = SwitchMgr().GenericSwitchInitialPressHandler; + sAppTask.PostEvent(&button_event); + chip::DeviceLayer::SystemLayer().CancelTimer(MultiPressTimeoutHandler, NULL); + button_event.Handler = SwitchMgr().GenericSwitchMultipressOngoingHandler; + } + else + { + button_event.Handler = SwitchMgr().GenericSwitchInitialPressHandler; + } } break; } @@ -375,9 +426,38 @@ void AppTask::TimerEventHandler(chip::System::Layer * aLayer, void * aAppState) sAppTask.PostEvent(&event); } +void AppTask::MultiPressTimeoutHandler(chip::System::Layer * aLayer, void * aAppState) +{ + ChipLogDetail(NotSpecified, "MultiPressTimeoutHandler"); + + sIsMultipressOngoing = false; + + AppEvent multipress_event = {}; + multipress_event.Type = AppEvent::kEventType_Button; + multipress_event.Handler = SwitchMgr().GenericSwitchMultipressCompleteHandler; + + sAppTask.PostEvent(&multipress_event); +} + +void AppTask::LongPressTimeoutHandler(chip::System::Layer * aLayer, void * aAppState) +{ + ChipLogDetail(NotSpecified, "LongPressTimeoutHandler"); + + // if the button is still pressed after threshold time, this is a LongPress, otherwise jsut ignore it + if (sSwitchButtonState == SWITCH_BUTTON_PRESSED) + { + sLongPressDetected = true; + AppEvent longpress_event = {}; + longpress_event.Type = AppEvent::kEventType_Button; + longpress_event.Handler = SwitchMgr().GenericSwitchLongPressHandler; + + sAppTask.PostEvent(&longpress_event); + } +} + void AppTask::TotalHoursTimerHandler(chip::System::Layer * aLayer, void * aAppState) { - ChipLogProgress(NotSpecified, "HourlyTimer"); + ChipLogDetail(NotSpecified, "HourlyTimer"); CHIP_ERROR err; uint32_t totalOperationalHours = 0; diff --git a/examples/light-switch-app/qpg/src/SwitchManager.cpp b/examples/light-switch-app/qpg/src/SwitchManager.cpp index cb065cd9b3e732..2bde0a5575979e 100644 --- a/examples/light-switch-app/qpg/src/SwitchManager.cpp +++ b/examples/light-switch-app/qpg/src/SwitchManager.cpp @@ -26,10 +26,12 @@ SwitchManager SwitchManager::sSwitch; using namespace ::chip; using namespace chip::DeviceLayer; +static uint8_t multiPressCount = 1; void SwitchManager::Init(void) { - // init - TODO + uint8_t multiPressMax = 2; + chip::app::Clusters::Switch::Attributes::MultiPressMax::Set(GENERICSWITCH_ENDPOINT_ID, multiPressMax); } void SwitchManager::ToggleHandler(AppEvent * aEvent) @@ -118,7 +120,7 @@ void SwitchManager::GenericSwitchInitialPressHandler(AppEvent * aEvent) return; } - ChipLogProgress(NotSpecified, "GenericSwitchInitialPress new position %d", newPosition); + ChipLogDetail(NotSpecified, "GenericSwitchInitialPress new position %d", newPosition); SystemLayer().ScheduleLambda([newPosition] { chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(GENERICSWITCH_ENDPOINT_ID, newPosition); // InitialPress event takes newPosition as event data @@ -126,7 +128,25 @@ void SwitchManager::GenericSwitchInitialPressHandler(AppEvent * aEvent) }); } -void SwitchManager::GenericSwitchReleasePressHandler(AppEvent * aEvent) +void SwitchManager::GenericSwitchLongPressHandler(AppEvent * aEvent) +{ + // Press moves Position from 0 (idle) to 1 (press) + uint8_t newPosition = 1; + + if (aEvent->Type != AppEvent::kEventType_Button) + { + ChipLogError(NotSpecified, "Event type not supported!"); + return; + } + + ChipLogDetail(NotSpecified, "GenericSwitchLongPress new position %d", newPosition); + SystemLayer().ScheduleLambda([newPosition] { + // LongPress event takes newPosition as event data + chip::app::Clusters::SwitchServer::Instance().OnLongPress(GENERICSWITCH_ENDPOINT_ID, newPosition); + }); +} + +void SwitchManager::GenericSwitchShortReleaseHandler(AppEvent * aEvent) { // Release moves Position from 1 (press) to 0 uint8_t newPosition = 0; @@ -138,10 +158,57 @@ void SwitchManager::GenericSwitchReleasePressHandler(AppEvent * aEvent) return; } - ChipLogProgress(NotSpecified, "GenericSwitchReleasePress new position %d", newPosition); + ChipLogDetail(NotSpecified, "GenericSwitchShortRelease new position %d", newPosition); SystemLayer().ScheduleLambda([newPosition, previousPosition] { chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(GENERICSWITCH_ENDPOINT_ID, newPosition); // Short Release event takes newPosition as event data chip::app::Clusters::SwitchServer::Instance().OnShortRelease(GENERICSWITCH_ENDPOINT_ID, previousPosition); }); } + +void SwitchManager::GenericSwitchLongReleaseHandler(AppEvent * aEvent) +{ + // Release moves Position from 1 (press) to 0 + uint8_t newPosition = 0; + uint8_t previousPosition = 1; + + if (aEvent->Type != AppEvent::kEventType_Button) + { + ChipLogError(NotSpecified, "Event type not supported!"); + return; + } + + ChipLogDetail(NotSpecified, "GenericSwitchLongRelease new position %d", newPosition); + SystemLayer().ScheduleLambda([newPosition, previousPosition] { + chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(GENERICSWITCH_ENDPOINT_ID, newPosition); + // LongRelease event takes newPosition as event data + chip::app::Clusters::SwitchServer::Instance().OnLongRelease(GENERICSWITCH_ENDPOINT_ID, previousPosition); + }); +} + +void SwitchManager::GenericSwitchMultipressOngoingHandler(AppEvent * aEvent) +{ + uint8_t newPosition = 1; + + multiPressCount++; + + ChipLogDetail(NotSpecified, "GenericSwitchMultiPressOngoing (%d)", multiPressCount); + + SystemLayer().ScheduleLambda([newPosition] { + chip::app::Clusters::SwitchServer::Instance().OnMultiPressOngoing(GENERICSWITCH_ENDPOINT_ID, newPosition, multiPressCount); + }); +} + +void SwitchManager::GenericSwitchMultipressCompleteHandler(AppEvent * aEvent) +{ + uint8_t previousPosition = 0; + + ChipLogProgress(NotSpecified, "GenericSwitchMultiPressComplete (%d)", multiPressCount); + + SystemLayer().ScheduleLambda([previousPosition] { + chip::app::Clusters::SwitchServer::Instance().OnMultiPressComplete(GENERICSWITCH_ENDPOINT_ID, previousPosition, + multiPressCount); + }); + + multiPressCount = 1; +} diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index fa848c35b526ac..bc458ebcbe1356 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -2751,14 +2751,19 @@ endpoint 2 { server cluster Switch { emits event InitialPress; + emits event LongPress; emits event ShortRelease; + emits event LongRelease; + emits event MultiPressOngoing; + emits event MultiPressComplete; ram attribute numberOfPositions default = 2; ram attribute currentPosition default = 0; + ram attribute multiPressMax default = 2; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 6; + ram attribute featureMap default = 30; ram attribute clusterRevision default = 1; } } diff --git a/examples/light-switch-app/qpg/zap/switch.zap b/examples/light-switch-app/qpg/zap/switch.zap index 7f00138fc26fbe..f0cb5a93c20fdd 100644 --- a/examples/light-switch-app/qpg/zap/switch.zap +++ b/examples/light-switch-app/qpg/zap/switch.zap @@ -6020,6 +6020,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "MultiPressMax", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "GeneratedCommandList", "code": 65528, @@ -6094,7 +6110,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "6", + "defaultValue": "30", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -6125,12 +6141,40 @@ "side": "server", "included": 1 }, + { + "name": "LongPress", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + }, { "name": "ShortRelease", "code": 3, "mfgCode": null, "side": "server", "included": 1 + }, + { + "name": "LongRelease", + "code": 4, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "MultiPressOngoing", + "code": 5, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "MultiPressComplete", + "code": 6, + "mfgCode": null, + "side": "server", + "included": 1 } ] } From d81f95630277fe9147a1b5fa8fc30fa66d2e560c Mon Sep 17 00:00:00 2001 From: Adam Bodurka Date: Tue, 23 Jul 2024 13:41:16 +0200 Subject: [PATCH 06/11] [INTERNAL] Fix qPinCfg.h error --- examples/light-switch-app/qpg/src/AppTask.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index fa617c29747938..65c372311b3585 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -42,7 +42,9 @@ using namespace ::chip; #include #include +#if defined(QORVO_QPINCFG_ENABLE) #include "qPinCfg.h" +#endif // QORVO_QPINCFG_ENABLE #include @@ -243,14 +245,15 @@ void AppTask::OpenCommissioning(intptr_t arg) CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; + +#if defined(QORVO_QPINCFG_ENABLE) qResult_t res = Q_OK; - res = qPinCfg_Init(NULL); if (res != Q_OK) { ChipLogError(NotSpecified, "qPinCfg_Init failed: %d", res); } - +#endif // QORVO_QPINCFG_ENABLE PlatformMgr().AddEventHandler(MatterEventHandler, 0); ChipLogProgress(NotSpecified, "Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); From 85d5afc4fb20560497c8cbb55bf9bd6660df5fa0 Mon Sep 17 00:00:00 2001 From: lucicop Date: Mon, 22 Jul 2024 09:53:20 +0200 Subject: [PATCH 07/11] Set groups cluster to server in switch.zap and improve command handling for unicast and multicast --- .../qpg/src/SwitchManager.cpp | 1 + .../qpg/src/binding-handler.cpp | 131 +++++++++++++----- .../light-switch-app/qpg/zap/switch.matter | 22 ++- examples/light-switch-app/qpg/zap/switch.zap | 96 ++++++++++--- 4 files changed, 197 insertions(+), 53 deletions(-) diff --git a/examples/light-switch-app/qpg/src/SwitchManager.cpp b/examples/light-switch-app/qpg/src/SwitchManager.cpp index 2bde0a5575979e..170bb8b454c765 100644 --- a/examples/light-switch-app/qpg/src/SwitchManager.cpp +++ b/examples/light-switch-app/qpg/src/SwitchManager.cpp @@ -48,6 +48,7 @@ void SwitchManager::ToggleHandler(AppEvent * aEvent) data->localEndpointId = SWITCH_ENDPOINT_ID; data->clusterId = chip::app::Clusters::OnOff::Id; data->commandId = chip::app::Clusters::OnOff::Commands::Toggle::Id; + data->isGroup = true; DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); } diff --git a/examples/light-switch-app/qpg/src/binding-handler.cpp b/examples/light-switch-app/qpg/src/binding-handler.cpp index eaf4c6cebfe9ae..f2a7c266d62338 100644 --- a/examples/light-switch-app/qpg/src/binding-handler.cpp +++ b/examples/light-switch-app/qpg/src/binding-handler.cpp @@ -38,31 +38,59 @@ static void ProcessSwitchUnicastBindingCommand(CommandId commandId, const EmberB ChipLogError(NotSpecified, "Switch command failed: %" CHIP_ERROR_FORMAT, error.Format()); }; - switch (commandId) + switch (data->clusterId) { - case Clusters::OnOff::Commands::Toggle::Id: - Clusters::OnOff::Commands::Toggle::Type toggleCommand; - Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, toggleCommand, onSuccess, onFailure); - break; + case Clusters::OnOff::Id: + switch (commandId) + { + case Clusters::OnOff::Commands::Toggle::Id: + Clusters::OnOff::Commands::Toggle::Type toggleCommand; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, toggleCommand, onSuccess, onFailure); + break; + case Clusters::OnOff::Commands::On::Id: + Clusters::OnOff::Commands::On::Type onCommand; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, onCommand, onSuccess, onFailure); + break; - case Clusters::LevelControl::Commands::MoveToLevel::Id: { - Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; - moveToLevelCommand.level = data->level; - Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, moveToLevelCommand, onSuccess, onFailure); - } - break; - case Clusters::ColorControl::Commands::MoveToColor::Id: { + case Clusters::OnOff::Commands::Off::Id: + Clusters::OnOff::Commands::Off::Type offCommand; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, offCommand, onSuccess, onFailure); + break; + default: + ChipLogError(NotSpecified, "Unsupported Command Id"); + break; + } + break; - Clusters::ColorControl::Commands::MoveToColor::Type moveToColorCommand; + case Clusters::LevelControl::Id: + if (commandId == Clusters::LevelControl::Commands::MoveToLevel::Id) + { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + moveToLevelCommand.level = data->level; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, moveToLevelCommand, onSuccess, onFailure); + } + else + { + ChipLogError(NotSpecified, "Unsupported Command Id"); + } + break; - moveToColorCommand.colorX = data->colorXY.x; - moveToColorCommand.colorY = data->colorXY.y; - Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, moveToColorCommand, onSuccess, onFailure); - } - break; + case Clusters::ColorControl::Id: + if (commandId == Clusters::ColorControl::Commands::MoveToColor::Id) + { + Clusters::ColorControl::Commands::MoveToColor::Type moveToColorCommand; + moveToColorCommand.colorX = data->colorXY.x; + moveToColorCommand.colorY = data->colorXY.y; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, moveToColorCommand, onSuccess, onFailure); + } + else + { + ChipLogError(NotSpecified, "Unsupported Command Id"); + } + break; default: - ChipLogError(NotSpecified, "Unsupported Command Id"); + ChipLogError(NotSpecified, "Unsupported Cluster Id"); break; } } @@ -71,28 +99,59 @@ static void ProcessSwitchGroupBindingCommand(CommandId commandId, const EmberBin { Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); - switch (commandId) + switch (data->clusterId) { - case Clusters::OnOff::Commands::Toggle::Id: { - Clusters::OnOff::Commands::Toggle::Type toggleCommand; - Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, toggleCommand); + case Clusters::OnOff::Id: + switch (commandId) + { + case Clusters::OnOff::Commands::Toggle::Id: + Clusters::OnOff::Commands::Toggle::Type toggleCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, toggleCommand); + break; + case Clusters::OnOff::Commands::On::Id: + Clusters::OnOff::Commands::On::Type onCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, onCommand); + + break; + case Clusters::OnOff::Commands::Off::Id: + Clusters::OnOff::Commands::Off::Type offCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, offCommand); + break; + default: + ChipLogError(NotSpecified, "Unsupported Command Id"); + break; + } break; - } - case Clusters::LevelControl::Commands::MoveToLevel::Id: { - Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; - moveToLevelCommand.level = data->level; - Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToLevelCommand); + + case Clusters::LevelControl::Id: + if (commandId == Clusters::LevelControl::Commands::MoveToLevel::Id) + { + Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; + moveToLevelCommand.level = data->level; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToLevelCommand); + } + else + { + ChipLogError(NotSpecified, "Unsupported Command Id"); + } break; - } - case Clusters::ColorControl::Commands::MoveToColor::Id: { - Clusters::ColorControl::Commands::MoveToColor::Type moveToColorCommand; - moveToColorCommand.colorX = data->colorXY.x; - moveToColorCommand.colorY = data->colorXY.y; - Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToColorCommand); + + case Clusters::ColorControl::Id: + if (commandId == Clusters::ColorControl::Commands::MoveToColor::Id) + { + Clusters::ColorControl::Commands::MoveToColor::Type moveToColorCommand; + moveToColorCommand.colorX = data->colorXY.x; + moveToColorCommand.colorY = data->colorXY.y; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, moveToColorCommand); + } + else + { + ChipLogError(NotSpecified, "Unsupported Command Id"); + } break; - } + default: - ChipLogError(NotSpecified, "Unsupported Command Id"); + ChipLogError(NotSpecified, "Unsupported Cluster Id"); break; } } diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index bc458ebcbe1356..8f848921e2614c 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -2675,7 +2675,6 @@ endpoint 1 { device type ma_colordimmerswitch = 261, version 1; binding cluster Identify; - binding cluster Groups; binding cluster OnOff; binding cluster LevelControl; binding cluster ScenesManagement; @@ -2695,6 +2694,27 @@ endpoint 1 { handle command TriggerEffect; } + server cluster Groups { + ram attribute nameSupport; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command AddGroup; + handle command AddGroupResponse; + handle command ViewGroup; + handle command ViewGroupResponse; + handle command GetGroupMembership; + handle command GetGroupMembershipResponse; + handle command RemoveGroup; + handle command RemoveGroupResponse; + handle command RemoveAllGroups; + handle command AddGroupIfIdentifying; + } + server cluster Descriptor { callback attribute deviceTypeList; callback attribute serverList; diff --git a/examples/light-switch-app/qpg/zap/switch.zap b/examples/light-switch-app/qpg/zap/switch.zap index f0cb5a93c20fdd..441c062334a2e7 100644 --- a/examples/light-switch-app/qpg/zap/switch.zap +++ b/examples/light-switch-app/qpg/zap/switch.zap @@ -4909,7 +4909,7 @@ "code": 4, "mfgCode": null, "define": "GROUPS_CLUSTER", - "side": "client", + "side": "server", "enabled": 1, "commands": [ { @@ -4917,7 +4917,7 @@ "code": 0, "mfgCode": null, "source": "client", - "isIncoming": 0, + "isIncoming": 1, "isEnabled": 1 }, { @@ -4925,7 +4925,7 @@ "code": 0, "mfgCode": null, "source": "server", - "isIncoming": 1, + "isIncoming": 0, "isEnabled": 1 }, { @@ -4933,7 +4933,7 @@ "code": 1, "mfgCode": null, "source": "client", - "isIncoming": 0, + "isIncoming": 1, "isEnabled": 1 }, { @@ -4941,7 +4941,7 @@ "code": 1, "mfgCode": null, "source": "server", - "isIncoming": 1, + "isIncoming": 0, "isEnabled": 1 }, { @@ -4949,7 +4949,7 @@ "code": 2, "mfgCode": null, "source": "client", - "isIncoming": 0, + "isIncoming": 1, "isEnabled": 1 }, { @@ -4957,7 +4957,7 @@ "code": 2, "mfgCode": null, "source": "server", - "isIncoming": 1, + "isIncoming": 0, "isEnabled": 1 }, { @@ -4965,7 +4965,7 @@ "code": 3, "mfgCode": null, "source": "client", - "isIncoming": 0, + "isIncoming": 1, "isEnabled": 1 }, { @@ -4973,7 +4973,7 @@ "code": 3, "mfgCode": null, "source": "server", - "isIncoming": 1, + "isIncoming": 0, "isEnabled": 1 }, { @@ -4981,7 +4981,7 @@ "code": 4, "mfgCode": null, "source": "client", - "isIncoming": 0, + "isIncoming": 1, "isEnabled": 1 }, { @@ -4989,16 +4989,80 @@ "code": 5, "mfgCode": null, "source": "client", - "isIncoming": 0, + "isIncoming": 1, "isEnabled": 1 } ], "attributes": [ + { + "name": "NameSupport", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "NameSupportBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "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": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "FeatureMap", "code": 65532, "mfgCode": null, - "side": "client", + "side": "server", "type": "bitmap32", "included": 1, "storageOption": "RAM", @@ -5014,7 +5078,7 @@ "name": "ClusterRevision", "code": 65533, "mfgCode": null, - "side": "client", + "side": "server", "type": "int16u", "included": 1, "storageOption": "RAM", @@ -5022,9 +5086,9 @@ "bounded": 0, "defaultValue": "4", "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": null + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 } ] }, From b7d2058e4f2670930224e08228fa8969e2b235a2 Mon Sep 17 00:00:00 2001 From: Adam Bodurka Date: Mon, 22 Jul 2024 14:24:38 +0200 Subject: [PATCH 08/11] [QPG] PowerSource cluster added --- .../light-switch-app/qpg/zap/switch.matter | 280 ++++++++++++++++ examples/light-switch-app/qpg/zap/switch.zap | 298 ++++++++++++++++++ 2 files changed, 578 insertions(+) diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index 8f848921e2614c..ade627a5818570 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -755,6 +755,265 @@ cluster OtaSoftwareUpdateRequestor = 42 { command AnnounceOTAProvider(AnnounceOTAProviderRequest): DefaultSuccess = 0; } +/** This cluster is used to describe the configuration and capabilities of a physical power source that provides power to the Node. */ +cluster PowerSource = 47 { + revision 1; // NOTE: Default/not specifically set + + enum BatApprovedChemistryEnum : enum16 { + kUnspecified = 0; + kAlkaline = 1; + kLithiumCarbonFluoride = 2; + kLithiumChromiumOxide = 3; + kLithiumCopperOxide = 4; + kLithiumIronDisulfide = 5; + kLithiumManganeseDioxide = 6; + kLithiumThionylChloride = 7; + kMagnesium = 8; + kMercuryOxide = 9; + kNickelOxyhydride = 10; + kSilverOxide = 11; + kZincAir = 12; + kZincCarbon = 13; + kZincChloride = 14; + kZincManganeseDioxide = 15; + kLeadAcid = 16; + kLithiumCobaltOxide = 17; + kLithiumIon = 18; + kLithiumIonPolymer = 19; + kLithiumIronPhosphate = 20; + kLithiumSulfur = 21; + kLithiumTitanate = 22; + kNickelCadmium = 23; + kNickelHydrogen = 24; + kNickelIron = 25; + kNickelMetalHydride = 26; + kNickelZinc = 27; + kSilverZinc = 28; + kSodiumIon = 29; + kSodiumSulfur = 30; + kZincBromide = 31; + kZincCerium = 32; + } + + enum BatChargeFaultEnum : enum8 { + kUnspecified = 0; + kAmbientTooHot = 1; + kAmbientTooCold = 2; + kBatteryTooHot = 3; + kBatteryTooCold = 4; + kBatteryAbsent = 5; + kBatteryOverVoltage = 6; + kBatteryUnderVoltage = 7; + kChargerOverVoltage = 8; + kChargerUnderVoltage = 9; + kSafetyTimeout = 10; + } + + enum BatChargeLevelEnum : enum8 { + kOK = 0; + kWarning = 1; + kCritical = 2; + } + + enum BatChargeStateEnum : enum8 { + kUnknown = 0; + kIsCharging = 1; + kIsAtFullCharge = 2; + kIsNotCharging = 3; + } + + enum BatCommonDesignationEnum : enum16 { + kUnspecified = 0; + kAAA = 1; + kAA = 2; + kC = 3; + kD = 4; + k4v5 = 5; + k6v0 = 6; + k9v0 = 7; + k12AA = 8; + kAAAA = 9; + kA = 10; + kB = 11; + kF = 12; + kN = 13; + kNo6 = 14; + kSubC = 15; + kA23 = 16; + kA27 = 17; + kBA5800 = 18; + kDuplex = 19; + k4SR44 = 20; + k523 = 21; + k531 = 22; + k15v0 = 23; + k22v5 = 24; + k30v0 = 25; + k45v0 = 26; + k67v5 = 27; + kJ = 28; + kCR123A = 29; + kCR2 = 30; + k2CR5 = 31; + kCRP2 = 32; + kCRV3 = 33; + kSR41 = 34; + kSR43 = 35; + kSR44 = 36; + kSR45 = 37; + kSR48 = 38; + kSR54 = 39; + kSR55 = 40; + kSR57 = 41; + kSR58 = 42; + kSR59 = 43; + kSR60 = 44; + kSR63 = 45; + kSR64 = 46; + kSR65 = 47; + kSR66 = 48; + kSR67 = 49; + kSR68 = 50; + kSR69 = 51; + kSR516 = 52; + kSR731 = 53; + kSR712 = 54; + kLR932 = 55; + kA5 = 56; + kA10 = 57; + kA13 = 58; + kA312 = 59; + kA675 = 60; + kAC41E = 61; + k10180 = 62; + k10280 = 63; + k10440 = 64; + k14250 = 65; + k14430 = 66; + k14500 = 67; + k14650 = 68; + k15270 = 69; + k16340 = 70; + kRCR123A = 71; + k17500 = 72; + k17670 = 73; + k18350 = 74; + k18500 = 75; + k18650 = 76; + k19670 = 77; + k25500 = 78; + k26650 = 79; + k32600 = 80; + } + + enum BatFaultEnum : enum8 { + kUnspecified = 0; + kOverTemp = 1; + kUnderTemp = 2; + } + + enum BatReplaceabilityEnum : enum8 { + kUnspecified = 0; + kNotReplaceable = 1; + kUserReplaceable = 2; + kFactoryReplaceable = 3; + } + + enum PowerSourceStatusEnum : enum8 { + kUnspecified = 0; + kActive = 1; + kStandby = 2; + kUnavailable = 3; + } + + enum WiredCurrentTypeEnum : enum8 { + kAC = 0; + kDC = 1; + } + + enum WiredFaultEnum : enum8 { + kUnspecified = 0; + kOverVoltage = 1; + kUnderVoltage = 2; + } + + bitmap Feature : bitmap32 { + kWired = 0x1; + kBattery = 0x2; + kRechargeable = 0x4; + kReplaceable = 0x8; + } + + struct BatChargeFaultChangeType { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + struct BatFaultChangeType { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + struct WiredFaultChangeType { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event WiredFaultChange = 0 { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event BatFaultChange = 1 { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + info event BatChargeFaultChange = 2 { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + readonly attribute PowerSourceStatusEnum status = 0; + readonly attribute int8u order = 1; + readonly attribute char_string<60> description = 2; + readonly attribute optional nullable int32u wiredAssessedInputVoltage = 3; + readonly attribute optional nullable int16u wiredAssessedInputFrequency = 4; + readonly attribute optional WiredCurrentTypeEnum wiredCurrentType = 5; + readonly attribute optional nullable int32u wiredAssessedCurrent = 6; + readonly attribute optional int32u wiredNominalVoltage = 7; + readonly attribute optional int32u wiredMaximumCurrent = 8; + readonly attribute optional boolean wiredPresent = 9; + readonly attribute optional WiredFaultEnum activeWiredFaults[] = 10; + readonly attribute optional nullable int32u batVoltage = 11; + readonly attribute optional nullable int8u batPercentRemaining = 12; + readonly attribute optional nullable int32u batTimeRemaining = 13; + readonly attribute optional BatChargeLevelEnum batChargeLevel = 14; + readonly attribute optional boolean batReplacementNeeded = 15; + readonly attribute optional BatReplaceabilityEnum batReplaceability = 16; + readonly attribute optional boolean batPresent = 17; + readonly attribute optional BatFaultEnum activeBatFaults[] = 18; + readonly attribute optional char_string<60> batReplacementDescription = 19; + readonly attribute optional BatCommonDesignationEnum batCommonDesignation = 20; + readonly attribute optional char_string<20> batANSIDesignation = 21; + readonly attribute optional char_string<20> batIECDesignation = 22; + readonly attribute optional BatApprovedChemistryEnum batApprovedChemistry = 23; + readonly attribute optional int32u batCapacity = 24; + readonly attribute optional int8u batQuantity = 25; + readonly attribute optional BatChargeStateEnum batChargeState = 26; + readonly attribute optional nullable int32u batTimeToFullCharge = 27; + readonly attribute optional boolean batFunctionalWhileCharging = 28; + readonly attribute optional nullable int32u batChargingCurrent = 29; + readonly attribute optional BatChargeFaultEnum activeBatChargeFaults[] = 30; + readonly attribute endpoint_no endpointList[] = 31; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + /** This cluster is used to manage global aspects of the Commissioning flow. */ cluster GeneralCommissioning = 48 { revision 1; // NOTE: Default/not specifically set @@ -2391,6 +2650,27 @@ endpoint 0 { handle command AnnounceOTAProvider; } + server cluster PowerSource { + ram attribute status; + ram attribute order; + ram attribute description; + ram attribute batVoltage; + ram attribute batPercentRemaining; + ram attribute batChargeLevel; + ram attribute batReplacementNeeded; + ram attribute batReplaceability; + ram attribute batReplacementDescription; + ram attribute batCommonDesignation; + ram attribute batQuantity; + callback attribute endpointList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 10; + ram attribute clusterRevision default = 1; + } + server cluster GeneralCommissioning { ram attribute breadcrumb default = 0x0000000000000000; callback attribute basicCommissioningInfo; diff --git a/examples/light-switch-app/qpg/zap/switch.zap b/examples/light-switch-app/qpg/zap/switch.zap index 441c062334a2e7..5578a0ff63b5e8 100644 --- a/examples/light-switch-app/qpg/zap/switch.zap +++ b/examples/light-switch-app/qpg/zap/switch.zap @@ -1185,6 +1185,304 @@ } ] }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Status", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerSourceStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Order", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Description", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatVoltage", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPercentRemaining", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatChargeLevel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "BatChargeLevelEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementNeeded", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplaceability", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "BatReplaceabilityEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementDescription", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatCommonDesignation", + "code": 20, + "mfgCode": null, + "side": "server", + "type": "BatCommonDesignationEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatQuantity", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EndpointList", + "code": 31, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "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": "EventList", + "code": 65530, + "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": "10", + "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": "General Commissioning", "code": 48, From 8e4c95df4dd4b45402a758d6abc67d91baf7bd5d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 25 Jul 2024 09:58:40 +0000 Subject: [PATCH 09/11] Restyled by whitespace --- examples/light-switch-app/qpg/src/AppTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index 65c372311b3585..b090a3f06ae3cc 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -245,7 +245,7 @@ void AppTask::OpenCommissioning(intptr_t arg) CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; - + #if defined(QORVO_QPINCFG_ENABLE) qResult_t res = Q_OK; res = qPinCfg_Init(NULL); From 98370e3ae78d5f7a25ba2529edd279bd4b4d027c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 25 Jul 2024 09:58:41 +0000 Subject: [PATCH 10/11] Restyled by clang-format --- examples/light-switch-app/qpg/src/AppTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/light-switch-app/qpg/src/AppTask.cpp b/examples/light-switch-app/qpg/src/AppTask.cpp index b090a3f06ae3cc..7cb0a41a452aca 100644 --- a/examples/light-switch-app/qpg/src/AppTask.cpp +++ b/examples/light-switch-app/qpg/src/AppTask.cpp @@ -247,8 +247,8 @@ CHIP_ERROR AppTask::Init() CHIP_ERROR err = CHIP_NO_ERROR; #if defined(QORVO_QPINCFG_ENABLE) - qResult_t res = Q_OK; - res = qPinCfg_Init(NULL); + qResult_t res = Q_OK; + res = qPinCfg_Init(NULL); if (res != Q_OK) { ChipLogError(NotSpecified, "qPinCfg_Init failed: %d", res); From 751dc2f44b414357143205d8352449a7b965b0ec Mon Sep 17 00:00:00 2001 From: Adam Bodurka Date: Thu, 25 Jul 2024 12:21:50 +0200 Subject: [PATCH 11/11] Fixed .matter file --- examples/light-switch-app/qpg/zap/switch.matter | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index ade627a5818570..73968414b217e9 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -2975,13 +2975,12 @@ endpoint 1 { } server cluster Groups { - ram attribute nameSupport; + ram attribute nameSupport; callback attribute generatedCommandList; callback attribute acceptedCommandList; - callback attribute eventList; callback attribute attributeList; - ram attribute featureMap default = 0; - ram attribute clusterRevision default = 4; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; handle command AddGroup; handle command AddGroupResponse;