上一节讲到终端节点向协调器发送一个绑定请求,在此之前呢,我们需要将协调器的绑定允许,这样终端节点才可以绑定成功~。好,我们选择workplace为simpleCollectorEB,然后我们按下s2键。在sapi层找到处理该事件的函数,找到SAPI_ProcessEvent中的如下代码:
case KEY_CHANGE:
#if ( SAPI_CB_FUNC )
zb_HandleKeys( ((keyChange_t *)pMsg)->state,((keyChange_t *)pMsg)->keys );
#endif
break;
进入到zb_HandleKeys处理键盘事件的函数中去看看:
if ( keys & HAL_KEY_SW_2)
{
if ( myAppState == APP_INIT )//这时应用状态已经不是初始化状态了,而是APP_START,执行else语句
{
// In the init state, keys are used to indicate the logicalmode.
// Key 2 starts device as a router
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8),&logicalType );
if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )
{
logicalType = ZG_DEVICETYPE_ROUTER;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),&logicalType);
}
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );
zb_SystemReset();
}
else
{
// Turn OFF Allow Bind mode indefinitely
zb_AllowBind( 0xff );//执行允许绑定函数
HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );//关闭LED_1
}
}
进入允许绑定函数中,看看源代码:
void zb_AllowBind ( uint8 timeout )
{
osal_stop_timerEx(sapi_TaskID,ZB_ALLOW_BIND_TIMER);//停止ZB_ALLOW_BIND_TIMER事件
if ( timeout == 0 )//不成立,执行else中的语句
{
afSetMatch(sapi_epDesc.simpleDesc->EndPoint,FALSE);
}
else
{
afSetMatch(sapi_epDesc.simpleDesc->EndPoint,TRUE);//执行次函数,即允许设置匹配描述符。绑定的实质呢就是寻找匹配的描述符,允许设置匹配描述符就是允许绑定
if ( timeout!= 0xFF )
{
if ( timeout > 64 )
{
timeout = 64;
}
osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER,timeout*1000);
}
}
return;
}
好,协调器允许绑定以后,我们要看一下终端节点怎么绑定协调器的,选择workplace为simpleSensorEB,终端节点在zb_StartConfirm函数时向sapi层发送了一个MY_FIND_COLLECTOR_EVT事件,来绑定一个协调器,我们看看具体代码,MY_FIND_COLLECTOR_EVT事件是在用户事件中,并找到:
if ( event & MY_FIND_COLLECTOR_EVT )
{
// Find andbind to a collector device
zb_BindDevice( TRUE, SENSOR_REPORT_CMD_ID, (uint8 *)NULL);//该函数的作用就是找到并且绑定协调器
}
我们可以进去看看源代码:
void zb_BindDevice ( uint8 create, uint16 commandId, uint8*pDestination )
{
zAddrType_t destination;
uint8 ret = ZB_ALREADY_IN_PROGRESS;
if ( create )//成立
{
if(sapi_bindInProgress ==0xffff)//初始化时确实将sapi_bindInProgress赋值为0xffff
{
if ( pDestination )//地址指针为空,执行下面else里的语句
{
destination.addrMode = Addr64Bit;
osal_cpyExtAddr( destination.addr.extAddr, pDestination );
ret = APSME_BindRequest( sapi_epDesc.endPoint, commandId,
&destination, sapi_epDesc.endPoint );
if ( ret == ZSuccess )
{
// Find nwk addr
ZDP_NwkAddrReq(pDestination, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
}
}
else
{
ret = ZB_INVALID_PARAMETER;
destination.addrMode = Addr16Bit;//16位网络地址
destination.addr.shortAddr =NWK_BROADCAST_SHORTADDR;//设置为广播地址0xffff
if ( ZDO_AnyClusterMatches( 1, &commandId,sapi_epDesc.simpleDesc->AppNumOutClusters,
sapi_epDesc.simpleDesc->pAppOutClusterList ))//该函数的作用是寻找到一个可以绑定的协调器,并且从输出簇中看看是否匹配。
{
// Try to match with a device in the allow bind mode
ret = ZDP_MatchDescReq( &destination,NWK_BROADCAST_SHORTADDR,
sapi_epDesc.simpleDesc->AppProfId, 1,&commandId, 0, (cId_t *)NULL, 0);//广播发送匹配描述符请求
}
else if ( ZDO_AnyClusterMatches( 1, &commandId,sapi_epDesc.simpleDesc->AppNumInClusters,
sapi_epDesc.simpleDesc->pAppInClusterList )))//该函数的作用是寻找到一个可以绑定的协调器,并且从输入簇中看看是否匹配。
{
ret = ZDP_MatchDescReq( &destination,NWK_BROADCAST_SHORTADDR,
sapi_epDesc.simpleDesc->AppProfId, 0, (cId_t *)NULL,1, &commandId, 0 );//广播发送匹配描述符请求
}
if ( ret == ZB_SUCCESS )
{
// 设置一段时间来保证完全绑定。
#if ( ZG_BUILD_RTR_TYPE )
osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER,AIB_MaxBindingTime);
#else
// AIB_MaxBindingTime is not defined for an End Device
osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER,zgApsDefaultMaxBindingTime);
#endif
sapi_bindInProgress = commandId;
return; // dont send cback event
}
}
}
SAPI_SendCback( SAPICB_BIND_CNF, ret, commandId );
}
else
{
// Removelocal bindings for the commandId
BindingEntry_t *pBind;
// Loopthrough bindings an remove any that match the cluster
while (pBind = bindFind( sapi_epDesc.simpleDesc->EndPoint,commandId, 0 ) )
{
bindRemoveEntry(pBind);
}
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
}
return;
}
协调器收到此匹配描述符请求会进行处理,我们看是怎么处理的,工作空间选择为协调器。在ZDO层找到ZDApp_event_loop函数中:
if ( events & SYS_EVENT_MSG )
{
while ((msg_ptr = osal_msg_receive( ZDAppTaskID )) )
{
ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );
// Release the memory
osal_msg_deallocate( msg_ptr );
}
// Returnunprocessed events
return(events ^ SYS_EVENT_MSG);
}
进入ZDApp_ProcessOSALMsg函数中:
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
// Data Confirmation message fields
uint8sentEP; // This should always be 0
uint8 sentStatus;
afDataConfirm_t *afDataConfirm;
uint8 tmp;
switch ( msgPtr->event )
{
// IncomingZDO Message
caseAF_INCOMING_MSG_CMD:
ZDP_IncomingData( (afIncomingMSGPacket_t *)msgPtr );
break;
继续进入到ZDP_IncomingData函数中:
void ZDP_IncomingData( afIncomingMSGPacket_t *pData )
{
//下面是对消息进行解析
uint8 x = 0;
uint8 handled;
zdoIncomingMsg_t inMsg;
inMsg.srcAddr.addrMode = Addr16Bit;
inMsg.srcAddr.addr.shortAddr =pData->srcAddr.addr.shortAddr;
inMsg.wasBroadcast =pData->wasBroadcast;
inMsg.clusterID =pData->clusterId;
inMsg.SecurityUse =pData->SecurityUse;
inMsg.asduLen =pData->cmd.DataLength-1;
inMsg.asdu =pData->cmd.Data+1;
inMsg.TransSeq =pData->cmd.Data[0];
inMsg.macDestAddr =pData->macDestAddr;
handled = ZDO_SendMsgCBs(&inMsg );
#if (defined MT_ZDO_CB_FUNC)
#if !defined MT_TASK
if (zgZdoDirectCB)
#endif
{
MT_ZdoDirectCB( pData, &inMsg );
}
#endif
while ( zdpMsgProcs[x].clusterID != 0xFFFF)
{
if (zdpMsgProcs[x].clusterID == inMsg.clusterID)//看看有没有这种clusterID类型的请求
{
zdpMsgProcs[x].pFn( &inMsg);//如果有,进入到此函数中,zdpMsgProcs是个结构体数组,点击进入看看
return;
}
x++;
}
// Handle unhandled messages
if ( !handled )
ZDApp_InMsgCB( &inMsg );
}
typedef struct
{
uint16 clusterID;
pfnZDPMsgProcessor pFn;
} zdpMsgProcItem_t;
CONST zdpMsgProcItem_t zdpMsgProcs[] =
{
#if ( RFD_RCVC_ALWAYS_ON==TRUE ) || ( ZG_BUILD_RTR_TYPE )
// These aren't processed by sleeping enddevices.
{NWK_addr_req, zdpProcessAddrReq },
{Device_annce, ZDO_ProcessDeviceAnnce },
#endif
{IEEE_addr_req, zdpProcessAddrReq },
{Node_Desc_req, ZDO_ProcessNodeDescReq },
{Power_Desc_req, ZDO_ProcessPowerDescReq },
{Simple_Desc_req, ZDO_ProcessSimpleDescReq },
{Active_EP_req, ZDO_ProcessActiveEPReq },
{Match_Desc_req, ZDO_ProcessMatchDescReq},//在这找到Match_Desc_req,对应的处理函数 是ZDO_ProcessMatchDescReq
#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
{Mgmt_NWK_Disc_req, ZDO_ProcessMgmtNwkDiscReq },
#endif
#if defined ( ZDO_MGMT_LQI_RESPONSE )&& ( ZG_BUILD_RTR_TYPE )
{Mgmt_Lqi_req, ZDO_ProcessMgmtLqiReq },
#endif
#if defined ( ZDO_MGMT_RTG_RESPONSE )&& ( ZG_BUILD_RTR_TYPE )
{Mgmt_Rtg_req, ZDO_ProcessMgmtRtgReq },
#endif
#if defined ( ZDO_MGMT_BIND_RESPONSE )&& defined ( REFLECTOR )
{Mgmt_Bind_req, ZDO_ProcessMgmtBindReq },
#endif
#if defined ( ZDO_MGMT_JOINDIRECT_RESPONSE )&& ( ZG_BUILD_RTR_TYPE )
{Mgmt_Direct_Join_req, ZDO_ProcessMgmtDirectJoinReq },
#endif
#if defined ( ZDO_MGMT_LEAVE_RESPONSE )
{Mgmt_Leave_req, ZDO_ProcessMgmtLeaveReq },
#endif
#if defined ( ZDO_MGMT_PERMIT_JOIN_RESPONSE ) && ( ZG_BUILD_RTR_TYPE )
{Mgmt_Permit_Join_req, ZDO_ProcessMgmtPermitJoinReq },
#endif
#if defined ( ZDO_USERDESC_RESPONSE )
{User_Desc_req, ZDO_ProcessUserDescReq },
#endif
#if defined ( ZDO_USERDESCSET_RESPONSE )
{User_Desc_set, ZDO_ProcessUserDescSet },
#endif
#if defined ( ZDO_SERVERDISC_RESPONSE )
{Server_Discovery_req, ZDO_ProcessServerDiscReq },
#endif
{0xFFFF, NULL} // Last
};
进入到 ZDO_ProcessMatchDescReq 函数中,看看如何对匹配描述符请求进行处理
void ZDO_ProcessMatchDescReq( zdoIncomingMsg_t *inMsg )
{
uint8 epCnt = 0;
uint8 numInClusters;
uint16 *inClusters = NULL;
uint8 numOutClusters;
uint16 *outClusters = NULL;
epList_t *epDesc;
SimpleDescriptionFormat_t *sDesc = NULL;
uint8 allocated;
uint8 *msg;
uint16 aoi;
uint16 profileID;
// Parse the incoming message
msg = inMsg->asdu;
aoi = BUILD_UINT16( msg[0], msg[1] );
profileID = BUILD_UINT16( msg[2], msg[3]);
msg += 4;
if ( ADDR_BCAST_NOT_ME ==NLME_IsAddressBroadcast(aoi) )
{
ZDP_MatchDescRsp( inMsg->TransSeq,&(inMsg->srcAddr),ZDP_INVALID_REQTYPE,
ZDAppNwkAddr.addr.shortAddr, 0, NULL,inMsg->SecurityUse );
return;
}
else if ( (ADDR_NOT_BCAST ==NLME_IsAddressBroadcast(aoi)) &&(aoi != ZDAppNwkAddr.addr.shortAddr) )
{
ZDP_MatchDescRsp( inMsg->TransSeq,&(inMsg->srcAddr),ZDP_INVALID_REQTYPE,
ZDAppNwkAddr.addr.shortAddr, 0, NULL,inMsg->SecurityUse );
return;
}
if ((numInClusters = *msg++)&&
(inClusters = (uint16*)osal_mem_alloc( numInClusters * sizeof(uint16 ) )))
{
msg =ZDO_ConvertOTAClusters( numInClusters, msg, inClusters );
}
else
{
numInClusters = 0;
}
if ((numOutClusters = *msg++)&&
(outClusters = (uint16 *)osal_mem_alloc( numOutClusters * sizeof(uint16 ) )))
{
msg =ZDO_ConvertOTAClusters( numOutClusters, msg, outClusters );
}
else
{
numOutClusters = 0;
}
// First count the number of endpoints thatmatch.
epDesc = epList;
while ( epDesc )
{
// Don'tsearch endpoint 0 and check if response is allowed
if (epDesc->epDesc->endPoint != ZDO_EP&&(epDesc->flags&eEP_AllowMatch))
{
if ( epDesc->pfnDescCB )
{
sDesc = (SimpleDescriptionFormat_t*)epDesc->pfnDescCB( AF_DESCRIPTOR_SIMPLE,epDesc->epDesc->endPoint );
allocated = TRUE;
}
else
{
sDesc =epDesc->epDesc->simpleDesc;
allocated = FALSE;
}
if ( sDesc &&sDesc->AppProfId == profileID )
{
uint8 *uint8Buf = (uint8 *)ZDOBuildBuf;
// If there are no search input/ouput clusters - respond
if ( ((numInClusters == 0) &&(numOutClusters == 0))
// Are there matching input clusters?
|| (ZDO_AnyClusterMatches( numInClusters, inClusters,
sDesc->AppNumInClusters,sDesc->pAppInClusterList ))
// Are there matching output clusters?
|| (ZDO_AnyClusterMatches( numOutClusters, outClusters,
sDesc->AppNumOutClusters,sDesc->pAppOutClusterList)) )
{
// 没有端点匹配处理.
uint8 bufLen = sizeof( ZDO_MatchDescRspSent_t ) + (numOutClusters +numInClusters) * sizeof(uint16);
ZDO_MatchDescRspSent_t *pRspSent = (ZDO_MatchDescRspSent_t *)osal_msg_allocate( bufLen );
if (pRspSent)
{
pRspSent->hdr.event = ZDO_MATCH_DESC_RSP_SENT;
pRspSent->nwkAddr =inMsg->srcAddr.addr.shortAddr;
pRspSent->numInClusters = numInClusters;
pRspSent->numOutClusters = numOutClusters;
if (numInClusters)
{
pRspSent->pInClusters = (uint16*) (pRspSent +1);
osal_memcpy(pRspSent->pInClusters, inClusters,numInClusters * sizeof(uint16));
}
else
{
pRspSent->pInClusters = NULL;
}
if (numOutClusters)
{
pRspSent->pOutClusters = (uint16*)(pRspSent + 1) +numInClusters;
osal_memcpy(pRspSent->pOutClusters, outClusters,numOutClusters * sizeof(uint16));
}
else
{
pRspSent->pOutClusters = NULL;
}
osal_msg_send(*epDesc->epDesc->task_id, (uint8*)pRspSent );
}
uint8Buf[epCnt++] = sDesc->EndPoint;
}
}
if ( allocated )
osal_mem_free( sDesc );
}
epDesc =epDesc->nextDesc;
}
// 当至少有一个匹配时,发送消息
if ( epCnt )
{
if (ZSuccess == ZDP_MatchDescRsp( inMsg->TransSeq,&(inMsg->srcAddr),ZDP_SUCCESS,
ZDAppNwkAddr.addr.shortAddr, epCnt, (uint8 *)ZDOBuildBuf,inMsg->SecurityUse ) )//发送匹配描述符响应给终端节点。
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "Match Desc Req", "Rsp Sent" );
#endif
}
}
else
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "Match Desc Req", "Non Matched" );
#endif
}
if ( inClusters != NULL )
osal_mem_free( inClusters );
if ( outClusters != NULL )
osal_mem_free( outClusters );
}