一、網絡拓撲結構
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;
}
}