diff --git a/examples/window-app/common/include/WindowApp.h b/examples/window-app/common/include/WindowApp.h index 000c997cde6d4a..e8184e21103b40 100644 --- a/examples/window-app/common/include/WindowApp.h +++ b/examples/window-app/common/include/WindowApp.h @@ -87,6 +87,8 @@ class WindowApp ProvisionedStateChanged, ConnectivityStateChanged, BLEConnectionsChanged, + WinkOff, + WinkOn, }; struct Event @@ -136,6 +138,7 @@ class WindowApp bool isThreadProvisioned = false; bool isThreadEnabled = false; bool haveBLEConnections = false; + bool isWinking = false; }; Cover & GetCover(); diff --git a/examples/window-app/common/src/WindowApp.cpp b/examples/window-app/common/src/WindowApp.cpp index af99c773cb2cab..01d9649d9b309d 100644 --- a/examples/window-app/common/src/WindowApp.cpp +++ b/examples/window-app/common/src/WindowApp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,49 @@ using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; using namespace chip::app::Clusters::WindowCovering; +inline void OnTriggerEffectCompleted(chip::System::Layer * systemLayer, void * appState) +{ + WindowApp::Instance().PostEvent(WindowApp::EventId::WinkOff); +} + +void OnTriggerEffect(Identify * identify) +{ + EmberAfIdentifyEffectIdentifier sIdentifyEffect = identify->mCurrentEffectIdentifier; + + ChipLogProgress(Zcl, "IDENTFY OnTriggerEffect"); + + if (identify->mCurrentEffectIdentifier == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE) + { + ChipLogProgress(Zcl, "IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE - Not supported, use effect varriant %d", + identify->mEffectVariant); + sIdentifyEffect = static_cast(identify->mEffectVariant); + } + + switch (sIdentifyEffect) + { + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY: + WindowApp::Instance().PostEvent(WindowApp::EventId::WinkOn); + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(5), OnTriggerEffectCompleted, identify); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_FINISH_EFFECT: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectCompleted, identify); + break; + default: + ChipLogProgress(Zcl, "No identifier effect"); + } +} + +Identify gIdentify = { + chip::EndpointId{ 1 }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStart"); }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStop"); }, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, + OnTriggerEffect, +}; + void WindowApp::Timer::Timeout() { mIsActive = false; diff --git a/examples/window-app/common/src/ZclCallbacks.cpp b/examples/window-app/common/src/ZclCallbacks.cpp index 42ddc8e8847820..b564449abcef39 100644 --- a/examples/window-app/common/src/ZclCallbacks.cpp +++ b/examples/window-app/common/src/ZclCallbacks.cpp @@ -39,7 +39,16 @@ using namespace ::chip::app::Clusters::WindowCovering; void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, uint16_t size, uint8_t * value) { - if (attributePath.mClusterId == Id) + if (attributePath.mClusterId == app::Clusters::Identify::Id) + { + ChipLogProgress(Zcl, "Identify cluster ID: " ChipLogFormatMEI " Type: %" PRIu8 " Value: %" PRIu16 ", length %" PRIu16, + ChipLogValueMEI(attributePath.mAttributeId), type, *value, size); + } + else if (attributePath.mClusterId == Id) + { + ChipLogProgress(Zcl, "Window cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(attributePath.mClusterId)); + } + else { ChipLogProgress(Zcl, "Unknown cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(attributePath.mClusterId)); } diff --git a/examples/window-app/common/window-app.zap b/examples/window-app/common/window-app.zap index 73bdaa2c02df73..882be5c3560a28 100644 --- a/examples/window-app/common/window-app.zap +++ b/examples/window-app/common/window-app.zap @@ -3426,7 +3426,7 @@ "mfgCode": null, "source": "client", "incoming": 1, - "outgoing": 1 + "outgoing": 0 }, { "name": "IdentifyQuery", @@ -3434,7 +3434,15 @@ "mfgCode": null, "source": "client", "incoming": 1, - "outgoing": 1 + "outgoing": 0 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 } ], "attributes": [ @@ -3461,20 +3469,20 @@ "mfgCode": null, "define": "IDENTIFY_CLUSTER", "side": "server", - "enabled": 0, + "enabled": 1, "commands": [ { "name": "IdentifyQueryResponse", "code": 0, "mfgCode": null, "source": "server", - "incoming": 1, + "incoming": 0, "outgoing": 1 } ], "attributes": [ { - "name": "identify time", + "name": "IdentifyTime", "code": 0, "mfgCode": null, "side": "server", @@ -3488,6 +3496,21 @@ "maxInterval": 65344, "reportableChange": 0 }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "ClusterRevision", "code": 65533, diff --git a/examples/window-app/efr32/src/WindowAppImpl.cpp b/examples/window-app/efr32/src/WindowAppImpl.cpp index 3c1de0115680d6..6d19e2930b410f 100644 --- a/examples/window-app/efr32/src/WindowAppImpl.cpp +++ b/examples/window-app/efr32/src/WindowAppImpl.cpp @@ -261,6 +261,12 @@ void WindowAppImpl::DispatchEvent(const WindowApp::Event & event) UpdateLEDs(); UpdateLCD(); break; + + case EventId::WinkOn: + case EventId::WinkOff: + mState.isWinking = (EventId::WinkOn == event.mId); + UpdateLEDs(); + break; case EventId::ConnectivityStateChanged: case EventId::BLEConnectionsChanged: UpdateLEDs(); @@ -298,7 +304,11 @@ void WindowAppImpl::UpdateLEDs() } else { - if (mState.isThreadProvisioned && mState.isThreadEnabled) + if (mState.isWinking) + { + mStatusLED.Blink(200, 200); + } + else if (mState.isThreadProvisioned && mState.isThreadEnabled) { mStatusLED.Blink(950, 50); } diff --git a/zzz_generated/window-app/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/window-app/zap-generated/IMClusterCommandHandler.cpp index 423fc9646c30ae..c8011a1c54ea7a 100644 --- a/zzz_generated/window-app/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/window-app/zap-generated/IMClusterCommandHandler.cpp @@ -167,6 +167,63 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP } // namespace GeneralCommissioning +namespace Identify { + +void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) +{ + // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV + // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. + // Any error value TLVUnpackError means we have received an illegal value. + // The following variables are used for all commands to save code size. + CHIP_ERROR TLVError = CHIP_NO_ERROR; + bool wasHandled = false; + { + switch (aCommandPath.mCommandId) + { + case Commands::Identify::Id: { + Commands::Identify::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfIdentifyClusterIdentifyCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::IdentifyQuery::Id: { + Commands::IdentifyQuery::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfIdentifyClusterIdentifyQueryCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::TriggerEffect::Id: { + Commands::TriggerEffect::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfIdentifyClusterTriggerEffectCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + default: { + // Unrecognized command ID, error status will apply. + ReportCommandUnsupported(apCommandObj, aCommandPath); + return; + } + } + } + + if (CHIP_NO_ERROR != TLVError || !wasHandled) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::InvalidCommand); + ChipLogProgress(Zcl, "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT, TLVError.Format()); + } +} + +} // namespace Identify + namespace NetworkCommissioning { void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) @@ -491,6 +548,9 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, TLV: case Clusters::GeneralCommissioning::Id: Clusters::GeneralCommissioning::DispatchServerCommand(apCommandObj, aCommandPath, aReader); break; + case Clusters::Identify::Id: + Clusters::Identify::DispatchServerCommand(apCommandObj, aCommandPath, aReader); + break; case Clusters::NetworkCommissioning::Id: Clusters::NetworkCommissioning::DispatchServerCommand(apCommandObj, aCommandPath, aReader); break; diff --git a/zzz_generated/window-app/zap-generated/PluginApplicationCallbacks.h b/zzz_generated/window-app/zap-generated/PluginApplicationCallbacks.h index 4d38da4f0e09f5..786865a1c7a556 100644 --- a/zzz_generated/window-app/zap-generated/PluginApplicationCallbacks.h +++ b/zzz_generated/window-app/zap-generated/PluginApplicationCallbacks.h @@ -28,6 +28,7 @@ MatterEthernetNetworkDiagnosticsPluginServerInitCallback(); \ MatterGeneralCommissioningPluginServerInitCallback(); \ MatterGeneralDiagnosticsPluginServerInitCallback(); \ + MatterIdentifyPluginServerInitCallback(); \ MatterNetworkCommissioningPluginServerInitCallback(); \ MatterOperationalCredentialsPluginServerInitCallback(); \ MatterSoftwareDiagnosticsPluginServerInitCallback(); \ diff --git a/zzz_generated/window-app/zap-generated/callback-stub.cpp b/zzz_generated/window-app/zap-generated/callback-stub.cpp index 309d5d8505fa43..1127e7a8d771ac 100644 --- a/zzz_generated/window-app/zap-generated/callback-stub.cpp +++ b/zzz_generated/window-app/zap-generated/callback-stub.cpp @@ -47,6 +47,9 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_GENERAL_DIAGNOSTICS_CLUSTER_ID: emberAfGeneralDiagnosticsClusterInitCallback(endpoint); break; + case ZCL_IDENTIFY_CLUSTER_ID: + emberAfIdentifyClusterInitCallback(endpoint); + break; case ZCL_NETWORK_COMMISSIONING_CLUSTER_ID: emberAfNetworkCommissioningClusterInitCallback(endpoint); break; @@ -101,6 +104,11 @@ void __attribute__((weak)) emberAfGeneralDiagnosticsClusterInitCallback(Endpoint // To prevent warning (void) endpoint; } +void __attribute__((weak)) emberAfIdentifyClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} void __attribute__((weak)) emberAfNetworkCommissioningClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/zzz_generated/window-app/zap-generated/endpoint_config.h b/zzz_generated/window-app/zap-generated/endpoint_config.h index 6592fd5f9afdbb..bd952b52a914fd 100644 --- a/zzz_generated/window-app/zap-generated/endpoint_config.h +++ b/zzz_generated/window-app/zap-generated/endpoint_config.h @@ -521,7 +521,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 180 +#define GENERATED_ATTRIBUTE_COUNT 183 #define GENERATED_ATTRIBUTES \ { \ \ @@ -683,6 +683,11 @@ ZAP_EMPTY_DEFAULT() }, /* CurrentFabricIndex */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* ClusterRevision */ \ \ + /* Endpoint: 1, Cluster: Identify (server) */ \ + { 0x0000, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(WRITABLE), ZAP_SIMPLE_DEFAULT(0x0000) }, /* identify time */ \ + { 0x0001, ZAP_TYPE(ENUM8), 1, 0, ZAP_SIMPLE_DEFAULT(0x0) }, /* identify type */ \ + { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(2) }, /* ClusterRevision */ \ + \ /* Endpoint: 1, Cluster: Descriptor (server) */ \ { 0x0000, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* device list */ \ { 0x0001, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* server list */ \ @@ -749,10 +754,14 @@ #define GENERATED_FUNCTION_ARRAYS \ const EmberAfGenericClusterFunction chipFuncArrayBasicServer[] = { \ (EmberAfGenericClusterFunction) emberAfBasicClusterServerInitCallback, \ + }; \ + const EmberAfGenericClusterFunction chipFuncArrayIdentifyServer[] = { \ + (EmberAfGenericClusterFunction) emberAfIdentifyClusterServerInitCallback, \ + (EmberAfGenericClusterFunction) MatterIdentifyClusterServerAttributeChangedCallback, \ }; #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 15 +#define GENERATED_CLUSTER_COUNT 16 #define GENERATED_CLUSTERS \ { \ { 0x001D, ZAP_ATTRIBUTE_INDEX(0), 5, 0, ZAP_CLUSTER_MASK(SERVER), NULL }, /* Endpoint: 0, Cluster: Descriptor (server) */ \ @@ -789,17 +798,23 @@ { \ 0x003E, ZAP_ATTRIBUTE_INDEX(124), 6, 4, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Operational Credentials (server) */ \ + { 0x0003, \ + ZAP_ATTRIBUTE_INDEX(130), \ + 3, \ + 5, \ + ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION), \ + chipFuncArrayIdentifyServer }, /* Endpoint: 1, Cluster: Identify (server) */ \ { \ - 0x001D, ZAP_ATTRIBUTE_INDEX(130), 5, 0, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x001D, ZAP_ATTRIBUTE_INDEX(133), 5, 0, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Descriptor (server) */ \ { \ - 0x0102, ZAP_ATTRIBUTE_INDEX(135), 20, 35, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0102, ZAP_ATTRIBUTE_INDEX(138), 20, 35, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 1, Cluster: Window Covering (server) */ \ { \ - 0x001D, ZAP_ATTRIBUTE_INDEX(155), 5, 0, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x001D, ZAP_ATTRIBUTE_INDEX(158), 5, 0, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 2, Cluster: Descriptor (server) */ \ { \ - 0x0102, ZAP_ATTRIBUTE_INDEX(160), 20, 35, ZAP_CLUSTER_MASK(SERVER), NULL \ + 0x0102, ZAP_ATTRIBUTE_INDEX(163), 20, 35, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 2, Cluster: Window Covering (server) */ \ } @@ -808,7 +823,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 11, 910 }, { ZAP_CLUSTER_INDEX(11), 2, 35 }, { ZAP_CLUSTER_INDEX(13), 2, 35 }, \ + { ZAP_CLUSTER_INDEX(0), 11, 910 }, { ZAP_CLUSTER_INDEX(11), 3, 40 }, { ZAP_CLUSTER_INDEX(14), 2, 35 }, \ } // Largest attribute size is needed for various buffers @@ -818,7 +833,7 @@ #define ATTRIBUTE_SINGLETONS_SIZE (246) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (980) +#define ATTRIBUTE_MAX_SIZE (985) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (3) diff --git a/zzz_generated/window-app/zap-generated/gen_config.h b/zzz_generated/window-app/zap-generated/gen_config.h index 99e2bb1d403069..90961a2fde9e94 100644 --- a/zzz_generated/window-app/zap-generated/gen_config.h +++ b/zzz_generated/window-app/zap-generated/gen_config.h @@ -35,6 +35,7 @@ #define EMBER_AF_ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_GENERAL_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_GENERAL_DIAGNOSTICS_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_IDENTIFY_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OPERATIONAL_CREDENTIALS_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_SOFTWARE_DIAGNOSTICS_CLUSTER_SERVER_ENDPOINT_COUNT (1) @@ -74,6 +75,11 @@ #define EMBER_AF_PLUGIN_GENERAL_DIAGNOSTICS_SERVER #define EMBER_AF_PLUGIN_GENERAL_DIAGNOSTICS +// Use this macro to check if the server side of the Identify cluster is included +#define ZCL_USING_IDENTIFY_CLUSTER_SERVER +#define EMBER_AF_PLUGIN_IDENTIFY_SERVER +#define EMBER_AF_PLUGIN_IDENTIFY + // Use this macro to check if the server side of the Network Commissioning cluster is included #define ZCL_USING_NETWORK_COMMISSIONING_CLUSTER_SERVER #define EMBER_AF_PLUGIN_NETWORK_COMMISSIONING_SERVER