Zigbee网络中进行数据通信主要有三种类型:单播、组播、广播。那这三种方式如何设置呢,在哪里设置呢,
一、 广播
当应用程序需要将数据包发送给网络的每一个设备时,使用这种模式。广播的短地址有三种
0xFFFF: 广播数据发送至所有设备,包括睡眠节点;
0xFFFD: 广播数据发送至正在睡眠的所有设备;
0xFFFC: 广播数据发送至所有协调器和路由器;
具体说明广播通信,假设终端发“0123456789”数据给协调器,当协调器收到数据后,通过串口发给电脑,电脑上的串口调试助手显示接收到的字符串,具体的流程如下图所示:左边为协调器的工作流程,右边为终端的工作流程,其中黑色阴影部分为SampleApp_Init函数完成的工作,橙色阴影部分为SampleApp_ProcessEvent函数完成的工作,蓝色阴影部分为SampleApp_MessageMSGCB和SampleApp_SendPeriodicMessage处理函数完成的工作,省略号表示其他代码。
1 应用初始化函数,即完成一些初始化工作,如果是协调器,则实现注册串口,填充端点描述符并注册端点描述符;如果是终端,则实现建立广播目的地址,填充端点描述符并注册端点描述符等。
void SampleApp_Init( uint8 task_id ) { ............................................................................. //注册串口 MT_UartInit(); //串口初始化 MT_UartRegisterTaskID(task_id); //注册串口任务 HalUARTWrite(0,"UartInit OK\n", sizeof("UartInit OK\n"));//提示信息 .............................................................................. //建立广播目的地址 SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//设置为广播模式 SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; //配置端点 SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF; //指定广播地址 //填充端点描述符 SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_epDesc.task_id = &SampleApp_TaskID; SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; SampleApp_epDesc.latencyReq = noLatencyReqs; // 注册端点描述符 afRegister( &SampleApp_epDesc ); .................................................................................. }
(2)任务处理函数,即处理应用事件函数。
首先当分别启动协调器和终端后,协调器实现组网和终端加入该网络,此后将分别触发系统事件SYS_EVENT_MSG中的网络状态改变ZDO_STATE_CHANGE事件。当网络状态改变后,令终端每隔5ms发送一次SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,即设置定时任务osal_start_timerEx。当时间到达后,将触发SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,在该事件中,终端发送广播信息 SampleApp_SendPeriodicMessage并重新设置定时任务osal_start_timerEx,这样周而复始,即终端每隔5ms周期性的发送事件。
其次,当终端发送SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件后,协调器将收到SYS_EVENT_MSG事件中的AF_INCOMING_MSG_CMD事件,这样协调器执行SampleApp_MessageMSGCB接收数据任务。
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; (void)task_id; // Intentionally unreferenced parameter if ( events & SYS_EVENT_MSG ) {//从信息列表中获取SampleApp_TaskID相关的信息 MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); while ( MSGpkt )//不为空,说明有信息 { switch ( MSGpkt->hdr.event ) { // Received when a key is pressed .............................................................. // 系统消息命令到来 case AF_INCOMING_MSG_CMD: SampleApp_MessageMSGCB( MSGpkt ); break; // 网络状态改变 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) ) { // 设置定时任务 osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT, SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT ); } ......................................................... } // 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); } // 触发定时任务 // (setup in SampleApp_Init()). if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) { // 发送广播信息 SampleApp_SendPeriodicMessage(); //重新设置定时任务 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); } ........................................................................... }
(3)接收消息函数
当协调器收到消息后,将通过判断协议号SAMPLEAPP_PERIODIC_CLUSTERID决定是否是由终端发送的周期性广播包,如果是,则通过串口发送到PC。
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) //接收数据 { uint16 flashTime; switch ( pkt->clusterId ) { case SAMPLEAPP_PERIODIC_CLUSTERID://判断协议镞类型,并发送串口数据 HalUARTWrite(0, "Rx:", 3); //提示信息 HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //输出接收到的数据 HalUARTWrite(0, "\n", 1); //回车换行 break; ..................................... } }
(4)发送广播函数
首先,函数是ZigBee协议的发送数据函数,其中参数1规定了数据的通信方式,即广播通信模式,通过短地址为0xFFFF(见SampleApp_Init函数);参考3定义了该广播数据的协议族号;参数4为发送数据的长度,参考5为发送的具体数据。
void SampleApp_SendPeriodicMessage( void ) { //发送广播数据 if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 1, (uint8*)&SampleAppPeriodicCounter, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } .............................................................. }
二、组播
(1)初始化函数配置
void SampleApp_Init( uint8 task_id ) { ............................// Setup for the flash command‘s destination address - Group 1 SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup; SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP; //组号1 //SampleApp_Flash_DstAddr.addr.shortAddr = 0x0002; //组号2 // Fill out the endpoint description. SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_epDesc.task_id = &SampleApp_TaskID; SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; SampleApp_epDesc.latencyReq = noLatencyReqs; // Register the endpoint description with the AF afRegister( &SampleApp_epDesc ); ................................// By default, all devices start out in Group 1 SampleApp_Group.ID = 0x0001; //SampleApp_Group.ID = 0x0002; osal_memcpy( SampleApp_Group.name, "Group 1", 7 ); aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group ); ............................... }
(2)任务处理函数设置
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 ) { // Send the periodic message SampleApp_SendPeriodicMessage(); // 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; }
(3)接收函数设置
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) { uint8 data; switch ( pkt->clusterId ) { ............................................. case SAMPLEAPP_FLASH_CLUSTERID: data = (uint8)pkt->cmd.Data[0]; if(data == 0) HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF); else HalLedSet(HAL_LED_2, HAL_LED_MODE_ON); break; }.............................................. }
(4)发送函数设置
void SampleApp_SendFlashMessage( uint16 flashTime ) { uint8 buffer[3]; buffer[0] = (uint8)(SampleAppFlashCounter++); buffer[1] = LO_UINT16( flashTime ); buffer[2] = HI_UINT16( flashTime ); if ( AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc, SAMPLEAPP_FLASH_CLUSTERID, 3, buffer, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { // Error occurred in request to send. } }
三、点播
(1)初始化函数配置
void SampleApp_Init( uint8 task_id ) { ..... SampleApp_P2P_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; //点播 SampleApp_P2P_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_P2P_DstAddr.addr.shortAddr = 0x0000; //发给协调器 // Fill out the endpoint description. SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_epDesc.task_id = &SampleApp_TaskID; SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; SampleApp_epDesc.latencyReq = noLatencyReqs; // Register the endpoint description with the AF afRegister( &SampleApp_epDesc ); .......... }
(2)任务处理函数设置
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; (void)task_id; // Intentionally unreferenced parameter .............................. // Send a message out - This event is generated by a timer // (setup in SampleApp_Init()). if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) { // Send the periodic message //SampleApp_SendPeriodicMessage(); SampleApp_Send_P2P_Message(); // 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); } ................. return 0; }
(3)接收函数设置
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) { uint16 flashTime; switch ( pkt->clusterId ) { case SAMPLEAPP_P2P_CLUSTERID: HalUARTWrite(0, "Rx:", 3); //提示接收到数据 HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //串口输出接收到的数据 HalUARTWrite(0, "\n", 1); // 回车换行 break; ............................. } }
(4)发送函数设置
void SampleApp_Send_P2P_Message( void ) { uint8 data[11]="0123456789"; if ( AF_DataRequest( &SampleApp_P2P_DstAddr, &SampleApp_epDesc, SAMPLEAPP_P2P_CLUSTERID, 10, data, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { // Error occurred in request to send. } }
四、参考链接