我是靠谱客的博主 听话翅膀,最近开发中收集的这篇文章主要介绍ZigBee ZDO_NetworkDiscoveryConfirmCB方法 及 ZDO_NWK_DISC_CNF事件源码分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述


当模块调用NLME_NetworkDiscoveryRequest()搜索周边路由节点或协调器节点时,当底层发现其他模块时,会调用ZDO层的ZDO_NetworkDiscoveryConfirmCB( uint8 ResultCount,   networkDesc_t *NetworkList ) 方法。我现在对这个方法的理解也是一知半解,在这里先记录一下,以后有时间再回来慢慢理解。


#define STACK_PROFILE_MAX 2

//NetworkList是一个链表,可能包括多个设备,ResultCount其实返回的是链表的节点个数
ZStatus_t ZDO_NetworkDiscoveryConfirmCB( uint8 ResultCount,
                                         networkDesc_t *NetworkList )
{
  networkDesc_t *pNwkDesc = NetworkList;
  ZDO_NetworkDiscoveryCfm_t msg;
  uint8 i = ResultCount;
  uint8 stackProfile;
  uint8 stackProfilePro;
  uint8 selected;

#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
  if ( zdappMgmtNwkDiscReqInProgress )
  {
    zdappMgmtNwkDiscReqInProgress = false;
    ZDO_FinishProcessingMgmtNwkDiscReq( ResultCount, NetworkList );
    return ( ZSuccess );
  }
#endif

  // process discovery results
  stackProfilePro = FALSE;
  selected = FALSE;

  
  
  //用来循环不同的协议版本,不知道为什么要对协议版本进行循环
  for ( stackProfile = 0; stackProfile < STACK_PROFILE_MAX; stackProfile++ )
  {
    //所发现的网络不论属于那个协议栈,都是加在同一个链表里NetworkList,
    //故针对新一个协议版本,都得重新开查找所有网络
    pNwkDesc = NetworkList;
    
    for ( i = 0; i < ResultCount; i++, pNwkDesc = pNwkDesc->nextDesc )
    {
      
      //printf("find count:%d padId:%X rn",ResultCount,pNwkDesc->panId);
      
      /*
        zgConfigPANID其实就是f8wConfig.cfg中的ZDAPP_CONFIG_PAN_ID,
       一般为0XFFFF,如果 ZDAPP_CONFIG_PAN_ID被定义为0xFFFF,
      那么协调器将根据自身的IEEE地址建立一个随机的PAN ID,
      如果ZDAPP_CONFIG_PAN_ID 没有被定义为0xFFFF,
      那么协调器建立网络的PAN ID将由ZDAPP_CONFIG_PAN_ID指定
      */
      if ( zgConfigPANID != 0xFFFF )
      {
        // PAN Id is preconfigured. check if it matches
        /*检查發現网络的PAN ID与
        配置文件指定所需要的PAN ID是否匹配,
        不如不匹配后面的事件都不用做了
        */
        if ( pNwkDesc->panId != zgConfigPANID )
          continue;
      }
      
     /*
      // The extended PanID used in ZDO layer for rejoin.
      uint8 ZDO_UseExtendedPANID[Z_EXTADDR_LEN];
      重新加入时,才会在事件处理函数去设置数组ZDO_UseExtendedPANID的值
      nwk_ExtPANIDValid为底层方法,初值加入这个方法应该返回的false
     */
      
      if ( nwk_ExtPANIDValid( ZDO_UseExtendedPANID) == true ) 
      {
        // If the extended Pan ID is commissioned to a non zero value
        // Only join the Pan that has match EPID
        if ( osal_ExtAddrEqual( ZDO_UseExtendedPANID, pNwkDesc->extendedPANID) == false )
          continue;
        
      }


        // check that network is allowing joining
        if ( ZSTACK_ROUTER_BUILD )
        {
          if ( stackProfilePro == FALSE )
          {
           /* 
            每一个网络的容量是有限制的,
            pNwkDesc->routerCapacity 指本网络还允许添加多少个路由器,
            pNwkDesc->deviceCapacity 指本网络还允许添加多个终端设备。
            byte routerCapacity;
            byte deviceCapacity;
            */
            if ( !pNwkDesc->routerCapacity )
            {
              continue;
            }
          }
          else
          {
            if ( !pNwkDesc->deviceCapacity )
            {
              continue;
            }
          }
        }
        else if ( ZSTACK_END_DEVICE_BUILD )//device
        {
          if ( !pNwkDesc->deviceCapacity )
          {
            continue;
          }
        }

        // check version of zigbee protocol
        //检查发现网络的协议的版本是不是与本模块的协议版本一样
        if ( pNwkDesc->version != _NIB.nwkProtocolVersion )
          continue;

        // check version of stack profile
        //检查协议栈规范的ID
        if ( pNwkDesc->stackProfile != zgStackProfile  )
        {
           /*
             参考:http://blog.sina.com.cn/s/blog_69c29fb30101fka8.html
            #define NETWORK_SPECIFIC    0  //“特定网络”
            #define HOME_CONTROLS       1 //ZigBee协议栈规范的ID
            #define ZIGBEEPRO_PROFILE   2 //ZigBeePRO协议栈规范的ID
            #define GENERIC_STAR        3
            #define GENERIC_TREE        4
          */
          if ( ((zgStackProfile == HOME_CONTROLS) && (pNwkDesc->stackProfile == ZIGBEEPRO_PROFILE)) 
              || ((zgStackProfile == ZIGBEEPRO_PROFILE) && (pNwkDesc->stackProfile == HOME_CONTROLS))  )
            stackProfilePro = TRUE;
          
          if ( stackProfile == 0 )
          {
            continue;
          }
        }

      // check if beacon order is the right value..
      //  if ( pNwkDesc->beaconOrder < ZDO_CONFIG_MAX_BO )
      //    continue;

      // choose this pan for joining
      break;
    } 
    if (i < ResultCount)
    {
      selected = TRUE;
      break;
    }
   
    // break if selected or stack profile pro wasn't found
    if ( (selected == TRUE) || (stackProfilePro == FALSE) )
    {
      break;
    }
  }

  //内层的for循环遍历完了 i 才会等于 ResultCount
  //说明没有到可以加入的网络   
  if ( i == ResultCount )
  {
    msg.hdr.status = ZDO_FAIL;  // couldn't find appropriate PAN to join !
  }
  else //已经找到网络
  {
    msg.hdr.status = ZDO_SUCCESS;
    msg.panIdLSB = LO_UINT16( pNwkDesc->panId );
    msg.panIdMSB = HI_UINT16( pNwkDesc->panId );
    msg.logicalChannel = pNwkDesc->logicalChannel;
    msg.version = pNwkDesc->version;
    osal_cpyExtAddr( msg.extendedPANID, pNwkDesc->extendedPANID );
  }
  //发送消息到ZDO层,
  //请到ZDO任务事件处理函数里查看ZDO_NWK_DISC_CNF这一事件的处理方式。
  ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(ZDO_NetworkDiscoveryCfm_t), (uint8 *)&msg );

  return (ZSuccess);
}  // ZDO_NetworkDiscoveryConfirmCB


 

