Part Number: CC2652R
Other Parts Discussed in Thread: SYSCONFIG, CC2652P, SIMPLELINK-CC13X2-26X2-SDK
In this condition, ZCL_Discover_Attribute command can't response other optional attributes.
It should be fixed like this
static uint8_t zclFindNextAttrRec( uint8_t endpoint, uint16_t clusterID, uint16_t manuCode, uint8_t direction,
uint16_t *attrId, zclAttrRec_t *pAttr, uint8_t *startIdx, bool cmpAttr )
{
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
uint8_t attrDir;
uint8_t matchManuCode = FALSE;
//match manufacturer-cluster, fixed by luoyiming 2020-01-08
if ( ( clusterID < 0xFC00 ) && ( manuCode != 0 ) )
{
matchManuCode = TRUE;
}
if ( pRec != NULL )
{
uint16_t x;
for ( x = *startIdx; x < pRec->numAttributes; x++ )
{
// match manufacturer attribute at first, luoyiming 2020-01-08
if ( ( pRec->attrs[x].attr.accessControl & ACCESS_MANU_ATTR ) && matchManuCode == FALSE )
{
continue;
}
if ( pRec->attrs[x].clusterID == clusterID )
{
// compare attrId or not, fixed by luoyiming 2021-07-04
if( (pRec->attrs[x].attr.attrId >= *attrId) || (cmpAttr == false) )
{
// also make sure direction is right
attrDir = (pRec->attrs[x].attr.accessControl & ACCESS_CLIENT) ? 1 : 0;
if ( (attrDir == direction) || (pRec->attrs[x].attr.accessControl & ACCESS_GLOBAL) )
{
// return attribute and found attribute ID
*pAttr = pRec->attrs[x];
*attrId = pAttr->attr.attrId;
*startIdx = x; // Update startIdx for next loop, luoyiming 2020-07-11
return ( TRUE ); // EMBEDDED RETURN
}
}
}
}
}
return ( FALSE );
}
uint8_t zclFindAttrRecEx( uint8_t endpoint, uint16_t clusterID, uint16_t manuCode, uint8_t direction,
uint16_t attrId, zclAttrRec_t *pAttr, uint8_t *idx )
{
uint8_t x;
zclAttrRecsList *pRec = zclFindAttrRecsList( endpoint );
uint8_t matchManuCode = FALSE;
// match manufacturer-cluster, fixed by luoyiming 2020-01-08
// don't execute for wildcard manufacturer ID, luoyiming add at 2020-01-09
if ( ( clusterID < 0xFC00 ) && ( manuCode != 0 ) && ( manuCode != 0xFFFF ) )
{
matchManuCode = TRUE;
}
if ( pRec != NULL )
{
for ( x = 0; x < pRec->numAttributes; x++ )
{
// match manufacturer attribute at first, luoyiming 2020-01-08
if ( ( pRec->attrs[x].attr.accessControl & ACCESS_MANU_ATTR ) && matchManuCode == FALSE )
{
continue;
}
if ( pRec->attrs[x].clusterID == clusterID && pRec->attrs[x].attr.attrId == attrId )
{
//match direction, fixed by luoyiming 2019-11-16
if ( (pRec->attrs[x].attr.accessControl & ACCESS_GLOBAL) ||
( GET_BIT( &(pRec->attrs[x].attr.accessControl), ACCESS_CONTROL_MASK ) == direction ) )
{
*pAttr = pRec->attrs[x];
// return the attribute's index, luoyiming 2021-07-04
if( idx != NULL )
{
*idx = x;
}
return ( TRUE ); // EMBEDDED RETURN
}
}
}
}
return ( FALSE );
}
static uint8_t zclProcessInDiscAttrs( zclIncoming_t *pInMsg )
{
zclDiscoverAttrsCmd_t *pDiscoverCmd;
zclAttrRec_t attrRec;
uint16_t attrID;
uint8_t numAttrs = 0;
uint8_t i;
uint8_t startIdx = 0;
uint8_t index;
bool findAttr = true;
pDiscoverCmd = (zclDiscoverAttrsCmd_t *)pInMsg->attrCmd;
// find the start attribute's index, luoyiming 2021-07-04
attrID = pDiscoverCmd->startAttr;
if ( !zclFindAttrRecEx( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, attrID, &attrRec, &startIdx ) )
{
// current attribute is not found, find the next valid attribute, louyiming 2021-07-04
if ( !zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, &attrID, &attrRec, &startIdx, true ) )
{
// attribute is not found, louyiming 2021-07-04
findAttr = false;
}
}
index = startIdx;
if( findAttr ) // If attribute is not found, set total number is 0. louyiming 2021-07-04
{
// Find out the number of attributes supported within the specified range
for ( i = 0; i < pDiscoverCmd->maxAttrIDs; i++ )
{
// finds the next attribute on this endpoint/cluster after the range.
// attributes must be in numerical order in the list.
if ( !zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, &attrID, &attrRec, &index, false ) )
{
break;
}
index += 1; // update startIdx for next loop, luoyiming fixed at 2020-07-22
}
numAttrs = i; // store range of attributes in buffer
}
// Process message for either attributes or extended attributes
if ( pInMsg->hdr.commandID == ZCL_CMD_DISCOVER_ATTRS )
{
zclProcessInDiscAttrsCmd( pInMsg, pDiscoverCmd, numAttrs, startIdx );
}
else if ( pInMsg->hdr.commandID == ZCL_CMD_DISCOVER_ATTRS_EXT )
{
zclProcessInDiscAttrsExtCmd( pInMsg, pDiscoverCmd, numAttrs, startIdx );
}
return TRUE;
}
static void zclProcessInDiscAttrsCmd( zclIncoming_t *pInMsg, zclDiscoverAttrsCmd_t *pDiscoverCmd, uint8_t numAttrs, uint8_t startIdx )
{
zclDiscoverAttrsRspCmd_t *pDiscoverRsp;
uint8_t discComplete = TRUE;
zclAttrRec_t attrRec;
uint16_t attrID;
uint8_t i;
// Allocate space for the response command
pDiscoverRsp = (zclDiscoverAttrsRspCmd_t *)zcl_mem_alloc( sizeof (zclDiscoverAttrsRspCmd_t)
+ sizeof ( zclDiscoverAttrInfo_t ) * numAttrs );
if ( pDiscoverRsp == NULL )
{
return; // EMBEDDED RETURN
}
if ( numAttrs != 0 )
{
for ( i = 0; i < numAttrs; i++ )
{
if ( !zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, &attrID, &attrRec, &startIdx, false ) )
{
break; // should not happen, as numAttrs already calculated
}
pDiscoverRsp->attrList[i].attrID = attrRec.attr.attrId;
pDiscoverRsp->attrList[i].dataType = attrRec.attr.dataType;
startIdx += 1; // update startIdx for next loop, luoyiming fixed at 2020-07-22
}
// Are there more attributes to be discovered?
if ( zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, &attrID, &attrRec, &startIdx, false ) )
{
discComplete = FALSE;
}
}
pDiscoverRsp->discComplete = discComplete;
pDiscoverRsp->numAttr = numAttrs;
zcl_SendDiscoverAttrsRspCmd( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
pInMsg->msg->clusterId, pDiscoverRsp, !(pInMsg->hdr.fc.direction),
true, pInMsg->hdr.manuCode, pInMsg->hdr.transSeqNum );
zcl_mem_free( pDiscoverRsp );
return;
}
static void zclProcessInDiscAttrsExtCmd( zclIncoming_t *pInMsg, zclDiscoverAttrsCmd_t *pDiscoverCmd, uint8_t numAttrs, uint8_t startIdx )
{
zclDiscoverAttrsExtRsp_t *pDiscoverExtRsp;
uint8_t discComplete = TRUE;
zclAttrRec_t attrRec;
uint16_t attrID;
uint8_t i;
// Allocate space for the response command
pDiscoverExtRsp = (zclDiscoverAttrsExtRsp_t *)zcl_mem_alloc( sizeof (zclDiscoverAttrsExtRsp_t)
+ sizeof ( zclExtAttrInfo_t ) * numAttrs );
if ( pDiscoverExtRsp == NULL )
{
return; // EMBEDDED RETURN
}
if ( numAttrs != 0 )
{
for ( i = 0; i < numAttrs; i++ )
{
if ( !zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, &attrID, &attrRec, &startIdx, false ) )
{
break; // Should not happen, as numAttrs already calculated
}
pDiscoverExtRsp->aExtAttrInfo[i].attrID = attrRec.attr.attrId;
pDiscoverExtRsp->aExtAttrInfo[i].attrDataType = attrRec.attr.dataType;
pDiscoverExtRsp->aExtAttrInfo[i].attrAccessControl = attrRec.attr.accessControl & ACCESS_CONTROLEXT_MASK;
startIdx += 1; // update startIdx for next loop, luoyiming fixed at 2020-07-22
}
// Are there more attributes to be discovered?
if ( zclFindNextAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, pInMsg->hdr.manuCode,
pInMsg->hdr.fc.direction, &attrID, &attrRec, &startIdx, false ) )
{
discComplete = FALSE;
}
}
pDiscoverExtRsp->discComplete = discComplete;
pDiscoverExtRsp->numAttr = numAttrs;
zcl_SendDiscoverAttrsExtRsp( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
pInMsg->msg->clusterId, pDiscoverExtRsp, !(pInMsg->hdr.fc.direction),
true, pInMsg->hdr.manuCode, pInMsg->hdr.transSeqNum );
zcl_mem_free( pDiscoverExtRsp );
return;
}
The idea is that:
1, Find the index of start attribute of zcl-DIsc-Attr command in device's attribute table. If the start attribute is not valid in attribute table, find another attribute whose attribute-ID is larger than it.
2, Generate the zcl-Disc-Attr Response from start-attribute's index to the end of attribute table.