分享

z-stack代码分析--GenericApp实例

 幸福的乐土 2012-06-06

//设备绑定并传送信息(hellow world)
//1、终端绑定:按Joystick右键,发起绑定请求,等待其他节点应答;如其他节点也按了Joystick右键,同样发出了绑定请求,则本节点收到一个End_Device_Bind_rsp的信息,
表示绑定成功并点亮HAL_LED_4
//2、匹配描述:按Joystick左键,发起匹配描述请求,等待其他节点应答;
//终端绑定和匹配描述的区别:
//匹配描述绑定:Match方式。即:一个节点可以通过调用afSetMatch函数允许或禁止本节点被Match(协议栈默认允许,可以手工关闭),然后另外一个节点在一定的时间内发起
ZDP_MatchDescReq请求,允许被Match的节点会响应这个Req,发起的节点在接收到RSP的时候就会自动处理绑定。特点:不需要别人帮忙,只要在网络中的节点互相之间就可以实现
,但是前提是他们一定要Match,即一方的outcluster至少有一个是另外一方的incluster,这种方式在很多时候用起来比较方便。注意:如果同时有多个节点(一个节点上的多个端
点也一样)处于允许Match状态,那么req的这个节点可能会收到一大票满足Match条件的rsp,那么你发起req的节点要在这个处理上多下功夫了。
//终端绑定:两个节点分别通过按键机制调用ZDP_EndDeviceBindReq函数。即:在一定时间内两个节点都通过按键(其他方式也可以)触发调用这个函数。特点:这个函数的调用将会
向协调器发出绑定请求,如果在16S(协议栈默认)时间内两个节点都执行了这个函数,协调器就会帮忙实现绑定。绑定表应该是存在OutCluster那边,即这两个节点应该是一个输出
控制命令,一个接收控制命令,绑定表存在输出控制命令这边。注意:这种方式一定需要协调器,否则不行;但是一旦绑定成功,不再需要协调器,协调器只是帮忙绑定的一个第
三方;虽然叫做EndDeviceBind,但是不局限于End Device,路由器也一样用;重复上述操作会解绑定,也就是说这是一个乒乓方式。
//如何理解OutCluster和InCluster:
//Cluster:簇,某一profile规划下的一特定对象的命令(command)和属性(attribute)的集合。zigbee联盟提供了zigbee cluster library(ZCL)便于程序设计。
//OutCluster:输出控制命令方的簇
//InCluster:接收控制命令方的簇
/*********************************************************************
  This application isn't intended to do anything useful, it is
  intended to be a simple example of an application's structure.
 
  This application sends "Hello World" to another "Generic"
  application every 15 seconds.  The application will also
  receive "Hello World" packets.
 
  The "Hello World" messages are sent/received as MSG type message.
  This applications doesn't have a profile, so it handles everything
  directly - itself.
 
  Key control:
    SW1:
    SW2:  initiates end device binding
    SW3:
    SW4:  initiates a match description request
*********************************************************************/
 
/*********************************************************************
 * INCLUDES
 */
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
 
#include "GenericApp.h"
#include "DebugTrace.h"
 
#if !defined( WIN32 )
  #include "OnBoard.h"
#endif
 
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
 
/*********************************************************************
 * MACROS
 */
 
/*********************************************************************
 * CONSTANTS
 */
 
/*********************************************************************
 * TYPEDEFS
 */
 
/*********************************************************************
 * GLOBAL VARIABLES
 */
 
// This list should be filled with Application specific Cluster IDs.
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{
  GENERICAPP_CLUSTERID
};
 
const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{
  GENERICAPP_ENDPOINT,              //  int Endpoint;
  GENERICAPP_PROFID,                //  uint16 AppProfId[2];
  GENERICAPP_DEVICEID,              //  uint16 AppDeviceId[2];
  GENERICAPP_DEVICE_VERSION,        //  int   AppDevVer:4;
  GENERICAPP_FLAGS,                 //  int   AppFlags:4;
  GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
  (cId_t *)GenericApp_ClusterList,  //  byte *pAppInClusterList;
  GENERICAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
  (cId_t *)GenericApp_ClusterList   //  byte *pAppInClusterList;
};
 
