我使用的协议栈版本及例子信息: 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层传递一个ASDU到AF层;中间调用了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消息(簇ID为SAMPLEAPP_FLASH_CLUSTERID),那么是用户应用任务的消息事件,则task_id=6, Event_flag在设置事件发生标志函数中被定义为SYS_EVENT_MSG,因而当系统主循环函数轮询到用户应用任务有事件发生时,就调用其事件处理函数SampleApp_ProcessEvent(),来看下这个函数: 函数中对应的task_id=6,events=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); //注意!这里 return到osal_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; } }
/*********************************************************************
|
|