ZIGBEE官方协议栈 SampleApp工程DemoEB项目 运行机制详解

该project实现了按键发送的功能。

同时实现了信息的广播和组播:

SampleApp_SendPeriodicMessage( void );   //阶段发送,广播形式

SampleApp_SendFlashMessage();   //闪烁发送,组播形式

同时按键up键可以进行控制信息的发送,即控制Group1中所有设备的LED1灯的闪烁时间。

按键right键进行设备加入/退出Group1的切换。

由于在SampleApp_Init( uint8 task_id )中添加了SampleApp_Init( taskID );(最后一个任务)

在操作系统启动的过程中,调用SampleApp_Init( uint8 task_id )

调用顺序:main( void )->osal_init_system();->osalInitTasks()->SampleApp_Init( taskID );

void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;

  // Device hardware initialization can be added here or in main() (Zmain.c).
  // If the hardware is application specific - add it here.
  // If the hardware is other parts of the device add it in main().

 #if defined ( BUILD_ALL_DEVICES )
  // The "Demo" target is setup to have BUILD_ALL_DEVICES and HOLD_AUTO_START
  // We are looking at a jumper (defined in SampleAppHw.c) to be jumpered
  // together - if they are - we will start up a coordinator. Otherwise,
  // the device will start as a router.
  if ( readCoordinatorJumper() )   //根据P02和P03是否有跳线来判断是协调器还是路由器
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
  else
    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES

#if defined ( HOLD_AUTO_START )
  // HOLD_AUTO_START is a compile option that will surpress ZDApp
  //  from starting the device and wait for the application to
  //  start the device.
  ZDOInitDevice(0);    //开始启动设备,协调器建立网络此时LED3闪烁,别的设备加入网络,加入后LED3一直亮着,说明加入成功
#endif

  // 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;

  // 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;

  // 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 );    //将填写好的端点向AF层进行注册,以便收到符合的消息时可以送到应用层

  // Register for all key events - This app will handle all key events
  RegisterForKeys( SampleApp_TaskID );  //注册所有的按键信息,由SampleApp_TaskID对应的SampleApp_ProcessEvent()进行处理

  // By default, all devices start out in Group 1        //这儿填写的组的内容,如组名,组标识,然后加入SAMPLEAPP_ENDPOINT组中
  SampleApp_Group.ID = 0x0001;
  osal_memcpy( SampleApp_Group.name, "Group 1", 7  );
  aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

#if defined ( LCD_SUPPORTED )
  HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}

这样的初始工作就已经完成了,接下来的就是分析按键事件及响应过程了

首先当网络形成时,下层会向应用层发送消息ZDO_STATE_CHANGE它由SampleApp_ProcessEvent()进行处理

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;

可以看出它启动了一个定时器,每次时间到时会触发SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,它由SampleApp_ProcessEvent()进行处理

 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);
  }

我们可以看出,在发送广播信息后又设置了同样的定时器,从而循环的发送。

当有案件时,由于对按键进行了注册,所以由SampleApp_ProcessEvent()进行处理

case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );//进行本函数进行处理
          break;

void SampleApp_HandleKeys( uint8 shift, uint8 keys )
{
  (void)shift;  // Intentionally unreferenced parameter
 
  if ( keys & HAL_KEY_SW_1 )
  {
      SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION );  //发送闪烁控制信息
  }

  if ( keys & HAL_KEY_SW_2 )
  {
    /* The Flashr Command is sent to Group 1.
     * This key toggles this device in and out of group 1.
     * If this device doesn't belong to group 1, this application
     * will not receive the Flash command sent to group 1.
     */
    aps_Group_t *grp;
    grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );//若已经加入组中,则退出组,若没有加入则加入
    if ( grp )
    {
      // Remove from the group
      aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP ); //(该函数的源码不公开,只公布接口)
    }
    else
    {
      // Add to the flash group
      aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
    }
  }
}

再看 SampleApp_SendFlashMessage函数

void SampleApp_SendFlashMessage( uint16 flashTime )  //主要调用AF_DataRequest()函数发送
{
  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.
  }
}

别的设备在接受到后,仍然由SampleApp_ProcessEvent()进行处理

case AF_INCOMING_MSG_CMD:
          SampleApp_MessageMSGCB( MSGpkt );
          break;

可见它由 SampleApp_MessageMSGCB( MSGpkt );处理

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  uint16 flashTime;

  switch ( pkt->clusterId )
  {
    case SAMPLEAPP_PERIODIC_CLUSTERID:  //对于收到的广播信息,忽略
        break;

    case SAMPLEAPP_FLASH_CLUSTERID:
      flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );  //对接受到的组播信息,控制LED4即LED1的闪烁
      HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
      break;
  }
}

这样的话我们就搞清楚了其中的脉络,总之,他就是举了一个按键发送的简单的例子,循环发送广播信息,按UP发送组播信息。

对接收到的广播信息不予理睬,对收到的组播信息控制LED1的闪烁。

同时按键Right时进行设备加入/退出组的切换。

原文地址:https://www.cnblogs.com/ltfbk/p/3269137.html