zoukankan      html  css  js  c++  java
  • 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
    ", sizeof("UartInit OK
    "));//提示信息
       ..............................................................................
     //建立广播目的地址
      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, "
    ", 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 )
      {
      }
      ..............................................................
    }

    二、组播

    具体说明组播通信,假设终端发“0123456789”数据给同一组的协调器,当协调器收到数据后,D1闪烁并通过串口发给电脑,电脑上的串口调试助手显示接收到的字符串,具体的流程如下图所示:左边为协调器的工作流程,右边为终端的工作流程,其中黑色阴影部分为SampleApp_Init函数完成的工作,橙色阴影部分为SampleApp_ProcessEvent函数完成的工作,蓝色阴影部分为SampleApp_MessageMSGCB和SampleApp_SendPeriodicMessage处理函数完成的工作,省略号表示其他代码。

    (1)初始化函数

    即完成一些初始化工作,如果是协调器,则实现注册串口,填充端点描述符并注册端点描述符,接着任务组初始化,并将终端加入到组中,值得注意的是,任务组的ID号要和终端的目的地址的短地址号SAMPLEAPP_FLASH_GROUP一致;如果是终端,则实现建立组播目的地址,填充端点描述符并注册端点描述符等。

    void SampleApp_Init( uint8 task_id )
    {
    ..................................................................................................
     //串口初始化
      MT_UartInit();                  //串口初始化
      MT_UartRegisterTaskID(task_id); //注册串口任务
      HalUARTWrite(0,"UartInit OK
    ", sizeof("UartInit OK
    "));//提示信息
      
      ............................
      // 建立组目的地址
      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
      
      /填充端点描述符
      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 );
    
      ................................
      // 初始化组并将端点加入到组中
      SampleApp_Group.ID = 0x0001;
      //SampleApp_Group.ID = 0x0002;
      osal_memcpy( SampleApp_Group.name, "Group 1", 7 );
      aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
    
    ...............................
    }

    (2)任务处理函数

    处理函数的分析与广播类似,区别在于定时时间到达后,响应的是组播发送函数 SampleApp_SendFlashMessage。

    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 )
          {        
           .............................................................
            // 系统消息命令到来
            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 );
              }
              ...................................................................................
          }
    
       ........................................................................................
        }
    ...................................................................................
      }
    
      //  由定时器触发定时任务
      if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
      {
        // 发送组播信息
       SampleApp_SendFlashMessage(2);
        // 重新建立组播定时任务
        osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
            (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
    
    .........................................................................................
      }
    
      // Discard unknown events
      return 0;
    }

    (3)接收函数设置

    分析与广播类似,区别是收到组播信息后,发送完串口数据,命令协调器的D1闪烁。

    void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
    {
      uint8 data;
    
      switch ( pkt->clusterId )
      {    
    .............................................
       case SAMPLEAPP_FLASH_CLUSTERID:     //
           HalUARTWrite(0, "Rx:", 3);        //提示信息
          HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //输出接收到的数据
          HalUARTWrite(0, "
    ", 1);         //回车换行
          HalLedBlink( HAL_LED_4, 2, 50, (flashTime / 4) );
          break;
      
    ..............................................
    }

    (4)发送函数设置 

    分析与广播类似,区别在于参数1包含了组播信息,即通信方式为组播,且短地址为目的地址组(协调器)的ID号,参考3规定为组播协议族。

    void SampleApp_SendFlashMessage( uint16 flashTime )
    {
     uint8 data[11]="0123456789";
      if ( AF_DataRequest(  &SampleApp_Flash_DstAddr, 
                           &SampleApp_epDesc,
                           SAMPLEAPP_FLASH_CLUSTERID,
                           10,
                           data,
                           &SampleApp_TransID,
                           AF_DISCV_ROUTE,
                           AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
      {
      }
    ..........................................................................
    }

    三、点播

    具体说明广播通信,假设终端发“0123456789”数据给协调器,当协调器收到数据后,通过串口发给电脑,电脑上的串口调试助手显示接收到的字符串,具体的流程如下图所示:左边为协调器的工作流程,右边为终端的工作流程,其中黑色阴影部分为SampleApp_Init函数完成的工作,橙色阴影部分为SampleApp_ProcessEvent函数完成的工作,蓝色阴影部分为SampleApp_MessageMSGCB和SampleApp_SendPeriodicMessage处理函数完成的工作,省略号表示其他代码。

    (1)初始化函数配置

    void SampleApp_Init( uint8 task_id )
    { 
       ...................................................................
      MT_UartInit();                  //串口初始化
      MT_UartRegisterTaskID(task_id); //注册串口任务
    .............................................................................
      SampleApp_P2P_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; //点播 
      SampleApp_P2P_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; 
      SampleApp_P2P_DstAddr.addr.shortAddr = 0x0000;            //发给协调器
    
      // 填充端点描述符
      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)任务处理函数设置

    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 )
          {        
           ................................................................................................
    
            // 系统消息命令到来
            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 );
              }
            .........................................................................................
          }
    
         ............................................................................
        }
        ................................................................................
      }
    
      // 触发定时任务
      if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
      {
        // 发送点播信息
        SampleApp_Send_P2P_Message();
        // 重新设置定时任务
        osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
            (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
    
     .........................................................................
      }
    
      // Discard unknown events
      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, "
    ", 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 )
     ....................................................
    }

    四、参考链接

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

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

  • 相关阅读:
    XPATH基本语法
    为博客园添加目录、导航的方法总结
    性能测试学习之路 (三)jmeter常见性能指标(相关术语、聚合报告 && 服务器性能监控配置 && 图形结果 && 概要报告)
    性能测试学习之路 (二)jmeter详解(jmeter执行顺序 && 作用域 && 断言 && 事务 &&集合点 )
    性能测试学习之路 (一)认识jmeter(性能测试流程 && 性能测试通过标准 &&jmeter体系结构)
    Mysql基础知识
    索引优化之Explain 及慢查询日志
    shell 编程 && bash 简介(shell 变量、shell操作环境、数据流重导向、管线命令、shell script)
    Mysql 逻辑架构图及日志系统
    react ,ant Design UI中table组件合并单元格并展开详情的问题
  • 原文地址:https://www.cnblogs.com/gjianw217/p/4499056.html
Copyright © 2011-2022 走看看