Ztack学习笔记(6)-广播组播点播

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.
  }
}

四、参考链接

【1】Zigbee单播、组播、广播网络通信

【2】zigbee单播、组播、广播

时间: 2024-11-09 08:09:09

Ztack学习笔记(6)-广播组播点播的相关文章

TCP/IP详解学习笔记(7)-广播和多播,IGMP协议

1.单播,多播,广播的介绍 1.1.单播(unicast) 单播是说,对特定的主机进行数据传送.例如给某一个主机发送IP数据包.这时候,数据链路层给出的数据头里面是非常具体的目的地址,对于以太网来 说,就是网卡的MAC地址(不是FF-FF-FF-FF-FF-FF这样的地址).现在的具有路由功能的主机应该可以将单播数据定向转发,而目的主机的网 络接口则可以过滤掉和自己MAC地址不一致的数据. 1.2.广播(unicast) 广播是主机针对某一个网络上的所有主机发送数据包.这个网络可能是网络,可能是

Android学习笔记之图片轮播...

PS:一个bug又折腾了一个下午....哎... 学习内容: 1.Android利用ViewPager和PagerAdapter实现图片轮播... 2.使用反射机制获取Android的资源信息...     图片轮播是非常常见的一种动画效果,在app中也是很常用的一个效果,这里就简单的来实现一下这个功能,Android中想要实现图片轮播,需要使用到ViewPager这个控件来实现,这个控件的主要功能是实现图片的滑动效果...那么有了滑动,在滑动的基础上附上图片也就实现了图片轮播的效果...这个控

Android 学习笔记 BroadcastReceiver广播...

PS:不断提升自己,是件好事... 学习内容: 1.BroadcastReceiver的使用.. 2.通过BroadcastReceiver去启动Service... 1.BroadcastReceiver...   广播接收者,用来接收系统和应用中的广播...Android广播机制用的地方还是很多的,比如说:当网络状态发生改变的时候,通过接收这条广播就能及时做出相应的响应,然后完成一些操作..这就是广播的机制...它自身并不实现图形用户界面...只是一个触发性的操作...   使用广播是需要几

bootstrap学习笔记 Bootstrap 列表组

本文将介绍列表组.列表组件用于以列表形式呈现复杂的和自定义的内容.创建一个基本的列表组的步骤如下: 向元素ul 添加class list-group 向li添加class list-group-item 下面的示例演示了这点: HTML <ul class="list-group"> <li class="list-group-item">免费注册域名</li> <li class="list-group-item

android菜鸟学习笔记26----Android广播消息及BroadcastReceiver

1.广播类型: Android中的广播有两种类型:标准广播和有序广播.其中,标准广播是完全异步发送的广播,发出之后,几乎所有的广播接收者都会在同一时刻收到这条广播消息,因而,这种类型的广播消息是不可拦截,不可修改的:而有序广播是一种同步发送的广播,广播发出后,只有优先级最高的广播接收者能够收到这条广播消息,它处理完自己的逻辑之后,广播才会向后继续传递给低优先级的广播接收者,因此,高优先级的广播接收者可以对广播消息进行拦截,修改操作. 2.接收系统广播: 要接收系统广播,就要有自己的广播接收者.定

Linux学习笔记——用户、组管理命令及常用选项

用户管理命令: useradd  userdel usermod passwd  id finger chsh  chfn chmod chown  su 组管理命令: groupadd groupdel groupmod gpasswd   chgrp 用户类型分为:用户u:owner.组g:group.其他o:other   三种类型 文件权限包含:r  w  x  执行权限 文件与目录之间关于rwx 权限的区别 : 文件: r :可读  ,可以使用cat 等命令查看 w : 可写  ,可以

IOS 学习笔记 2015-03-20 OC-数组

[NSArray] 一 定义 1 不可变数组 2 oc中数组的元素可以是任何对象 3 数字中装有元素的地址 二 初始化 NSArray *变量 = [[NSArry alloc] initWithObjects:对象...,nil]; 三 使用场景 1 遍历数组 A 枚举 NSEnumerator *enums = [array1 objectEnumerator]; while (obj=[enums nextObject]) B 下标 for (i=0;i<count;i++) { C 快速

Android学习笔记之广播意图及广播接收者MyBroadcastReceiver、Broadcast

(1)第一种使用xml文件进行注册 布局文件,添加一个button点击的时候进行广播 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height

&lt;Bootstrap&gt; 学习笔记五. 按钮组的使用

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="bootstrap/css/bootstrap.css"> <link rel="stylesheet&