获取网络拓扑

1、实验内容:PC端串口调试助手向协调器发送命名“topology”,协调器接受到命令后,将网络拓扑信息发送到PC机串口调试助手上。

2、知识点:在1-11 实验9 网络管理实验1 获取自身和父节点的网络地址、MAC地址 中,我们知道每个节点都获取自身和父节点的网络地址,然后发送到协调器节点,然后再通过串口写到串口的调试助手上。这样就可以获得整个网络的拓扑结构啦。

3、程序设计

     协调器程序设计

//NewCoordinator.h文件中添加如下结构体。
typedef struct rftx{
   uint8 type[3];
   uint8 myNWK[4];
   uint8 pNWK[4];
  }RFTX;

NewCoordinator.c文件如下:

#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "NewCoordinator.h"
//#include "GenericApp.h"
#include "DebugTrace.h"

#if !defined( WIN32 )
  #include "OnBoard.h"
#endif

/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"

/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */
/*********************************************************************
 * TYPEDEFS
 */
/*********************************************************************
 * GLOBAL VARIABLES
 */
// This list should be filled with Application specific Cluster IDs.
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{
  GENERICAPP_CLUSTERID
};

const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{
  GENERICAPP_ENDPOINT,              //  int Endpoint;
  GENERICAPP_PROFID,                //  uint16 AppProfId[2];
  GENERICAPP_DEVICEID,              //  uint16 AppDeviceId[2];
  GENERICAPP_DEVICE_VERSION,        //  int   AppDevVer:4;
  GENERICAPP_FLAGS,                 //  int   AppFlags:4;
  //下面的初始化 二选一!!!!!!!!
  GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
  (cId_t *)GenericApp_ClusterList,  //  byte *pAppInClusterList;
 // GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
 // (cId_t *)GenericApp_ClusterList   //  byte *pAppInClusterList;
 0,
 (cId_t *)NULL
};

// This is the Endpoint/Interface description.  It is defined here, but
// filled-in in GenericApp_Init().  Another way to go would be to fill
// in the structure here and make it a "const" (in code space).  The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t GenericApp_epDesc;
/*********************************************************************
 * EXTERNAL VARIABLES
 */
/*********************************************************************
 * EXTERNAL FUNCTIONS
 */
/*********************************************************************
 * LOCAL VARIABLES
 */
byte GenericApp_TaskID;   // Task ID for internal task/event processing
                          // This variable will be received when
                          // GenericApp_Init() is called.
devStates_t GenericApp_NwkState;


byte GenericApp_TransID;  // This is the unique message ID (counter)

//afAddrType_t GenericApp_DstAddr;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
//void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
//void GenericApp_HandleKeys( byte shift, byte keys );
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );//处理事件
//void GenericApp_SendTheMessage( void );//发送数据

static void rxCB(uint8 port,uint8 envent);

/*********************************************************************
 * NETWORK LAYER CALLBACKS
 */

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      GenericApp_Init
 *
 * @brief   Initialization function for the Generic App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void GenericApp_Init( byte task_id )
{
  GenericApp_TaskID = task_id;
 // GenericApp_NwkState = DEV_INIT;
  GenericApp_TransID = 0;

  // Device hardware initialization can be added here or in main() (Zmain.c).
  // If the hardware is application specific - add it here.
  // If the hardware is other parts of the device add it in main().

 // GenericApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
 // GenericApp_DstAddr.endPoint = 0;
 // GenericApp_DstAddr.addr.shortAddr = 0;

  // Fill out the endpoint description.
  GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;
  GenericApp_epDesc.task_id = &GenericApp_TaskID;
  GenericApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
  GenericApp_epDesc.latencyReq = noLatencyReqs;

  // Register the endpoint description with the AF
  afRegister( &GenericApp_epDesc );
  
  //串口的设置,并打开串口
  halUARTCfg_t uartConfig;
  uartConfig.configured =TRUE;
  uartConfig.baudRate   =HAL_UART_BR_115200;
  uartConfig.flowControl=FALSE;
 // uartConfig.callBackFunc=NULL;//???????????????????????????????????
  uartConfig.callBackFunc=rxCB;
  HalUARTOpen(0,&uartConfig);   //打开串口
}

