ZigBee學習筆記十一 ~ 基於廣播和單播的星狀網絡的組建

一、網絡拓撲結構

ZigBee網絡支持星狀、樹(簇)狀、網狀三種網絡拓撲結構:

在星狀網絡中只允許協調器與終端設備通信,終端與終端之間不能直接通信,終端設備之間的通信需要通過協調器來進行轉發

樹狀網絡是由一個或者多個星狀網絡構成的,終端設備可以選擇加入協調器或者路由器,設備只能選擇與自己的父節點或者子節點進行直接通信,如果要越級通信,需要依靠樹狀的節點組織進行一個轉發

網狀網絡,不管是子節點還是父節點都可以進行直接通信

二、功能需求

協調器週期性的以廣播的形式向終端節點發送數據“I am coordinator\n”

加入其網絡的終端節點都會收到數據,終端節點分別單播給協調器“I am endpoint device 1 or 2\n”

三、實現過程

1、複製一份樣板工程並且重命名

2、添加串口相關代碼

3、在SampleApp_Init()裏將SampleApp_Flash_DstAddr設置爲單播模式,且地址設置爲0x0000,此地址是協調器的地址

4、當網絡狀態發生改變,觸發SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,當檢測到這個事件時,首先判斷設備的邏輯類型
(1):如果是協調器則執行 SampleApp_SendPeriodicMessage();
(2):如果是終端則執行SampleApp_SendFlashMessage();

四、具體代碼實現

1、首先我們還是在SampleApp.c文件添加我們要用到的庫函數

#include "mt_uart.h"
#include "string.h"

2、然後進入串口初始化,配置波特率爲115200並關閉流控狀態

void MT_UartInit ()
{
  halUARTCfg_t uartConfig;

  /* Initialize APP ID */
  App_TaskID = 0;

  /* UART Configuration */
  uartConfig.configured           = TRUE;
  uartConfig.baudRate             = MT_UART_DEFAULT_BAUDRATE;    //這裏GOTO進去
  uartConfig.flowControl          = MT_UART_DEFAULT_OVERFLOW;

我們找到MT_UART_DEFAULT_BAUDRATE並GOTO進去,進行流控的關閉和波特率的設置

#if !defined( MT_UART_DEFAULT_OVERFLOW )
  #define MT_UART_DEFAULT_OVERFLOW       FALSE
#endif

#if !defined MT_UART_DEFAULT_BAUDRATE
#define MT_UART_DEFAULT_BAUDRATE         HAL_UART_BR_115200
#endif

3、接着我們打印一句話,在HAL層的hal_uart.h文件中,找到hal_uartwrite,打印一句話

*/
extern uint16 HalUARTRead ( uint8 port, uint8 *pBuffer, uint16 length );

/*
 * Write a buff to the uart *
 */
extern uint16 HalUARTWrite ( uint8 port, uint8 *pBuffer, uint16 length );  //找到這句話,複製粘貼到SampleAPP.c中,進行打印

/*
 * Write a buffer to the UART
 */
extern uint8 HalUARTIoctl ( uint8 port, uint8 cmd, halUARTIoctl_t *pIoctl );
HalUARTWrite ( 0,"uart0 is ok\n",strlen("uart0 is ok\n") );

4、給兩個地址結構體進行賦值

//這裏是協調器給終端發送的設置
// Setup for the periodic message's destination address
  // Broadcast to everyone   這裏是用來給協調器
  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;  //設置爲廣播模式
  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;			//以及廣播地址
//這裏是終端給協調器發送的,以單播的方式
//單播設置流程  go to 進入(SampleApp_Flash_DstAddr),再go to進入(afAddrType_t)
 // Setup for the flash command's destination address - Group 1
  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Flash_DstAddr.addr.shortAddr = 0x0000;  //協調器地址爲 0x0000

單播設置流程一 go to 進入(SampleApp_Flash_DstAddr),再go to進入(afAddrType_t)
二 直接go to進入afAddrMode_t結構體

//找到此結構體,然後goto(afAddrMode_t),就會指向我們的afAddrMode_t;這個結構體
typedef struct
{
  union
  {
    uint16      shortAddr;
    ZLongAddr_t extAddr;
  } addr;
  afAddrMode_t addrMode;
  byte endPoint;
  uint16 panId;  // used for the INTER_PAN feature
} afAddrType_t;

typedef enum
{
  afAddrNotPresent = AddrNotPresent,
  afAddr16Bit      = Addr16Bit,    //這個就表示我們的單播
  afAddr64Bit      = Addr64Bit,
  afAddrGroup      = AddrGroup,
  afAddrBroadcast  = AddrBroadcast
} afAddrMode_t;

5、下面進入uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )函數,進行事件的輪詢 在事件輪詢中,對於協調器和終端,我們要進行不同操作,因此必然要對協調器與終端進行識別

