分享

OSAL处理来自AF的数据包流程

 韦小枫 2012-11-30
 

我使用的协议栈版本及例子信息:

ZigBee2006\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SampleApp

 

以下为系统处理来自AF层数据包的大致流程,

afIncomingData() ——afBuildMSGIncoming() ——osal_msg_send() —— osal_set_event()——

根据task_id调用事件处理函(SampleApp_ProcessEvent()) ——判断具体事件类型调用相应回调函数(SampleApp_MessageMSGCB()) ——实现具体现象

 

    afIncomingData()函数用来从APS层传递一个ASDUAF;中间调用了afBuildMSGIncoming()函数,这个函数是用来为APS层建立一个特定格式的消息包,然后再调用osal_msg_send()把消息(包含了ASDU)传往AF.

AF层规定接收的数据包的类型如下:

typedef struct

{

  osal_event_hdr_t hdr;

  uint16 groupId;

  uint16 clusterId;

  afAddrType_t srcAddr;

  byte endPoint;

  byte wasBroadcast;

  byte LinkQuality;

  byte SecurityUse;

  uint32 timestamp;

  afMSGCommandFormat_t cmd;

} afIncomingMSGPacket_t;

 

首先看一下afIncomingData()函数

/*********************************************************************

 * @fn          afIncomingData

 *

 * @brief       Transfer a data PDU (ASDU) from the APS sub-layer to the AF.

 *

 * @param       aff  - pointer to APS frame format

 * @param       SrcAddress  - Source address

 * @param       LinkQuality - incoming message's link quality

 * @param       SecurityUse - Security enable/disable

 *

 * @return      none

 */

//传输数据:APS---->AF

void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress,

                     uint8 LinkQuality, byte SecurityUse, uint32 timestamp )

{

  endPointDesc_t *epDesc = NULL;

  uint16 epProfileID = 0xFFFF;  // Invalid Profile ID

  epList_t *pList;

  uint8 grpEp;

//-----------

  /*如果这个帧传递模式是组传递*/

  if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )

  {

    // Find the first endpoint for this group

    grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST );

    if ( grpEp == APS_GROUPS_EP_NOT_FOUND )

      return;   // No endpoint found,没找到终端

 

    epDesc = afFindEndPointDesc( grpEp );   //找到终端,接着找终端描述符

    if ( epDesc == NULL )

      return;   // Endpoint descriptor not found,没找到终端描述符

 

    pList = afFindEndPointDescList( epDesc->endPoint );  //找到终端描述符

  }  //pList指向终端列表中的元素

//-----------

  /*广播到各端点*/

  else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )

  {

    // Set the list

    if ( (pList = epList) )

    {

      epDesc = pList->epDesc;

    }

  }

//-----------

  /*单播到特定端点*/

  else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) )

  {

    pList = afFindEndPointDescList( epDesc->endPoint );

  }

//-----------

  while ( epDesc )

  {

    if ( pList->pfnDescCB )  //如果有回叫函数

    {

      uint16 *pID = (uint16 *)(pList->pfnDescCB(

                                 AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint ));

      if ( pID )

      {

        epProfileID = *pID;

        osal_mem_free( pID );

      }

    }

   

    else if ( epDesc->simpleDesc )  //简单描述符

    {

      epProfileID = epDesc->simpleDesc->AppProfId;

    }

 

    if ( (aff->ProfileID == epProfileID) ||

         ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) )  //符合各条件

    {

      { 

        //建立信息传递,注意,这里调用afBuildMSGIncoming()!!

        afBuildMSGIncoming( aff, epDesc, SrcAddress, LinkQuality, SecurityUse, timestamp );

      }

    }

 

    /*组传递模式,找下一个终端*/

    if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )

    {

      // Find the next endpoint for this group

      grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp );

      if ( grpEp == APS_GROUPS_EP_NOT_FOUND )

        return;   // No endpoint found

 

      epDesc = afFindEndPointDesc( grpEp );

      if ( epDesc == NULL )

        return;   // Endpoint descriptor not found

 

      pList = afFindEndPointDescList( epDesc->endPoint );  //epDesc != NULL

    }

    /*广播传递模式,找下一个终端*/

    else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )

    {

      pList = pList->nextDesc;

      if ( pList )

        epDesc = pList->epDesc;

      else

        epDesc = NULL;

    }

    /*单播模式,无下一终端*/

    else

      epDesc = NULL;

  }

}

//----------------------------------------------------------------------------------------

afBuildMSGIncoming( aff, epDesc, SrcAddress, LinkQuality, SecurityUse, timestamp )

afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,

                 zAddrType_t *SrcAddress, uint8 LinkQuality, byte SecurityUse,

                 uint32 timestamp )

实参——形参

Aff——*aff

epDesc——*epDesc

SrcAddress——*SrcAddress

LinkQuality—— LinkQuality

SecurityUse—— SecurityUse

Timestamp—— timestamp

 

看一下afBuildMSGIncoming()函数