/*********************************************************************
 * @fn      GenericApp_ProcessEvent
 *
 * @brief   Generic Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The OSAL assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  none
 */
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
   HalLedBlink(HAL_LED_1,0,50,500);
  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
         case AF_INCOMING_MSG_CMD:  //天线接收到数据
          HalLedBlink(HAL_LED_2,0,50,500);
          GenericApp_MessageMSGCB( MSGpkt );   //接收数据并把数据发送到UART
         break;         
        default:
          break;
      }
      // Release the memory
      osal_msg_deallocate( (uint8 *)MSGpkt );
      // Next
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    }
    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }
  return 0;
}

/*********************************************************************
 * LOCAL FUNCTIONS
 */
/*********************************************************************
 * @fn      GenericApp_MessageMSGCB
 *
 * @brief   Data message processor callback.  This function processes
 *          any incoming data - probably from other devices.  So, based
 *          on cluster ID, perform the intended action.
 *
 * @param   none
 *
 * @return  none
 */
  RFTX rftx;

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  switch ( pkt->clusterId )
  {
    case GENERICAPP_CLUSTERID:
    osal_memcpy(&rftx,pkt->cmd.Data,sizeof(rftx));
    //不使用rxCB时,放在这里,尽然只输出一行结果
 /* uint8 changeline[2]={0x0A,0x0D};
  HalUARTWrite(0,"Type: ",osal_strlen("Type:"));
  HalUARTWrite(0,rftx.type,3);
  HalUARTWrite(0,"  NWK:",osal_strlen("  NWK:")); //刚才用了sizeof("  NWK:")
  HalUARTWrite(0,rftx.myNWK,sizeof(rftx.myNWK));         刚才用了sizeof(rftx.myNWk),是不能正确显示的
  HalUARTWrite(0,"  pNWK:",osal_strlen("  pNWK:"));
  HalUARTWrite(0,rftx.pNWK,sizeof(rftx.pNWK));  
  HalUARTWrite(0,changeline,2);*/      
      break;
  }
}

static void rxCB(uint8 port,uint8 envent)
{
  uint8 changeline[2]={0x0A,0x0D};
  uint8 buf[8];
  HalUARTRead(0,buf,8);
  if(osal_memcmp(buf,"topology",8))
  {
  HalUARTWrite(0,"Type: ",osal_strlen("Type:"));
  HalUARTWrite(0,rftx.type,3);
  HalUARTWrite(0,"  NWK:",osal_strlen("  NWK:")); //刚才用了sizeof("  NWK:")
  HalUARTWrite(0,rftx.myNWK,sizeof(rftx.myNWK));         刚才用了sizeof(rftx.myNWk),是不能正确显示的
  HalUARTWrite(0,"  pNWK:",osal_strlen("  pNWK:"));
  HalUARTWrite(0,rftx.pNWK,sizeof(rftx.pNWK));
  HalUARTWrite(0,changeline,2); 
  }
}

路由器节点或终端节点(共用的Enddevice.c文件)

#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"

#include "NewCoordinator.h"
//#include "GenericApp.h"
#include "DebugTrace.h"

#if !defined( WIN32 )
  #include "OnBoard.h"
#endif

/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
#define SEND_DATA_EVENT 0x01
/*********************************************************************
 * MACROS
 */
/*********************************************************************
 * CONSTANTS
 */
/*********************************************************************
 * TYPEDEFS
 */
/*********************************************************************
 * GLOBAL VARIABLES
 */
// This list should be filled with Application specific Cluster IDs.
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{
  GENERICAPP_CLUSTERID
};

