diff --git a/examples/lighting-app/lighting-common/gen/IMClusterCommandHandler.cpp b/examples/lighting-app/lighting-common/gen/IMClusterCommandHandler.cpp index 6b5fba4464f174..1bd2f0d3347f94 100644 --- a/examples/lighting-app/lighting-common/gen/IMClusterCommandHandler.cpp +++ b/examples/lighting-app/lighting-common/gen/IMClusterCommandHandler.cpp @@ -1909,6 +1909,189 @@ void DispatchServerCommand(app::CommandHandler * apCommandObj, CommandId aComman } // namespace GeneralCommissioning +namespace Identify { + +void DispatchServerCommand(app::CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, + 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; + CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; + uint32_t validArgumentCount = 0; + uint32_t expectArgumentCount = 0; + uint32_t currentDecodeTagId = 0; + bool wasHandled = false; + { + switch (aCommandId) + { + case Clusters::Identify::Commands::Ids::Identify: { + expectArgumentCount = 1; + uint16_t identifyTime; + bool argExists[1]; + + memset(argExists, 0, sizeof argExists); + + while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. + if (!TLV::IsContextTag(aDataTlv.GetTag())) + { + continue; + } + currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); + if (currentDecodeTagId < 1) + { + if (argExists[currentDecodeTagId]) + { + ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); + TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + break; + } + else + { + argExists[currentDecodeTagId] = true; + validArgumentCount++; + } + } + switch (currentDecodeTagId) + { + case 0: + TLVUnpackError = aDataTlv.Get(identifyTime); + break; + default: + // Unsupported tag, ignore it. + ChipLogProgress(Zcl, "Unknown TLV tag during processing."); + break; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + break; + } + } + + if (CHIP_END_OF_TLV == TLVError) + { + // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. + TLVError = CHIP_NO_ERROR; + } + + if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) + { + // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. + wasHandled = emberAfIdentifyClusterIdentifyCallback(apCommandObj, identifyTime); + } + break; + } + case Clusters::Identify::Commands::Ids::IdentifyQuery: { + + // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. + wasHandled = emberAfIdentifyClusterIdentifyQueryCallback(apCommandObj); + break; + } + case Clusters::Identify::Commands::Ids::TriggerEffect: { + expectArgumentCount = 2; + uint8_t effectId; + uint8_t effectVariant; + bool argExists[2]; + + memset(argExists, 0, sizeof argExists); + + while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. + if (!TLV::IsContextTag(aDataTlv.GetTag())) + { + continue; + } + currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); + if (currentDecodeTagId < 2) + { + if (argExists[currentDecodeTagId]) + { + ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); + TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + break; + } + else + { + argExists[currentDecodeTagId] = true; + validArgumentCount++; + } + } + switch (currentDecodeTagId) + { + case 0: + TLVUnpackError = aDataTlv.Get(effectId); + break; + case 1: + TLVUnpackError = aDataTlv.Get(effectVariant); + break; + default: + // Unsupported tag, ignore it. + ChipLogProgress(Zcl, "Unknown TLV tag during processing."); + break; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + break; + } + } + + if (CHIP_END_OF_TLV == TLVError) + { + // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. + TLVError = CHIP_NO_ERROR; + } + + if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount) + { + // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. + wasHandled = emberAfIdentifyClusterTriggerEffectCallback(apCommandObj, effectId, effectVariant); + } + break; + } + default: { + // Unrecognized command ID, error status will apply. + chip::app::CommandPathParams returnStatusParam = { aEndpointId, + 0, // GroupId + Clusters::Identify::Id, aCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, + Protocols::SecureChannel::Id, + Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); + ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::Identify::Id); + return; + } + } + } + + if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) + { + chip::app::CommandPathParams returnStatusParam = { aEndpointId, + 0, // GroupId + Clusters::Identify::Id, aCommandId, + (chip::app::CommandPathFlags::kEndpointIdValid) }; + apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, + Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); + ChipLogProgress(Zcl, + "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT + ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, + validArgumentCount, expectArgumentCount, ChipError::FormatError(TLVError), + ChipError::FormatError(TLVUnpackError), currentDecodeTagId); + // A command with no arguments would never write currentDecodeTagId. If + // progress logging is also disabled, it would look unused. Silence that + // warning. + UNUSED_VAR(currentDecodeTagId); + } +} + +} // namespace Identify + namespace LevelControl { void DispatchServerCommand(app::CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, @@ -3750,6 +3933,9 @@ void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aC case Clusters::GeneralCommissioning::Id: clusters::GeneralCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; + case Clusters::Identify::Id: + clusters::Identify::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); + break; case Clusters::LevelControl::Id: clusters::LevelControl::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; diff --git a/examples/lighting-app/lighting-common/gen/callback-stub.cpp b/examples/lighting-app/lighting-common/gen/callback-stub.cpp index acba1cc98d6df6..7ba3597a72f9e8 100644 --- a/examples/lighting-app/lighting-common/gen/callback-stub.cpp +++ b/examples/lighting-app/lighting-common/gen/callback-stub.cpp @@ -46,6 +46,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_LEVEL_CONTROL_CLUSTER_ID: emberAfLevelControlClusterInitCallback(endpoint); break; @@ -106,6 +109,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)) emberAfLevelControlClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/examples/lighting-app/lighting-common/gen/endpoint_config.h b/examples/lighting-app/lighting-common/gen/endpoint_config.h index e6be40bfa8eb2f..681b05f346b54c 100644 --- a/examples/lighting-app/lighting-common/gen/endpoint_config.h +++ b/examples/lighting-app/lighting-common/gen/endpoint_config.h @@ -649,7 +649,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 140 +#define GENERATED_ATTRIBUTE_COUNT 142 #define GENERATED_ATTRIBUTES \ { \ \ @@ -780,6 +780,10 @@ { 0x0001, ZAP_TYPE(ARRAY), 254, 0, ZAP_LONG_DEFAULTS_INDEX(1672) }, /* fabrics list */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* cluster revision */ \ \ + /* Endpoint: 1, Cluster: Identify (server) */ \ + { 0x0000, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(WRITABLE), ZAP_SIMPLE_DEFAULT(0x0000) }, /* identify time */ \ + { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(2) }, /* cluster revision */ \ + \ /* Endpoint: 1, Cluster: On/off (server) */ \ { 0x0000, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_SIMPLE_DEFAULT(0x00) }, /* OnOff */ \ { 0x4000, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_SIMPLE_DEFAULT(0x01) }, /* GlobalSceneControl */ \ @@ -835,6 +839,10 @@ const EmberAfGenericClusterFunction chipFuncArrayBasicServer[] = { \ (EmberAfGenericClusterFunction) emberAfBasicClusterServerInitCallback, \ }; \ + const EmberAfGenericClusterFunction chipFuncArrayIdentifyServer[] = { \ + (EmberAfGenericClusterFunction) emberAfIdentifyClusterServerInitCallback, \ + (EmberAfGenericClusterFunction) emberAfIdentifyClusterServerAttributeChangedCallback, \ + }; \ const EmberAfGenericClusterFunction chipFuncArrayOnOffServer[] = { \ (EmberAfGenericClusterFunction) emberAfOnOffClusterServerInitCallback, \ }; \ @@ -849,7 +857,7 @@ }; #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 14 +#define GENERATED_CLUSTER_COUNT 15 #define GENERATED_CLUSTERS \ { \ { 0x0028, \ @@ -885,26 +893,32 @@ { \ 0x003E, ZAP_ATTRIBUTE_INDEX(101), 2, 256, ZAP_CLUSTER_MASK(SERVER), NULL \ }, /* Endpoint: 0, Cluster: Operational Credentials (server) */ \ - { 0x0006, \ + { 0x0003, \ ZAP_ATTRIBUTE_INDEX(103), \ + 2, \ + 4, \ + ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION), \ + chipFuncArrayIdentifyServer }, /* Endpoint: 1, Cluster: Identify (server) */ \ + { 0x0006, \ + ZAP_ATTRIBUTE_INDEX(105), \ 6, \ 9, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayOnOffServer }, /* Endpoint: 1, Cluster: On/off (server) */ \ { 0x0008, \ - ZAP_ATTRIBUTE_INDEX(109), \ + ZAP_ATTRIBUTE_INDEX(111), \ 5, \ 7, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayLevelControlServer }, /* Endpoint: 1, Cluster: Level Control (server) */ \ { 0x0300, \ - ZAP_ATTRIBUTE_INDEX(114), \ + ZAP_ATTRIBUTE_INDEX(116), \ 22, \ 36, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ chipFuncArrayColorControlServer }, /* Endpoint: 1, Cluster: Color Control (server) */ \ { 0x0406, \ - ZAP_ATTRIBUTE_INDEX(136), \ + ZAP_ATTRIBUTE_INDEX(138), \ 4, \ 5, \ ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ @@ -916,7 +930,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 10, 1988 }, { ZAP_CLUSTER_INDEX(10), 4, 57 }, \ + { ZAP_CLUSTER_INDEX(0), 10, 1988 }, { ZAP_CLUSTER_INDEX(10), 5, 61 }, \ } // Largest attribute size is needed for various buffers @@ -926,7 +940,7 @@ #define ATTRIBUTE_SINGLETONS_SIZE (642) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (2045) +#define ATTRIBUTE_MAX_SIZE (2049) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (2) @@ -970,7 +984,7 @@ // Array of EmberAfCommandMetadata structs. #define ZAP_COMMAND_MASK(mask) COMMAND_MASK_##mask -#define EMBER_AF_GENERATED_COMMAND_COUNT (73) +#define EMBER_AF_GENERATED_COMMAND_COUNT (77) #define GENERATED_COMMANDS \ { \ \ @@ -1028,6 +1042,12 @@ { 0x003E, 0xA1, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* AddTrustedRootCertificate */ \ { 0x003E, 0xA2, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* RemoveTrustedRootCertificate */ \ \ + /* Endpoint: 1, Cluster: Identify (server) */ \ + { 0x0003, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* Identify */ \ + { 0x0003, 0x00, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* IdentifyQueryResponse */ \ + { 0x0003, 0x01, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* IdentifyQuery */ \ + { 0x0003, 0x40, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* TriggerEffect */ \ + \ /* Endpoint: 1, Cluster: On/off (server) */ \ { 0x0006, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* Off */ \ { 0x0006, 0x01, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* On */ \ diff --git a/examples/lighting-app/lighting-common/gen/gen_config.h b/examples/lighting-app/lighting-common/gen/gen_config.h index f0ef37c275eec4..9b35d7b3c834b3 100644 --- a/examples/lighting-app/lighting-common/gen/gen_config.h +++ b/examples/lighting-app/lighting-common/gen/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_LEVEL_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OCCUPANCY_SENSING_CLUSTER_SERVER_ENDPOINT_COUNT (1) @@ -80,6 +81,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 Level Control cluster is included #define ZCL_USING_LEVEL_CONTROL_CLUSTER_SERVER #define EMBER_AF_PLUGIN_LEVEL_CONTROL_SERVER