代码之家  ›  专栏  ›  技术社区  ›  komelgman

CC253x固件的非标准ZCL包支持

  •  0
  • komelgman  · 技术社区  · 7 年前

    Livolo交换机有自己的Zigbee门。我想把它们从zigbee2mqtt连接到CC2531 USB加密狗。一般来说,它是可以工作的,但是当我打开/关闭开关按钮(在物理设备上)时,交换机发送的ZCL包不正确。

    我绝对是微控制器编程和Zigbee架构的新手。所以我希望有人能帮我回答这些问题:

    • 如何修复该包以支持Zigbee标准?

    https://github.com/Koenkk/Z-Stack-firmware/blob/master/coordinator/Z-Stack_Home_1.2/COMPILE.md

    // Malformed ZCL package
    // header    
    0x7c, // [0111 1100]
          // 01 - frame type = "Command is specific or local to a cluster"
          // 1 - manufacturer spec = manufacturer code present
          // 1 - direction = "from server to client"
          // 1 - disable default response 
          // 100 - reserved
    
    0xd2, 0x15, // manufacturer  
    0xd8, // sequence  
    0x00, // read attrs command
    
    // endpoint adress 
    0x12, 0x0f, 0x05, 0x18, 0x00, 0x4b, 0x12, 0x00, 
    
    0x22, 0x00, // ????? need more data from another switches
    
    0x03 // 0x00|0x01|0x02|0x03 - switch state
    

    升级版: 我想,我可以在afIncomingData函数中截取AF.c文件中的消息并修复afBuildMSGIncoming。

    void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,
                         NLDE_Signal_t *sig, uint8 nwkSeqNum, uint8 SecurityUse,
                         uint32 timestamp, uint8 radius )
    {
      endPointDesc_t *epDesc = NULL;
      epList_t *pList = epList;
    #if !defined ( APS_NO_GROUPS )
      uint8 grpEp = APS_GROUPS_EP_NOT_FOUND;
    #endif
    
      if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
      {
    #if !defined ( APS_NO_GROUPS )
        // Find the first endpoint for this group
        grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST );
        if ( grpEp == APS_GROUPS_EP_NOT_FOUND ) {
          // No endpoint found, default to endpoint 1.
          // In the original source code there is a return here. 
          // This prevent the messags from being forwarded.
          // For our use-case we want to capture all messages. 
          // Even if the coordinator is not in the group.
          epDesc = afFindEndPointDesc( 1 );
        }
        else {
          epDesc = afFindEndPointDesc( grpEp );
        }
    
        if ( epDesc == NULL )
          return;   // Endpoint descriptor not found
    
        pList = afFindEndPointDescList( epDesc->endPoint );
    #else
        return; // Not supported
    #endif
      }
      else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
      {
        // Set the list
        if ( pList != NULL )
        {
          epDesc = pList->epDesc;
        }
      }
      else if ( aff->DstEndPoint == 10 || aff->DstEndPoint == 11 ) {
        if ( (epDesc = afFindEndPointDesc( 1 )) )
        {
          pList = afFindEndPointDescList( epDesc->endPoint );
        }
      }
      else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) )
      {
        pList = afFindEndPointDescList( epDesc->endPoint );
      }
    
      while ( epDesc )
      {
        uint16 epProfileID = 0xFFFE;  // Invalid Profile ID
    
        if ( pList->pfnDescCB )
        {
          uint16 *pID = (uint16 *)(pList->pfnDescCB(
                                     AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint ));
          if ( pID )
          {
            epProfileID = *pID;
            osal_mem_free( pID );
          }
        }
        else if ( epDesc->simpleDesc )
        {
          epProfileID = epDesc->simpleDesc->AppProfId;
        }
    
        // First part of verification is to make sure that:
        // the local Endpoint ProfileID matches the received ProfileID OR
        // the message is specifically send to ZDO (this excludes the broadcast endpoint) OR
        // if the Wildcard ProfileID is received the message should not be sent to ZDO endpoint
        if ( (aff->ProfileID == epProfileID) ||
             ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) ||
             ((epDesc->endPoint != ZDO_EP) && ( aff->ProfileID == ZDO_WILDCARD_PROFILE_ID )) )
        {
          // Save original endpoint
          uint8 endpoint = aff->DstEndPoint;
    
          // overwrite with descriptor's endpoint
          aff->DstEndPoint = epDesc->endPoint;
    
          afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig,
                             nwkSeqNum, SecurityUse, timestamp, radius );
    
          // Restore with original endpoint
          aff->DstEndPoint = endpoint;
        }
    
        if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
        {
    #if !defined ( APS_NO_GROUPS )
          // Find the next endpoint for this group
          grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp );
          if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
            return;   // No endpoint found
    
          epDesc = afFindEndPointDesc( grpEp );
          if ( epDesc == NULL )
            return;   // Endpoint descriptor not found
    
          pList = afFindEndPointDescList( epDesc->endPoint );
    #else
          return;
    #endif
        }
        else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
        {
          pList = pList->nextDesc;
          if ( pList )
            epDesc = pList->epDesc;
          else
            epDesc = NULL;
        }
        else
          epDesc = NULL;
      }
    }
    
    static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,
                     zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig,
                     uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp, uint8 radius )
    {
      afIncomingMSGPacket_t *MSGpkt;
      const uint8 len = sizeof( afIncomingMSGPacket_t ) + aff->asduLength;
      uint8 *asdu = aff->asdu;
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_allocate( len );
    
      if ( MSGpkt == NULL )
      {
        return;
      }
    
      MSGpkt->hdr.event = AF_INCOMING_MSG_CMD;
      MSGpkt->groupId = aff->GroupID;
      MSGpkt->clusterId = aff->ClusterID;
      afCopyAddress( &MSGpkt->srcAddr, SrcAddress );
      MSGpkt->srcAddr.endPoint = aff->SrcEndPoint;
      MSGpkt->endPoint = epDesc->endPoint;
      MSGpkt->wasBroadcast = aff->wasBroadcast;
      MSGpkt->LinkQuality = sig->LinkQuality;
      MSGpkt->correlation = sig->correlation;
      MSGpkt->rssi = sig->rssi;
      MSGpkt->SecurityUse = SecurityUse;
      MSGpkt->timestamp = timestamp;
      MSGpkt->nwkSeqNum = nwkSeqNum;
      MSGpkt->macSrcAddr = aff->macSrcAddr;
      MSGpkt->macDestAddr = aff->macDestAddr;
      MSGpkt->srcAddr.panId = SrcPanId;
      MSGpkt->cmd.TransSeqNumber = 0;
      MSGpkt->cmd.DataLength = aff->asduLength;
      MSGpkt->radius = radius;
    
      if ( MSGpkt->cmd.DataLength )
      {
        MSGpkt->cmd.Data = (uint8 *)(MSGpkt + 1);
        osal_memcpy( MSGpkt->cmd.Data, asdu, MSGpkt->cmd.DataLength );
      }
      else
      {
        MSGpkt->cmd.Data = NULL;
      }
    
    #if defined ( MT_AF_CB_FUNC )
      // If ZDO or SAPI have registered for this endpoint, dont intercept it here
      if (AFCB_CHECK(CB_ID_AF_DATA_IND, *(epDesc->task_id)))
      {
        MT_AfIncomingMsg( (void *)MSGpkt );
        // Release the memory.
        osal_msg_deallocate( (void *)MSGpkt );
      }
      else
    #endif
      {
        // Send message through task message.
        osal_msg_send( *(epDesc->task_id), (uint8 *)MSGpkt );
      }
    }
    
    0 回复  |  直到 6 年前
        1
  •  3
  •   tomlogic    6 年前

    0x7c, // [0111 1100]
          // 011 - reserved
          // 1 - disable default response 
          // 1 - direction = "from server to client"
          // 1 - manufacturer spec = manufacturer code present
          // 00 - frame type = "Command acts across entire profile"
    

    这是基于旧的ZCL规范(大约在2008年?)也许在以后的规范版本中,保留位已经有了一些意义。

    我相信制造商特定的位表明这是

    更新: afIncomingData() 去看看 aff 识别这个确切的消息类型(帧控制、端点、集群、概要文件),然后将其交给您自己的函数进行处理(并在必要时进行响应)。

    MT_AF_CB_FUNC MT_AfIncomingMsg() 看看这是否是“官方”的方法来识别您想要在自己的代码中处理的帧。

        2
  •  3
  •   komelgman    6 年前

    AF.c 函数afIncomingData和afBuildMSGIncoming中的文件添加了标记为

    #if defined ( LIVOLO_SUPPORT ) 
    #endif
    

    在afIncomingData中,我添加了:

    #if defined ( LIVOLO_SUPPORT )  
      else if ( aff->DstEndPoint == 0x08 ) 
      {
        if ( (epDesc = afFindEndPointDesc( 1 )) )
        {
          pList = afFindEndPointDescList( epDesc->endPoint );
        }
      }  
    #endif  
    

    它预先过滤发送到未知目标端点的消息

    传入和生成MSGinafFunction:

    #if defined ( LIVOLO_SUPPORT )
      uint8 fixedPackage[] = { 
            0x18, 0xd8, 0x01, // header
            0x00, 0x00, // attrId
            0x00, // success
            0x10, // boolean
            0x00
          };
    
      if (aff->SrcEndPoint == 0x06 && aff->DstEndPoint == 0x01 
          && aff->ClusterID == 0x0001 && aff->ProfileID == 0x0104) {
    
        const uint8 mlfrmdHdr[] = { 0x7c, 0xd2, 0x15, 0xd8, 0x00 }; 
        if (osal_memcmp(asdu, mlfrmdHdr, 5) == TRUE) {      
          fixedPackage[7] = asdu[aff->asduLength - 1];
          MSGpkt->cmd.DataLength = 8; // sizeof(fixedPackage)
          MSGpkt->clusterId = 0x06; // genOnOff
          asdu = fixedPackage;
        }
      }
    #endif
    

    它将不支持的包更改为readAttrResp包。