//協調器終端識別函數
if ( readCoordinatorJumper() )
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
  else
    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;  //go to 進ZG_DEVICETYPE_ROUTER,可以選取找到終端標識 ZG_DEVICETYPE_ENDDEVICE

然後我們根據協調器和終端,調用不同的發送函數

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  // Intentionally unreferenced parameter

  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        // Received when a key is pressed
        case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;

        // Received when a messages is received (OTA) for this endpoint
        case AF_INCOMING_MSG_CMD:
          SampleApp_MessageMSGCB( MSGpkt );
          break;

        // Received whenever the device changes state in the network
        case ZDO_STATE_CHANGE:
          SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (SampleApp_NwkState == DEV_ZB_COORD)
              || (SampleApp_NwkState == DEV_ROUTER)
              || (SampleApp_NwkState == DEV_END_DEVICE) )
          {
            // Start sending the periodic message in a regular interval.
            osal_start_timerEx( SampleApp_TaskID,
                              SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
                              SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
          }
          else
          {
            // Device is no longer in the network
          }
          break;

        default:
          break;
      }

      // Release the memory
      osal_msg_deallocate( (uint8 *)MSGpkt );

      // Next - if one is available
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

  // Send a message out - This event is generated by a timer
  //  (setup in SampleApp_Init()).
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
  {
    
    if(zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR)
    // Send the periodic message
    SampleApp_SendPeriodicMessage();  //協調器發送數據
    
    else if(zgDeviceLogicalType = ZG_DEVICETYPE_ENDDEVICE)  //這裏的ZG_DEVICETYPE_ENDDEVICE,go to 進去後包含路由器等的宏定義
     SampleApp_SendFlashMessage( 0x0000 );  //終端發送數據
     

    // Setup to send message again in normal period (+ a little jitter)
    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
        (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }

  // Discard unknown events
  return 0;
}

6、事件輪詢,然後就要發送數據 我們先來看協調器調用的發送函數

void SampleApp_SendPeriodicMessage( void )
{
  uint8 *buff = "I am coordinator decive\n";  //先用一個指針
  if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_PERIODIC_CLUSTERID,
                       strlen(buff),//長度
                       buff,  //實際數據
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
    // Error occurred in request to send.
  }
}

然後看一下終端的

void SampleApp_SendFlashMessage( uint16 flashTime )
{
  uint8 *buffer = "I am endpoint device 1\n";
  

  if ( AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_FLASH_CLUSTERID,
                       strlen(buffer),
                       buffer,
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
    // Error occurred in request to send.
  }
}

7、發送完數據,就要對數據進行處理,返回事件輪詢,對新的無線消息進行處理

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  uint16 flashTime;

  switch ( pkt->clusterId )
  {
    case SAMPLEAPP_PERIODIC_CLUSTERID:  //終端收到的命令號
    HalUARTWrite ( 0,pkt-cmd.data,pkt-cmd.DataLength );
      break;

    case SAMPLEAPP_FLASH_CLUSTERID:  //協調器收到的命令號
      HalUARTWrite ( 0,pkt-cmd.data,pkt-cmd.DataLength );
      break;
  }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章