Other Parts Discussed in Thread: Z-STACK
Tool/software: WEBENCH® Design Tools
It is known that the ZCL of z-stack don't support manufacture code, don't support specific-command filter. Some zigbee device who is base on zstack can receives and executes specific-command whose cluster ID and command-ID can't be lookup by ZDP-Simple-Desc-req and ZCL-DISCOVER-CMDS.
1st, add this function in zcl.c
/*********************************************************************
* @fn zcl_matchClusterId
*
* @brief Match if cluster ID is supported by current EP, add by
* Luoyiming, 2019-10-20
*
* @param pInMsg - incoming message to process
*
* @return TRUE if cluster ID is supported by EP, FALSE ont support
*/
uint8_t zcl_matchClusterId( zclIncoming_t *pInMsg )
{
uint8_t free = FALSE;
uint8_t match = FALSE;
SimpleDescriptionFormat_t *sDesc = NULL;
free = afFindSimpleDesc( &sDesc, pInMsg->msg->endPoint );
if ( sDesc )
{
uint8_t numClusters = 0;
cId_t *pClusterList = NULL;
if ( zcl_ServerCmd(pInMsg->hdr.fc.direction) ) // match if InCluster is support by sever.
{
numClusters = sDesc->AppNumInClusters;
pClusterList = sDesc->pAppInClusterList;
}
else if ( zcl_ClientCmd(pInMsg->hdr.fc.direction) )// match if OutCluster is support by client.
{
numClusters = sDesc->AppNumOutClusters;
pClusterList = sDesc->pAppOutClusterList;
}
//match incoming message cluster with EP's SimpleDesc.
if ( ( pClusterList != NULL ) && ( numClusters ) )
{
uint8_t n;
for ( n = 0; n < numClusters; n++ )
{
if ( pInMsg->msg->clusterId == pClusterList[n] )
{
match = TRUE;
break;
}
}
}
}
if ( free && sDesc )
{
zcl_mem_free( sDesc );
}
return match;
}
2nd, add "zclGenUnsupportCallback" into zcl_general.c to execute manufacture code command. This function can also collect wrong command receiving.
static ZStatus_t (*zclGenUnsupportCallback)(zclIncoming_t* pInMsg) = NULL;
/*********************************************************************
* @fn zclGeneral_RegisterUnsupportCallback
*
* @brief Register an callback for unsupport endpoint
*
* @param callback - pointer to the callback record.
*
* @return NONE
*/
void zclGeneral_RegisterUnsupportCallback( ZStatus_t (*callback)(zclIncoming_t*pInMsg) )
{
// Register as a ZCL Plugin
if ( zclGenPluginRegisted == FALSE )
{
zcl_registerPlugin( ZCL_CLUSTER_ID_GEN_BASIC,
ZCL_CLUSTER_ID_GEN_MULTISTATE_VALUE_BASIC,
zclGeneral_HdlIncoming );
#ifdef ZCL_SCENES
// Initialize the Scenes Table
zclGeneral_ScenesInit();
#endif // ZCL_SCENES
zclGenPluginRegisted = TRUE;
}
zclGenUnsupportCallback = callback;
}
3rd, fix function "zclGeneral_HdlIncoming"
if ( zcl_ClusterCmd( pInMsg->hdr.fc.type ) )
{
// Is this a manufacturer specific command?
stat = ZFailure;
if ( pInMsg->hdr.fc.manuSpecific == 0 )
{
if ( zcl_matchClusterId( pInMsg ) ) //match cluster ID support.
{
#ifdef ZCL_DISCOVER
zclCommandRec_t cmdRec;
if( TRUE == zclFindCmdRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId,
pInMsg->hdr.commandID, &cmdRec ) )
{
if( ( zcl_ServerCmd(pInMsg->hdr.fc.direction) && (cmdRec.flag & CMD_DIR_SERVER_RECEIVED) ) ||
( zcl_ClientCmd(pInMsg->hdr.fc.direction) && (cmdRec.flag & CMD_DIR_CLIENT_RECEIVED) ) )
{
stat = zclGeneral_HdlInSpecificCommands( pInMsg );
}
}
#else
stat = zclGeneral_HdlInSpecificCommands( pInMsg );
#endif
}
}
else
{
// We don't support any manufacturer specific command.
stat = ZFailure;
}
//execute unsupported command,luoyiming fix at 2019-07-20
if( stat == ZFailure)
{
if( zclGenUnsupportCallback )
{
stat = zclGenUnsupportCallback( pInMsg );
}
}
}
4th, This model can be used in any other zlc plugin, such as zcl_ss, zcl_se, zcl_hvac.