目录
要获取网络的拓扑信息,需要知道每个网络节点的网路地址以及父节点的网路地址。可考虑如下思路来获取拓扑信息:节点上电后,将自身的网络地址以及父节点的网络地址发送给协调器,通过串口给协调器发送命令,协调器收到命令后,将各个节点的网络地址以及父节点的网络地址发送给PC机
系统上电后,各个节点需要将自身设备类型,网络地址,父节点网络地址发送给协调器,设计一个数据结构,如下:
协调器编程:
//Coordinator.c
typedef struct RFTXBUF
{
uint8 type[3];
uint8 myNWK[4];
uint8 pNWK[4];
}RFTX;
该结构体用于存放节点对的信息:设备类型,网络地址,父节点网络地址
//Coordinator.c
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memcpy(&nodeinfo[nodenum++],pkt->cmd.Data,11);
break;
}
}
static void rxCB(uint8 port,uint8 event)
{
unsigned char changeline[2]={0x0A,0x0D};
uint8 buf[8];
uint8 uartbuf[16];
uint8 i=0;
HalUARTRead(0,buf,8);
if(osal_memcmp(buf,"topology",8))
{
for(i=0;i<3;i++)
{
HalUARTWrite(0,nodeinfo[i].type,3); //输出设备类型
HalUARTWrite(0," NWK: ",6);
HalUARTWrite(0,nodeinfo[i].myNWK,4); //输出网络地址
HalUARTWrite(0," pNWK: ",7);
HalUARTWrite(0,nodeinfo[i].pNWK,4); //输出父节点网络地址
HalUARTWrite(0,changeline,2);
}
}
}
串口回调函数,当串口缓冲区有数据时,会调用这个函数,读取串口缓冲区的数据,使用osal_memcmp()函数,判断是否收到“topology”
终端节点和路由器编程:
//Enddevice.c
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case ZDO_STATE_CHANGE:
GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);
if((GenericApp_NwkState == DEV_END_DEVICE)
|| (GenericApp_NwkState == DEV_ROUTER))
{
osal_set_event(GenericApp_TaskID,SEND_DATA_EVENT);
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt ); //释放内存
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
return (events ^ SYS_EVENT_MSG);
}
if(events & SEND_DATA_EVENT)
{
SendInfo();
return (events ^ SEND_DATA_EVENT);
}
return 0;
}
当成功加入网络后,设置SEND_DATA_EVENT事件,在该事件处理函数中,调用SendInfo()函数,向协调器发送设备信息
//Enddevice.c
void SendInfo( void )
{
RFTX rftx;
uint16 nwk;
if(GenericApp_NwkState == DEV_END_DEVICE) //判断是否为终端节点
{
osal_memcpy(rftx.type,"END",3);
}
if(GenericApp_NwkState == DEV_ROUTER) //判断是否是路由器
{
osal_memcpy(rftx.type,"ROU",3);
}
nwk = NLME_GetShortAddr();
To_string(rftx.myNWK,(uint8 *)&nwk,2);
nwk = NLME_GetCoordShortAddr();
To_string(rftx.pNWK,(uint8 *)&nwk,2);
afAddrType_t my_DstAddr;
my_DstAddr.addrMode= (afAddrMode_t)Addr16Bit;
my_DstAddr.endPoint= GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr= 0x0000;
AF_DataRequest( &my_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
11,
(uint8 *)&rftx,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) ;
}
void To_string(uint8 *dest,char *src,uint8 length)
{
uint8 *xad;
uint8 i=0;
uint8 ch;
xad = src + length-1;
for(i=0;i> 4) & 0x0F;
dest[i<<1] = ch + ((ch<10) ? '0' : '7');
ch = *xad & 0x0F;
dest[(i<<1) + 1] = ch + ((ch<10) ? '0' : '7');
}
}
如果设备类型是终端节点,则在设备类型字段填充“END”;如果设备类型是路由器,则在设备类型字段填充“RND”。使用NLME_GetCoordShortAddr()函数获得父节点网络地址。
测试:
打开串口调试助手,发送topology命令,此时会输出网络的拓扑信息
可见,网络中有一个路由器,网络地址为0x0001,还有两个终端节点,网络地址分别为0x796F,0x7970。网络拓扑如下: