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.

zstack协调器管理设备长短地址的一点小结和疑问

Other Parts Discussed in Thread: Z-STACK

目的:根据64位长地址寻得短地址,协调器通过该短地址与设备进行单点通信

我现在除了协调器,所有的设备都是router,还没有enddevice。

方法1:在节点数比较少的情况下,router与coordinator都是直连的,中间没有经过其他的router跳转,因此可以在网关端直接使用

APSME_LookupNwkAddr函数,参考blog.chinaunix.net/uid-20788636-id-1841417.html。需要注意长地址要翻转一下,代码很简单就。但是正如这个帖子所说,该函数只能找到子节点短地址,孙子节点就找不到。所以在设备增多的时候,就没法获取一些节点的地址了。
			uint16	destNWKaddr;
			uint8 	revdestIEEEaddr[ZIGBEE_DEVID_LEN];
			uint8	destIEEEaddr[ZIGBEE_DEVID_LEN];
			uint8 	len = SerialData_Buf[UART_LEN_OFFSET];
			uint8   i = 0;

			osal_memcpy(destIEEEaddr,SerialData_Buf+4,ZIGBEE_DEVID_LEN);
			osal_revmemcpy(revdestIEEEaddr,destIEEEaddr,ZIGBEE_DEVID_LEN);
			APSME_LookupNwkAddr(revdestIEEEaddr,&destNWKaddr) ;
			
			GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
			GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT;
			GenericApp_DstAddr.addr.shortAddr = destNWKaddr;	

方法2:全网络寻找短地址,参考www.deyisupport.com/.../91221.aspx。我的做法是