/*********************************************************************

 * @fn          afBuildMSGIncoming

 *

 * @brief       Build the message for the app

 *

 * @param

 *

 * @return      pointer to next in data buffer

 */*********************************************************************

//Build the message for the app 

static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,

                 zAddrType_t *SrcAddress, uint8 LinkQuality, byte SecurityUse,

                 uint32 timestamp )

{

  afIncomingMSGPacket_t *MSGpkt;    //AF层需要接收这种结构体类型的信息包

                                                                          //下面就通过本函数来为接收到的信息构造这种类型

                                                                           //信息包,从而可以发送到AF层去

  const byte len = sizeof( afIncomingMSGPacket_t ) + aff->asduLength;  //长度

  byte *asdu = aff->asdu;

  MSGpkt = (afIncomingMSGPacket_t *)osal_msg_allocate( len );  //分配内存

 

  if ( MSGpkt == NULL )

  {

    return;

  }

 

  MSGpkt->hdr.event = AF_INCOMING_MSG_CMD//事件类型

  MSGpkt->groupId = aff->GroupID;         //ID

  MSGpkt->clusterId = aff->ClusterID;     //ID

  afCopyAddress( &MSGpkt->srcAddr, SrcAddress );  //源地址

  MSGpkt->srcAddr.endPoint = aff->SrcEndPoint; 

  MSGpkt->endPoint = epDesc->endPoint;

  MSGpkt->wasBroadcast = aff->wasBroadcast; //广播

  MSGpkt->LinkQuality = LinkQuality;        //链路质量

  MSGpkt->SecurityUse = SecurityUse;        //安全使能

  MSGpkt->timestamp = timestamp;            //时间

 

  MSGpkt->cmd.TransSeqNumber = 0;           //传送序号

  MSGpkt->cmd.DataLength = aff->asduLength; //长度

 

  if ( MSGpkt->cmd.DataLength )  //aff->asduLength

  {

    MSGpkt->cmd.Data = (byte *)(MSGpkt + 1);  //空间

               //把长为 MSGpkt->cmd.DataLength数据从asdu赋给MSGpkt->cmd.Data

    osal_memcpy( MSGpkt->cmd.Data, asdu, MSGpkt->cmd.DataLength );

  }

  else  //无数据

  {

    MSGpkt->cmd.Data = NULL;

  }

 

#if defined ( MT_AF_CB_FUNC )

  // If MT has subscribed for this callback, don't send as a message.

  if AFCB_CHECK(MSGpkt->endPoint, *(epDesc->task_id), SPI_CB_AF_DATA_IND)

  {

    af_MTCB_IncomingData( (void *)MSGpkt );

    // Release the memory.

    osal_msg_deallocate( (void *)MSGpkt );

  }

  else

#endif

  {

    // Send message through task message.

//数据包构造好后,就要发送到AF层,这里调用osal_msg_send()

osal_msg_send( *(epDesc->task_id), (uint8 *)MSGpkt );

  }

}

 

/*********************************************************************

看下osal_msg_send()函数

osal_msg_send( *(epDesc->task_id), (uint8 *)MSGpkt );

byte osal_msg_send( byte destination_task, byte *msg_ptr )

 

实参——形参

*(epDesc->task_id)—— destination_task

(uint8 *)MSGpkt——*msg_ptr

 

/*********************************************************************

 * @fn      osal_msg_send

 *

 * @brief

 *

 *    This function is called by a task to send a command message to

 *    another task or processing element.  The sending_task field must

 *    refer to a valid task, since the task ID will be used

 *    for the response message.  This function will also set a message

 *    ready event in the destination tasks event list.

*

 * @param   byte destination task - Send msg to?  Task ID  目的任务

 * @param   byte *msg_ptr - pointer to new message buffer  指向消息

 * @param   byte len - length of data in message  消息中的数据长度

 *

 * @return  ZSUCCESS, INVALID_SENDING_TASK, INVALID_DESTINATION_TASK,

 *          INVALID_MSG_POINTER, INVALID_LEN

 */*********************************************************************

 

byte osal_msg_send( byte destination_task, byte *msg_ptr )

{

//--------------------------------

  if ( msg_ptr == NULL ) //无消息

    return ( INVALID_MSG_POINTER );

//--------------------------------

  if ( destination_task >= tasksCnt )  //不在任务条目范围内???任务不合法

  {

    osal_msg_deallocate( msg_ptr );

    return ( INVALID_TASK );

  }

//--------------------------------

  // Check the message header

  if ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||

       OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )   //检查到指针不合法

  {

    osal_msg_deallocate( msg_ptr );   //释放这个消息内存

    return ( INVALID_MSG_POINTER );

  }

 

  OSAL_MSG_ID( msg_ptr ) = destination_task;   //检查到含有合法任务的消息,

                            //则把目的任务的ID赋给消息结构体的dest_id

  //OSAL_MSG_ID()参见前面          

                                            