// This is the Endpoint/Interface description.  It is defined here, but
// filled-in in GenericApp_Init().  Another way to go would be to fill
// in the structure here and make it a "const" (in code space).  The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t GenericApp_epDesc;
 
/*********************************************************************
 * EXTERNAL VARIABLES
 */
 
/*********************************************************************
 * EXTERNAL FUNCTIONS
 */
 
/*********************************************************************
 * LOCAL VARIABLES
 */
byte GenericApp_TaskID;   // Task ID for internal task/event processing
                          // This variable will be received when
                          // GenericApp_Init() is called.
devStates_t GenericApp_NwkState;
 
byte GenericApp_TransID;  // This is the unique message ID (counter)
 
afAddrType_t GenericApp_DstAddr;
/*********************************************************************
 * LOCAL FUNCTIONS
 */
void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
void GenericApp_HandleKeys( byte shift, byte keys );
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void GenericApp_SendTheMessage( void );
 
/*********************************************************************
 * NETWORK LAYER CALLBACKS
 */
 
/*********************************************************************
 * PUBLIC FUNCTIONS
 */
 
/*********************************************************************
 * @fn      GenericApp_Init
 *
 * @brief   Initialization function for the Generic App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void GenericApp_Init( byte task_id )
{
  GenericApp_TaskID = task_id;
  GenericApp_NwkState = DEV_INIT;
  GenericApp_TransID = 0;//TransId:osal给每个任务指定的一个id号,传输序号指针。当数据被发送时,会被函数自动加1,防止广播风暴。
 
  // 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().
 
  //发送目的地址+端点地址(端点号)+传送模式
  GenericApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;//传送模式不指定
  GenericApp_DstAddr.endPoint = 0;
  GenericApp_DstAddr.addr.shortAddr = 0;
 
  // Fill out the endpoint description.
  //源(答复或确认)终端的描述(比如操作系统中任务ID等)
  GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;
  GenericApp_epDesc.task_id = &GenericApp_TaskID;
  GenericApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
  GenericApp_epDesc.latencyReq = noLatencyReqs;
 
  // Register the endpoint description with the AF
  //要对该终端进行初始化并在AF进行登记,告诉应用层有这么一个EP已经可以使用,
  //那么下层要是有关于该终端的信息或者应用要对下层做哪些操作,就自动得到下层的配合。
  afRegister( &GenericApp_epDesc );
 
  // Register for all key events - This app will handle all key events
//登记按键事件
  RegisterForKeys( GenericApp_TaskID );
 
  // Update the display
#if defined ( LCD_SUPPORTED )
    HalLcdWriteString( "GenericApp", HAL_LCD_LINE_1 );
#endif
   
//ZDO_RegisterForZDOMsg:是将ZDO方面的消息返回到应用层面处理的一个请求注册,注册后就可以把底层的数据活动情况通过消息的方式发到应用层
//注册ZDO消息,只有注册了的消息才能以ZDO_CB_MSG消息的形式发送给指定的任务
  ZDO_RegisterForZDOMsg( GenericApp_TaskID, End_Device_Bind_rsp );// 我自己解析End_Device_Bind_rsp(终端绑定应答)
  ZDO_RegisterForZDOMsg( GenericApp_TaskID, Match_Desc_rsp );// 我自己解析Match_Desc_rsp (匹配描述应答)
}
 
/*********************************************************************
 * @fn      GenericApp_ProcessEvent
 *
 * @brief   Generic Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The OSAL assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  none
 */
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  afDataConfirm_t *afDataConfirm;
 
  // Data Confirmation message fields
  byte sentEP;
  ZStatus_t sentStatus;
  byte sentTransID;       // This should match the value sent
  (void)task_id;  // Intentionally unreferenced parameter
 