const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{
  GENERICAPP_ENDPOINT,              //  int Endpoint;
  GENERICAPP_PROFID,                //  uint16 AppProfId[2];
  GENERICAPP_DEVICEID,              //  uint16 AppDeviceId[2];
  GENERICAPP_DEVICE_VERSION,        //  int   AppDevVer:4;
  GENERICAPP_FLAGS,                 //  int   AppFlags:4;
  //下面是二选一
  0,
  (cId_t*)0,
  //GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
 // (cId_t *)GenericApp_ClusterList,  //  byte *pAppInClusterList;
  GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
  (cId_t *)GenericApp_ClusterList   //  byte *pAppInClusterList;
};

// This is the Endpoint/Interface description.  It is defined here, but
// filled-in in GenericApp_Init().  Another way to go would be to fill
// in the structure here and make it a "const" (in code space).  The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t GenericApp_epDesc;
/*********************************************************************
 * EXTERNAL VARIABLES
 */
/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */
byte GenericApp_TaskID;   // Task ID for internal task/event processing
                          // This variable will be received when
                          // GenericApp_Init() is called.
devStates_t GenericApp_NwkState;

byte GenericApp_TransID;  // This is the unique message ID (counter)

//afAddrType_t GenericApp_DstAddr;  //???????????????

/*********************************************************************
 * LOCAL FUNCTIONS
 */
//void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
//void GenericApp_HandleKeys( byte shift, byte keys );
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void GenericApp_SendTheMessage( void );

void To_string(uint8 *dest,char* src,uint8 length);//二进制书转化为十六进制数  
//static void rxCB(uint8 port,uint8 envent);

/*********************************************************************
 * NETWORK LAYER CALLBACKS
 */
/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/*********************************************************************
 * @fn      GenericApp_Init
 *
 * @brief   Initialization function for the Generic App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void GenericApp_Init( byte task_id )
{
  GenericApp_TaskID = task_id;
  GenericApp_NwkState = DEV_INIT;
  GenericApp_TransID = 0;
  // Fill out the endpoint description.
  GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;
  GenericApp_epDesc.task_id = &GenericApp_TaskID;
  GenericApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
  GenericApp_epDesc.latencyReq = noLatencyReqs;
  // Register the endpoint description with the AF
  afRegister( &GenericApp_epDesc );  
  //串口的设置,并打开串口
  halUARTCfg_t uartConfig;
  uartConfig.configured =TRUE;
  uartConfig.baudRate   =HAL_UART_BR_115200;
  uartConfig.flowControl=FALSE;
  uartConfig.callBackFunc=NULL;//???????????????????????????????????
//  uartConfig.callBackFunc=rxCB;
  HalUARTOpen(0,&uartConfig);   //打开串口

  //这里就不用添加事件了!!!倒回去看什么时候要添加事件       ???????
  // Register for all key events - This app will handle all key events
  //RegisterForKeys( GenericApp_TaskID );
}


/*********************************************************************
 * @fn      GenericApp_ProcessEvent
 *
 * @brief   Generic Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The OSAL assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  none
 */
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_ROUTER)
              || (GenericApp_NwkState == DEV_END_DEVICE) )
          {
            osal_set_event(GenericApp_TaskID,SEND_DATA_EVENT);
          }
          break;
        default:
          break;
      }
      // Release the memory
      osal_msg_deallocate( (uint8 *)MSGpkt );
      // Next
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    }
    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }
   if ( events &  SEND_DATA_EVENT )
  {
    //这里添加获取自己和父节点的NWK地址
    HalLedBlink(HAL_LED_2,0,50,500);
    // Send "the" message
    GenericApp_SendTheMessage();  //AF发送
         osal_start_timerEx( GenericApp_TaskID,
                        SEND_DATA_EVENT,    //事件
                           GENERICAPP_SEND_MSG_TIMEOUT );//定时时间
    return (events ^ SEND_DATA_EVENT);
  }
  // Discard unknown events
  return 0;
}
/*********************************************************************
 * @fn      GenericApp_SendTheMessage
 *
 * @brief   Send "the" message.
 *
 * @param   none
 *
 * @return  none
 */
