Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2257721
  • 博文数量: 187
  • 博客积分: 1457
  • 博客等级: 上尉
  • 技术积分: 2423
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-13 09:41
个人简介

如需要绘制PCB,设计电路可以和我联系。sunhenu@163.com.

文章分类

全部博文(187)

文章存档

2017年(2)

2016年(2)

2015年(7)

2014年(13)

2013年(80)

2012年(83)

分类: LINUX

2013-04-20 11:16:26

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

以下为系统处理来自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( 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;

  }

}

 

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

阅读(4557) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~