//如果是系统事件消息
  if ( events & SYS_EVENT_MSG )
  {
//获取本任务消息
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        case ZDO_CB_MSG://接收到ZDO消息
          GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
          break;
         
        case KEY_CHANGE://键盘消息
          GenericApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;
 
        case AF_DATA_CONFIRM_CMD://应用层(AF)数据发送完成后确认
          // This message is received as a confirmation of a data packet sent.
          // The status is of ZStatus_t type [defined in ZComDef.h]
          // The message fields are defined in AF.h
          afDataConfirm = (afDataConfirm_t *)MSGpkt;//发送数据后的确认消息
          sentEP = afDataConfirm->endpoint;//取端点
          sentStatus = afDataConfirm->hdr.status;//取状态
          sentTransID = afDataConfirm->transID;//取消息发送ID
          (void)sentEP;
          (void)sentTransID;
 
          // Action taken when confirmation is received.
          if ( sentStatus != ZSuccess )//数据发送不成功
          {
            // The data wasn't delivered -- Do something
          }
          break;
 
        case AF_INCOMING_MSG_CMD://接收到无线数据消息,即新的报文来
          GenericApp_MessageMSGCB( MSGpkt );
          break;
 
        case ZDO_STATE_CHANGE://网络状态变化消息
          GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (GenericApp_NwkState == DEV_ZB_COORD)
              || (GenericApp_NwkState == DEV_ROUTER)
              || (GenericApp_NwkState == DEV_END_DEVICE) )
          {
            // Start sending "the" message in a regular interval.
//启动定时器触发GENERICAPP_SEND_MSG_EVT事件
            osal_start_timerEx( GenericApp_TaskID,
                                GENERICAPP_SEND_MSG_EVT,
                              GENERICAPP_SEND_MSG_TIMEOUT );
          }
          break;
 
        default:
          break;
      }
 
      // Release the memory
//释放内存
      osal_msg_deallocate( (uint8 *)MSGpkt );
 
      // Next
//获取下一条系统消息
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    }
 
    // return unprocessed events
//返回未处理系统事件消息
    return (events ^ SYS_EVENT_MSG);
  }
 
  // Send a message out - This event is generated by a timer
  //  (setup in GenericApp_Init()).
//如果是定时器触发的GENERICAPP_SEND_MSG_EVT自定义消息
  if ( events & GENERICAPP_SEND_MSG_EVT )
  {
    // Send "the" message
    GenericApp_SendTheMessage();
 
    // Setup to send message again
//再次启动定时器触发GENERICAPP_SEND_MSG_EVT事件
    osal_start_timerEx( GenericApp_TaskID,
                        GENERICAPP_SEND_MSG_EVT,
                      GENERICAPP_SEND_MSG_TIMEOUT );
 
    // return unprocessed events
//返回未处理自定义消息
    return (events ^ GENERICAPP_SEND_MSG_EVT);
  }
 
  // Discard unknown events
  return 0;
}
 
/*********************************************************************
 * Event Generation Functions
 */
 
/*********************************************************************
 * @fn      GenericApp_ProcessZDOMsgs()
 *
 * @brief   Process response messages
 *
 * @param   none
 *
 * @return  none
 */
//处理ZDO消息函数
void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
  switch ( inMsg->clusterID )//选择消息簇ID
  {
    case End_Device_Bind_rsp://如果接收到的ZDO消息是终端绑定应答
//ZDO_ParseBindRsp:解析Bind_rsp,Unbind_rsp或End_Device_Bind_rsp信息
      if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )//绑定成功
      {
        // Light LED
        HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
      }
#if defined(BLINK_LEDS)
      else
      {
        // Flash LED to show failure
        HalLedSet ( HAL_LED_4, HAL_LED_MODE_FLASH );
      }