最终会进入ZDO任务事件处理函数中的ZDApp_ProcessOSALMsg方法:

void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
  // Data Confirmation message fields
  uint8 sentEP;       // This should always be 0
  uint8 sentStatus;
  afDataConfirm_t *afDataConfirm;
  uint8 tmp;

  switch ( msgPtr->event )
  {
    .....
    case ZDO_NWK_DISC_CNF:
      
      if (devState != DEV_NWK_DISC)
        break;
     
      
      if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
      {
	    //如果发现了设备,并且扫描的次数大于2 (NUM_DISC_ATTEMPTS)
        if ( (((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->hdr.status == ZDO_SUCCESS) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
        {
		
		  //如是是首次加入,这里会加入一个新的网络
          if ( devStartMode == MODE_JOIN )
          {
            devState = DEV_NWK_JOINING;
  
            ZDApp_NodeProfileSync((ZDO_NetworkDiscoveryCfm_t *)msgPtr);
   
             //申请加入父设备
            //向父设备发送Associate Request请求分配设备地址。
            //分配成功后,回调ZDO_JoinConfirmCB方法
            if ( NLME_JoinRequest( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->extendedPANID,
                 BUILD_UINT16( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdLSB, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdMSB ),
                 ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->logicalChannel,
                 ZDO_Config_Node_Descriptor.CapabilityFlags ) != ZSuccess )
            {
              
			  //延迟一小会,重新初始化网络 ;这个方法最终会执行设备扫描
              ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
                  + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
				  
            }
           
          }
		  
		  //如果是重新加入,注意这个网络一定是以前加入过
          else if ( devStartMode == MODE_REJOIN )
          {
            devState = DEV_NWK_REJOIN;

            // Before trying to do rejoin, check if the device has a valid short address
            // If not, generate a random short address for itself
			//在重新加入之前,检测设备的网络短地址是否合法
			//如果不合法,则随机生成一个网络短地址
            if ( _NIB.nwkDevAddress == INVALID_NODE_ADDR )
            {
              _NIB.nwkDevAddress = osal_rand();
              ZMacSetReq( ZMacShortAddress, (byte*)&_NIB.nwkDevAddress );
            }

			//ZG_SECURE_ENABLED是否可用
            if ( ZG_SECURE_ENABLED )
            {
              ZDApp_RestoreNwkKey();
            }
            
            // Check if the device has a valid PanID, if not, set it to the discovered Pan
			//检测当前网络的panid是否合法,如果不合法,则将扫描出来的padid设置给当前设备
            if ( _NIB.nwkPanId == INVALID_PAN_ID )
            {
              _NIB.nwkPanId = BUILD_UINT16( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdLSB, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdMSB );
              ZMacSetReq( ZMacPanId, (byte*)&(_NIB.nwkPanId) );
            }

            tmp = true;
			//如果tmp设置为true,Rx 的状态会一直ON,可能会影响功率
            ZMacSetReq( ZMacRxOnIdle, &tmp ); // Set receiver always on during rejoin 
			
			//发起重新连接的请求
			//这个函数底层会根据ZDO_UseExtendedPANID,会和之前保存的PANID做比较,确定是不是需要rejoin的那个。
            if ( NLME_ReJoinRequest( ZDO_UseExtendedPANID, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->logicalChannel) != ZSuccess )
            {
			  
			  //过一会再重新尝试
              ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
                  + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
            }
          }
  
          //暂时搞不明白啥意思
          if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
          {
            // The receiver is on, turn network layer polling off.
			//设置/改变网络检测速率,仅终端设备可用
            NLME_SetPollRate( 0 );
			//设置/改变队列检测速率,仅终端设备可用
            NLME_SetQueuedPollRate( 0 );
			//回复数据的速率??
            NLME_SetResponseRate( 0 );
          }
          else
          {
            if ( (ZG_SECURE_ENABLED) && (devStartMode == MODE_JOIN) )
            {
              ZDApp_SavedPollRate = zgPollRate;
              NLME_SetPollRate( zgRejoinPollRate );
            }
          }
        }
        else
        {
          if ( continueJoining )
          {
    #if defined ( MANAGED_SCAN )
            ZDApp_NetworkInit( MANAGEDSCAN_DELAY_BETWEEN_SCANS );
    #else
            zdoDiscCounter++;
            ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY
                  + ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) );
    #endif
          }
        }
      }
      break;
     
	  ......
	  
    default:
      if ( ZG_SECURE_ENABLED )
        ZDApp_ProcessSecMsg( msgPtr );
      break;
  }

}

本人也是刚接触ZigBee,以上只是个人理解,欢迎高手指点。



最后

以上就是听话翅膀为你收集整理的ZigBee ZDO_NetworkDiscoveryConfirmCB方法 及 ZDO_NWK_DISC_CNF事件源码分析的全部内容,希望文章能够帮你解决ZigBee ZDO_NetworkDiscoveryConfirmCB方法 及 ZDO_NWK_DISC_CNF事件源码分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部