//第一步
void GenericApp_Init( uint8 task_id )
{
  ...
  // Register with  the ZDO to receive Match Descriptor Response
  ZDO_RegisterForZDOMsg( GenericApp_TaskID,NWK_addr_rsp );
  ...
}
//第二步
uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )
{
  ...
  switch ( MSGpkt->hdr.event )
  {
    case ZDO_CB_MSG:
      GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t*)MSGpkt );
      break;
  }
  ...
}
//第三步
void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
  switch ( inMsg->clusterID)
  { 
    case NWK_addr_rsp:
      //Send find device callback to application
      ZDO_NwkIEEEAddrResp_t *pNwkAddrRsp = ZDO_ParseAddrRsp( inMsg );
      if( pNwkAddrRsp )
      {
        if( pNwkAddrRsp->status == ZSuccess)
        {
          uint8 test[2];
          Map_NwkAdd = pNwkAddrRsp->nwkAddr;
          test[0] = (Map_NwkAdd&0xFF00)>>8;
          test[1] = Map_NwkAdd&0x00FF;
	  HalUARTWrite(0,test,2);
				
        }
      }
      break;
  }
}
//第4步
//同样在GenericApp_ProcessEvent中添加了一个轮询事件,用来处理串口来的消息,最后就是调用ZDP_NwkAddrReq来获取目标短地址
ZDP_NwkAddrReq(destIEEEaddr,ZDP_ADDR_REQTYPE_SINGLE,0,0);
可是问题是我在第三步设置断点,程序根本跑不到这里,这是为什么呢?
其实全网广播获取并不是个好方法,对网络负载大。我已经放弃使用了,但还是想知道实现的具体步骤。
2楼继续。。。。。。
  • 方法3:

    我看到有uint8  AddrMgrExtAddrLookup( uint16 nwkAddr, uint8* extAddr )这个函数,但是网上资料太少,有无使用例子,以及寻址的局限?

    方法4:

    目前我用的方法是,设备在上电的时候发送自己的长短地址给协调器,协调器解析并存入NV,用到的时候再读取。实现如下,因为c语言不扎实,没用链表,用数组做的。。。

    void tbox_UpdateNodeAddr(uint8 *buffer)
    {
    	uint8 	Count = 0;
    	Count = tbox_ReadNodeNum(ADDR_COUNT_NV);
    
    	//no node addr exist
    	if( Count == 0)
    	{
    		tbox_AddNodeAddr(ADDR_STORE_NV,buffer);
    		tbox_UpdateNodeNum(ADDR_COUNT_NV,Count);
    	}
    
    	//already exist at least one addr
    	else
    	{
    		if( !tbox_CheckNodeAddr(ADDR_STORE_NV,Count,buffer) )	//Not found
    		{
    			tbox_AddNodeAddr(ADDR_STORE_NV+Count,buffer);
    			tbox_UpdateNodeNum(ADDR_COUNT_NV,Count);			//Add addr first then update num
    		}
    	}
    
    }
    
    void tbox_UpdateNodeNum(uint16 nv_id,uint8 num)
    {
    	num++;
    	osal_nv_item_init(nv_id,1,NULL);
    	osal_nv_write(nv_id,0,1,&num);
    }
    
    void tbox_AddNodeAddr(uint16 nv_id,uint8 * addr_buf)
    {
    	osal_nv_item_init(nv_id,ADDR_STORE_LEN,NULL);
    	osal_nv_write(nv_id,0,8,&addr_buf[LONG_ADDR_INDEX]);
    	osal_nv_write(nv_id,8,2,&addr_buf[SHORT_ADDR_INDEX]);
    }
    
    uint8 tbox_CheckNodeAddr(uint16 nv_id,uint8 num,uint8 *addr_buf)
    {
    	uint8 i = 0;
    	uint8 long_addr[8];
    	uint8 short_addr[2];
    	
    	//check if the addr is already exist
    	for(i=0; i<num; i++)
    	{
    		osal_nv_item_init(nv_id+i,ADDR_STORE_LEN,NULL);
    		osal_nv_read(nv_id+i,0,8,&long_addr);
    		
    		if( osal_memcmp(&addr_buf[LONG_ADDR_INDEX],&long_addr,8) )			//if long addr is already exist
    		{
    			osal_nv_read(nv_id+i,8,2,&short_addr);
    			
    			if( !osal_memcmp(&addr_buf[LONG_ADDR_INDEX],&short_addr,2) )		//if short addr has changed, update it
    				osal_nv_write(nv_id+i,8,2,&addr_buf[SHORT_ADDR_INDEX]);
    
    			break;
    		}
    	}
    
    	if(i == num)
    		return 0;		//Not found
    	else 
    		return i;
    }
    
    uint8 tbox_ReadNodeNum(uint16 nv_id)
    {
    	uint8 num = 0;
    	osal_nv_item_init(nv_id,1,NULL);
    	osal_nv_read(nv_id,0,1,&num);
    
    	return num;
    }
    uint16 tbox_FindNodeShortAddr(uint16 nv_id,uint8 *longaddr)
    {
    	uint16 shortaddr = 0;
    	uint8 shortbuf[2];
    	
    	uint8 j = 0;
    	uint8 nodenum = 0;
    	uint8 nv_long_addr[8];
    
    	nodenum = tbox_ReadNodeNum(ADDR_COUNT_NV);
    	for(j=0; j<nodenum;j++)
    	{
    		osal_nv_item_init(nv_id+j,ADDR_STORE_LEN,NULL);
    		osal_nv_read(nv_id+j,0,8,nv_long_addr);
    		if( osal_memcmp(longaddr,nv_long_addr,8) )
    		{
    			osal_nv_read(nv_id+j,8,2,shortbuf);
    			shortaddr = shortbuf[1];	
    			shortaddr |= shortbuf[0]<<8;
    			return shortaddr;		//Find success
    		}
    	
    	}
    	return 0;						//Not Found
    }

    ①收到设备消息的时候,在tbox_MessageMSGCB里,调用tbox_UpdateNodeAddr(buffer);

    ②通信的时候,设置好目标短地址就好GenericApp_DstAddr.addr.shortAddr = tbox_FindNodeShortAddr(ADDR_STORE_NV,destIEEEaddr);

    虽然能用,但是还是有很大的缺陷。我希望是在设备正常传数据的时候,比如温度传感器发送温度消息的时候,能同时获取该设备的短地址,不需要额外的消息占用网络资源。无线数据包是否会携带设备自身的短地址,若是又该在哪里读取?我看到无线数据包结构体afIncomingMSGPacket_t里有个uint16 macDestAddr,不过好像不是短地址,我读出来一直是0。

    typedef struct
    {
      osal_event_hdr_t hdr;     /* OSAL Message header */
      uint16 groupId;           /* Message's group ID - 0 if not set */
      uint16 clusterId;         /* Message's cluster ID */
      afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
                                   it's an InterPAN message */
      uint16 macDestAddr;       /* MAC header destination short address */
      uint8 endPoint;           /* destination endpoint */
      uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
      uint8 LinkQuality;        /* The link quality of the received data frame */
      uint8 correlation;        /* The raw correlation value of the received data frame */
      int8  rssi;               /* The received RF power in units dBm */
      uint8 SecurityUse;        /* deprecated */
      uint32 timestamp;         /* receipt timestamp from MAC */
      uint8 nwkSeqNum;          /* network header frame sequence number */
      afMSGCommandFormat_t cmd; /* Application Data */
    } afIncomingMSGPacket_t;
  • 关于方法4中的问题,已经初步解决了。参考http://blog.csdn.net/tanqiuwei/article/details/8076925

    应该看afIncomingMSGPacket_t结构体中的成员afAddrType_t  srcAddr,再查找afAddrType_t ,进一步发现

    typedef struct
    {
      union
      {
        uint16      shortAddr;
        ZLongAddr_t extAddr;
      } addr;
      afAddrMode_t addrMode;
      uint8 endPoint;
      uint16 panId;  // used for the INTER_PAN feature
    } afAddrType_t;

    可见数据包中是包含节点自身短地址的。只要在MessageMSGCB函数中设个变量直接赋值即可uint 16 short_addr = pkt->srcAddr.addr.shortAddr;

  • As I know,  you can use IEEE address to do unicast in current Z-Stack.

    Why do you still translate IEEE address to short address by yourself in method 1? Z-Stack will do this for you.

    Am I wrong?

    typedef enum
    {
    afAddrNotPresent = AddrNotPresent,
    afAddr16Bit = Addr16Bit,
    afAddr64Bit = Addr64Bit,
    afAddrGroup = AddrGroup,
    afAddrBroadcast = AddrBroadcast
    } afAddrMode_t;

  • Eh..I didn't notice this way as the demo uses short addr to communicate.....I tried just now and it did work. Here is the code if someone needs.

    //notice to revert the addr

    GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr64Bit;
    osal_revmemcpy(GenericApp_DstAddr.addr.extAddr,destIEEEaddr,8);
    
    
    But in another post: 
    http://www.deyisupport.com/question_answer/wireless_connectivity/zigbee/f/104/t/69052.aspx
    it shows its limitations.
  • 感谢分享!

  • 不错的总结,学习了。