#endif
      break;
 
    case Match_Desc_rsp://如果接收到的ZDO消息是匹配描述应答
      {
//ZDO_ParseEPListRsp:解析Active_EP_rsp或Match_Desc_rsp信息
        ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
        if ( pRsp )
        {
          if ( pRsp->status == ZSuccess && pRsp->cnt )
          {
            GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
            GenericApp_DstAddr.addr.shortAddr = pRsp->nwkAddr;
            // Take the first endpoint, Can be changed to search through endpoints
            GenericApp_DstAddr.endPoint = pRsp->epList[0];
 
            // Light LED
            HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
          }
          osal_mem_free( pRsp );
        }
      }
      break;
  }
}
 
/*********************************************************************
 * @fn      GenericApp_HandleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   shift - true if in shift/alt.
 * @param   keys - bit field for key events. Valid entries:
 *                 HAL_KEY_SW_4
 *                 HAL_KEY_SW_3
 *                 HAL_KEY_SW_2
 *                 HAL_KEY_SW_1
 *
 * @return  none
 */
void GenericApp_HandleKeys( byte shift, byte keys )
{
  zAddrType_t dstAddr;
 
  // Shift is used to make each button/switch dual purpose.
  if ( shift )
  {
    if ( keys & HAL_KEY_SW_1 )
    {
    }
    if ( keys & HAL_KEY_SW_2 )
    {
    }
    if ( keys & HAL_KEY_SW_3 )
    {
    }
    if ( keys & HAL_KEY_SW_4 )
    {
    }
  }
  else
  {
    if ( keys & HAL_KEY_SW_1 )
    {
    }
 
    if ( keys & HAL_KEY_SW_2 )
    {
      HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
 
      // Initiate an End Device Bind Request for the mandatory endpoint
      dstAddr.addrMode = Addr16Bit;
      dstAddr.addr.shortAddr = 0x0000; // Coordinator
//发起终端绑定请求
      ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
                            GenericApp_epDesc.endPoint,
                            GENERICAPP_PROFID,
                            GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
                            GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
                            FALSE );
    }
 
    if ( keys & HAL_KEY_SW_3 )
    {
    }
 
    if ( keys & HAL_KEY_SW_4 )
    {
      HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
      // Initiate a Match Description Request (Service Discovery)
//发起匹配描述绑定(自动绑定)请求
      dstAddr.addrMode = AddrBroadcast;
      dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
      ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
                        GENERICAPP_PROFID,
                        GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
                        GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
                        FALSE );
    }
  }
}
 
/*********************************************************************
 * LOCAL FUNCTIONS
 */
 
/*********************************************************************
 * @fn      GenericApp_MessageMSGCB
 *
 * @brief   Data message processor callback.  This function processes
 *          any incoming data - probably from other devices.  So, based
 *          on cluster ID, perform the intended action.
 *
 * @param   none
 *
 * @return  none
 */
//接收到报文处理函数
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  switch ( pkt->clusterId )
  {
    case GENERICAPP_CLUSTERID:
      // "the" message
#if defined( LCD_SUPPORTED )
      HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
      WPRINTSTR( pkt->cmd.Data );
#endif
      break;
  }
}
 
/*********************************************************************
 * @fn      GenericApp_SendTheMessage
 *
 * @brief   Send "the" message.
 *
 * @param   none
 *
 * @return  none
 */
//发送报文函数
void GenericApp_SendTheMessage( void )
{
  char theMessageData[] = "Hello World";
 
  if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                       GENERICAPP_CLUSTERID,
                       (byte)osal_strlen( theMessageData ) + 1,
                       (byte *)&theMessageData,
                       &GenericApp_TransID,
                       AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
    // Successfully requested to be sent.
  }
  else
  {
    // Error occurred in request to send.
  }
}
 
/*********************************************************************
*********************************************************************/

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多