目的:根据64位长地址寻得短地址,协调器通过该短地址与设备进行单点通信
我现在除了协调器,所有的设备都是router,还没有enddevice。
方法1:在节点数比较少的情况下,router与coordinator都是直连的,中间没有经过其他的router跳转,因此可以在网关端直接使用
APSME_LookupNwkAddr函数,参考http://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]; uint8i = 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:全网络寻找短地址,参考https://www.deyisupport.com/question_answer/wireless_connectivity/zigbee/f/104/t/91221.aspx。我的做法是
//第一步 void GenericApp_Init( uint8 task_id ) {...// Register with the ZDO to receive Match Descriptor ResponseZDO_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 applicationZDO_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楼继续。。。。。。
Hu Jinfeng:
方法3:
我看到有uint8 AddrMgrExtAddrLookup( uint16 nwkAddr, uint8* extAddr )这个函数,但是网上资料太少,有无使用例子,以及寻址的局限?
方法4:
目前我用的方法是,设备在上电的时候发送自己的长短地址给协调器,协调器解析并存入NV,用到的时候再读取。实现如下,因为c语言不扎实,没用链表,用数组做的。。。
void tbox_UpdateNodeAddr(uint8 *buffer) {uint8Count = 0;Count = tbox_ReadNodeNum(ADDR_COUNT_NV);//no node addr existif( Count == 0){tbox_AddNodeAddr(ADDR_STORE_NV,buffer);tbox_UpdateNodeNum(ADDR_COUNT_NV,Count);}//already exist at least one addrelse{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 existfor(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 itosal_nv_write(nv_id+i,8,2,&addr_buf[SHORT_ADDR_INDEX]);break;}}if(i == num)return 0;//Not foundelsereturn 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 */int8rssi;/* 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;
Hu Jinfeng:
回复 Hu Jinfeng:
关于方法4中的问题,已经初步解决了。参考http://blog.csdn.net/tanqiuwei/article/details/8076925
应该看afIncomingMSGPacket_t结构体中的成员afAddrType_t srcAddr,再查找afAddrType_t ,进一步发现
typedef struct {union{uint16shortAddr;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;
James Chu:
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;
Hu Jinfeng:
回复 James Chu:
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.aspxit shows its limitations.
VV:
回复 Hu Jinfeng:
感谢分享!
chengzi chen:
回复 VV:
不错的总结,学习了。