RFTX rftx;
void GenericApp_SendTheMessage( void )//AF发送
{
uint16 nwk;
  if (GenericApp_NwkState == DEV_ROUTER)
        osal_memcpy(rftx.type,"ROU",3);
  else if(GenericApp_NwkState == DEV_END_DEVICE) 
        osal_memcpy(rftx.type,"DEV",3);
  nwk=NLME_GetShortAddr();
  To_string(rftx.myNWK,(uint8*)&nwk,2);
  nwk=NLME_GetCoordShortAddr();
  To_string(rftx.pNWK,(uint8*)&nwk,2);  
  //下面是串口输出,尽然不管用,不是没有配置串口和打开串口的原因。到底是哪里出了问题呢???
  uint8 changeline[2]={0x0A,0x0D};
  HalUARTWrite(0,"Type: ",osal_strlen("Type:"));
  HalUARTWrite(0,rftx.type,3);
  HalUARTWrite(0,"  NWK:",osal_strlen("  NWK:")); //刚才用了sizeof("  NWK:")
  HalUARTWrite(0,rftx.myNWK,sizeof(rftx.myNWK));         刚才用了sizeof(rftx.myNWk),是不能正确显示的
  HalUARTWrite(0,"  pNWK:",osal_strlen("  pNWK:"));
  HalUARTWrite(0,rftx.pNWK,sizeof(rftx.pNWK));
  HalUARTWrite(0,changeline,2);   
  afAddrType_t my_DstAddr;                       //
  my_DstAddr.addrMode=(afAddrMode_t)Addr16Bit;
  my_DstAddr.endPoint=GENERICAPP_ENDPOINT;
  my_DstAddr.addr.shortAddr=0x0000;
    if ( AF_DataRequest(&my_DstAddr, &GenericApp_epDesc,
                       GENERICAPP_CLUSTERID,
                     11,//  sizeof(rftx),
                        (uint8 *)&rftx,
                       &GenericApp_TransID,
                       AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
      HalLedBlink(HAL_LED_1,0,50,500);
  }
}
/*static void rxCB(uint8 port,uint8 envent)
{      
  uint8 changeline[2]={0x0A,0x0D};
  HalUARTWrite(0,"Type: ",osal_strlen("Type:"));
  HalUARTWrite(0,rftx.type,3);
  HalUARTWrite(0,"  NWK:",osal_strlen("  NWK:")); //刚才用了sizeof("  NWK:")
  HalUARTWrite(0,rftx.myNWK,sizeof(rftx.myNWK));         刚才用了sizeof(rftx.myNWk),是不能正确显示的
  HalUARTWrite(0,"  pNWK:",osal_strlen("  pNWK:"));
  HalUARTWrite(0,rftx.pNWK,sizeof(rftx.pNWK));
  HalUARTWrite(0,changeline,2); 
}*/

void To_string(uint8 *dest,char* src,uint8 length)//二进制书转化为十六进制数  
{  
  uint8* xad;  
  uint8 i=0;  
  uint8 ch;  
  xad=src+length-1;  
  for(i=0;i<length;i++,xad--)  
  {  
   ch=(*xad>>4)&0x0F;  //除以十六  
   dest[i<<1]=ch+((ch<10)?'0':'7');  
   ch=*xad&0x0F;  
   dest[(i<<1)+1]=ch+((ch<10)?'0':'7');  
  }  
}

4、实验结果(只有两块板子,一个做协调器,另一个只能做路由节点或终端节点,所以看不到拓扑的结果)

将网络拓扑结构导入python模型 一键获取网络拓扑结构_#include


将网络拓扑结构导入python模型 一键获取网络拓扑结构_#include_02


5、注意:(因为下面一条语句,又花我一个下午,搞残了哥!!!)

osal_strlen("  NWK:")用了sizeof("  NWK:")