//--------------------------------

  // queue message  把当前消息(msg_ptr所指)加入到系统消息列表中

  osal_msg_enqueue( &osal_qHead, msg_ptr );

//--------------------------------

  // Signal the task that a message is waiting

  osal_set_event( destination_task, SYS_EVENT_MSG );  //设置事件发生标志函数!!

 

  return ( ZSUCCESS );

}

 

/*********************************************************************

看下osal_set_event()函数

osal_set_event( destination_task, SYS_EVENT_MSG )

osal_set_event( byte task_id, UINT16 event_flag )

 

实参——形参

destination_task—— task_id

SYS_EVENT_MSG—— event_flag

/*********************************************************************

 * @fn      osal_set_event

 *

 * @brief

 *

 *    This function is called to set the event flags for a task.  The

 *    event passed in is OR'd into the task's event variable.

 *

 * @param   byte task_id - receiving tasks ID

 * @param   byte event_flag - what event to set

 *

 * @return  ZSUCCESS, INVALID_TASK

 */*********************************************************************/

byte osal_set_event( byte task_id, UINT16 event_flag )

{

  if ( task_id < tasksCnt )

  {

  halIntState_t   intState;

    HAL_ENTER_CRITICAL_SECTION(intState);    // Hold off interrupts

    tasksEvents[task_id] |= event_flag;  // Stuff the event bit(s)  相应任务有事件发生

    HAL_EXIT_CRITICAL_SECTION(intState);     // Release interrupts

  }

   else

    return ( INVALID_TASK );

 

  return ( ZSUCCESS );

}

 

/*********************************************************************

从上面的tasksEvents[task_id] |= event_flag;系统主循环函数中会轮询到相应任务有事件发生(这点请参照OSAL系统主循环流程),因而调用相应的任务事件处理函数.比如说这个消息是从另一个节点发过来的flash消息(簇IDSAMPLEAPP_FLASH_CLUSTERID),那么是用户应用任务的消息事件,则task_id=6,

Event_flag在设置事件发生标志函数中被定义为SYS_EVENT_MSG,因而当系统主循环函数轮询到用户应用任务有事件发生时,就调用其事件处理函数SampleApp_ProcessEvent(),来看下这个函数:

   函数中对应的task_id=6events=SYS_EVENT_MSG,而在构造AF信息包的时候,MSGpkt->hdr.event = AF_INCOMING_MSG_CMD; 因而函数最终调用SampleApp_MessageMSGCB( MSGpkt )进行处理.

 

/*********************************************************************

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )

{

  afIncomingMSGPacket_t *MSGpkt;  //接收到的消息

 

  /*如果是系统消息*///判断OSAL层的消息类型

  if ( events & SYS_EVENT_MSG )

  {

    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );  //接收属于本用户应用SampleApp

                                                       消息(SampleApp_TaskID来标志

    while ( MSGpkt//接收到着                                            

    {                                                                      //属于这个应用的消息osal_msg_receive( MApp_TaskID );

      switch ( MSGpkt->hdr.event//判断数据包事件类型

      {

       

        // Received when a key is pressed

        /*事件:按键事件*/

        case KEY_CHANGE:      //#define KEY_CHANGE  0xC0   --Key Events

          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );

          break;                                             //执行按键处理函

 

         

          // Received when a messages is received (OTA:over the air) for this endpoint

        /*事件:收到信息事件*/

        case AF_INCOMING_MSG_CMD: // #define AF_INCOMING_MSG_CMD  0x 1A  --Incoming MSG type message

          SampleApp_MessageMSGCB( MSGpkt );

          break;

 

          

        // Received whenever the device changes state in the network

          /*事件:端点状态变化事件*/

        case ZDO_STATE_CHANGE:   //#define ZDO_STATE_CHANGE  0xD1  --ZDO has changed the device's network state

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

    //end while ( MSGpkt )

 

    // return unprocessed events

    // 判断是否有未处理的系统消息,有则接收返回没有处理的事件

    return (events ^ SYS_EVENT_MSG);  //注意!这里 returnosal_start_system()下

  }   

//--------------------------

 

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

}

/*********************************************************************

最后我们再来看下SampleApp_MessageMSGCB()函数

SampleApp_MessageMSGCB( MSGpkt )

SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

实参——形参

MSGpkt——*pkt

 

通过判断信息包中的簇ID,SAMPLEAPP_FLASH_CLUSTERID,因而最终执行小灯闪烁四下.

/*********************************************************************

 * @fn      SampleApp_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

 */

//SampleApp_MessageMSGCB()功能是处理接收数据,函数

//的输入为接收到的数据,而输出为小灯闪烁的时间。

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

  uint16 flashTime;

 

  switch ( pkt->clusterId )//判断簇ID

  {

    case SAMPLEAPP_PERIODIC_CLUSTERID //periodic

      break;

 

    case SAMPLEAPP_FLASH_CLUSTERID //flash

      flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );

      HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );  //小灯闪烁四次

      break;

  }

}

 

/*********************************************************************

 

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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多