This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Zs-tack中对于使用函数ReadWriteCB访问的Attribute,不能被Reporting。

Other Parts Discussed in Thread: Z-STACK

在Z-stack中,使用pfnReadWriteCB访问的Attribute和实际分配了全局变量的Attribute有什么区别?为什么前者不能用Reporting的方式进行上报?

针对上述情况,我修改了ZCL.c下面的函数zcl_SendReportCmd,使其能够被Reporting

ZStatus_t zcl_SendReportCmd( uint8 srcEP, afAddrType_t *dstAddr,
                             uint16 clusterID, zclReportCmd_t *reportCmd,
                             uint8 direction, uint8 disableDefaultRsp, uint8 seqNum )
{
  uint16 dataLen = 0;
  uint8 *buf;
  ZStatus_t status;
  uint8 i;

  // calculate the size of the command
  for ( i = 0; i < reportCmd->numAttr; i++ )
  {
    zclReport_t *reportRec = &(reportCmd->attrList[i]);

    dataLen += 2 + 1; // Attribute ID + data type

    // Attribute Data
    //dataLen += zclGetAttrDataLength( reportRec->dataType, reportRec->attrData );
    if( reportRec->attrData )
    {
      dataLen += zclGetAttrDataLength( reportRec->dataType, reportRec->attrData );
    }
    else
    {
      dataLen += zclGetAttrDataLengthUsingCB( srcEP, clusterID, reportRec->attrID );
    }
  }

  buf = zcl_mem_alloc( dataLen );
  if ( buf != NULL )
  {
    // Load the buffer - serially
    uint8 *pBuf = buf;

    for ( i = 0; i < reportCmd->numAttr; i++ )
    {
      zclReport_t *reportRec = &(reportCmd->attrList[i]);

      *pBuf++ = LO_UINT16( reportRec->attrID );
      *pBuf++ = HI_UINT16( reportRec->attrID );
      *pBuf++ = reportRec->dataType;

      //pBuf = zclSerializeData( reportRec->dataType, reportRec->attrData, pBuf );
      if ( reportRec->attrData != NULL )
      {
        // Copy attribute data to the buffer to be sent out
        pBuf = zclSerializeData( reportRec->dataType, reportRec->attrData, pBuf );
      }
      else
      {
        uint16 dataLen;
        // Read attribute data directly into the buffer to be sent out
        zclReadAttrDataUsingCB( srcEP, clusterID, reportRec->attrID, pBuf, &dataLen );
        pBuf += dataLen;
      }
    }

    status = zcl_SendCommand( srcEP, dstAddr, clusterID, ZCL_CMD_REPORT, FALSE,
                              direction, disableDefaultRsp, 0, seqNum, dataLen, buf );
    zcl_mem_free( buf );
  }
  else
  {
    status = ZMemError;
  }

  return ( status );
}

另外还要修改BDB_Reporting中的函数,这样改是否符合zigbee规范?

  • 看看你的問題跟 processors.wiki.ti.com/.../Zigbee_Known_Issues_and_Proposed_Fixes 裡的 BDB reporting doesn't support read/write attribute data callback functions 是否有關
  • 尝试替换下面的函数:

    uint8 *gAttrDataValue;
    
    static uint8 bdb_RepFindAttrEntry( uint8 endpoint, uint16 cluster, uint16 attrID, zclAttribute_t* attrRes )
    {
      epList_t *epCur = epList;
      uint8 i;
    
      zcl_memset(gAttrDataValue, 0, BDBREPORTING_MAX_ANALOG_ATTR_SIZE);
      for ( epCur = epList; epCur != NULL; epCur = epCur->nextDesc )
      {
        if( epCur->epDesc->endPoint == endpoint )
        {
          zclAttrRecsList* attrItem = zclFindAttrRecsList( epCur->epDesc->endPoint );
    
          if( (attrItem != NULL) && ( (attrItem->numAttributes > 0) && (attrItem->attrs != NULL) ) )
          {
            for ( i = 0; i < attrItem->numAttributes; i++ )
            {
              if ( ( attrItem->attrs[i].clusterID == cluster ) && ( attrItem->attrs[i].attr.attrId ==  attrID ) )
              {
                uint16 dataLen;
    
                attrRes->attrId = attrItem->attrs[i].attr.attrId;
                attrRes->dataType = attrItem->attrs[i].attr.dataType;
                attrRes->accessControl = attrItem->attrs[i].attr.accessControl;
    
                dataLen = zclGetDataTypeLength(attrRes->dataType);
                zcl_ReadAttrData( endpoint, cluster, attrRes->attrId, gAttrDataValue, &dataLen );
                attrRes->dataPtr = gAttrDataValue;
                return BDBREPORTING_TRUE;
              }
            }
          }
        }
      }
      return BDBREPORTING_FALSE;
    }

  • 我已经自己完成了BDB_Reporting文件的修改,在调用bdb_RepFindAttrEntry后,判断attrRec.dataPtr是否为NULL,再进行分支操作。
  • 你给的这段代码有bug,gAttrDataValue是一个野指针,而zcl_ReadAttrData需要填入的是一个buffer,其实可以在每次操作bdb_RepFindAttrEntry函数前对填入参数attrRes->dataPtr赋值一个Size= BDBREPORTING_MAX_ANALOG_ATTR_SIZE的Buffer,然后再用zcl_ReadAttrData直接填入attrRes->dataPtr指针。

    参考我的代码

    static uint8 bdb_RepFindAttrEntry( uint8 endpoint, uint16 cluster, uint16 attrID, zclAttribute_t* attrRes )
    {
      epList_t *epCur = epList;
      uint8 i;
      uint8 found = BDBREPORTING_FALSE;
      for ( epCur = epList; epCur != NULL; epCur = epCur->nextDesc )
      {
        if( epCur->epDesc->endPoint == endpoint )
        {
          zclAttrRecsList* attrItem = zclFindAttrRecsList( epCur->epDesc->endPoint );
          
          if( (attrItem != NULL) && ( (attrItem->numAttributes > 0) && (attrItem->attrs != NULL) ) )
          {
            for ( i = 0; i < attrItem->numAttributes; i++ )
            {
              if ( ( attrItem->attrs[i].clusterID == cluster ) && ( attrItem->attrs[i].attr.attrId ==  attrID ) )
              {
                attrRes->attrId = attrItem->attrs[i].attr.attrId;
                attrRes->dataType = attrItem->attrs[i].attr.dataType;
                attrRes->accessControl = attrItem->attrs[i].attr.accessControl;
                if(attrRes->dataPtr)
                {
                  uint16 dataLen = zclGetDataTypeLength(attrRes->dataType);
                  zcl_ReadAttrData( endpoint, cluster, attrRes->attrId, attrRes->dataPtr, &dataLen );
                }
                else
                {
                  attrRes->dataPtr = attrItem->attrs[i].attr.dataPtr;
                }
                return BDBREPORTING_TRUE;
              }
            }
          }
        }
      }
      return found;
    }

    然后进行如下调用

    1

              uint8  dataBuf[BDBREPORTING_MAX_ANALOG_ATTR_SIZE];
              zclAttribute_t attrRec = {.dataPtr = dataBuf};
              uint8 attrRes = bdb_RepFindAttrEntry( clusterEndpointItem->endpoint, clusterEndpointItem->cluster, attrListItem->data->attrID, &attrRec );

    在BDB_Reporting.c一共只有四处调用bdb_RepFindAttrEntry函数,每一处调用前都进行这种处理即可。