|
回复 2# outman
感谢奥特曼将我的帖子发到了教程里面。关于afIncomingData这个函数究竟收到的是什么,奥特曼建议我去多做做实验,这个经验很好我会好好采纳,不过之后我又看了遍协议栈,终于找到发送Match_Desc_rsp请求的位置了。
之前关于nwk请求的认识很不全面,所以在帖子中关于协议栈在Client Services方面描述的很粗糙现特地补正。
nwk采取的是Client Services机制,一般是Client向 Service发出XXXX_req,而Service接受请求回复XXXX_rsp给Client完成nwk的一次数据传输。
比如说节点1根据ieee地址广播发出NWK_addr_req 请求向节点2获取nwk地址,而节点2接受到NWK_addr_req 请求后根据发送的ieee地址判断是否符合本地ieee地址,再回复给节点1NWK_addr_rsp,这个NWK_addr_rsp里面包含了节点2的地址。如此节点1获得了节点2的地址,完成了一次nwk的请求。
而节点的匹配也是如此。
local device里的GenericApp_HandleKeys如果检测到HAL_KEY_SW_4 的话就调用ZDP_MatchDescReq发出 Match_Desc_req请求。关于这里我发现自己的帖子贴错函数了,应该是
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 );
}
而Match_Desc_req的命令包格式在ZigBee Specification这个文件已经说的很清楚了,由于图片上传大小限制请恕本人不能上图。
而remote device里从afIncomingData函数中获得了Match_Desc_req的命令包,根据层层的调用最后到了ZDO_ProcessMatchDescReq里,而这个函数就是完成了Match_Desc_rsp的传送。
ZDO_ProcessMatchDescReq函数是注册在CONST zdpMsgProcItem_t zdpMsgProcs[]数组里的,这个数组存储了大部分的nwk的XXX_req的处理函数,也就是说存储了大部分XXX_rsp的发送函数。
现在仔细看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] ); //这个就是 NWK_BROADCAST_SHORTADDR
profileID = BUILD_UINT16( msg[2], msg[3] ); //这个是 GENERICAPP_PROFID,这些全是ZDP_MatchDescReq的参数
msg += 4;
if ( ADDR_BCAST_NOT_ME == NLME_IsAddressBroadcast(aoi) ) //广播地址是0xfffd,如果当前device状态RxOnWhenIdle == TRUE 就能接受到
{ // 如果当前device不满足的话发送 ZDP_INVALID_REQTYPE标志给原来的device
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) )//如果不是广播模式且nwk地址和自己不
{ //匹配ZDP_INVALID_REQTYPE
ZDP_MatchDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_INVALID_REQTYPE,
ZDAppNwkAddr.addr.shortAddr, 0, NULL, inMsg->SecurityUse );
return;
}
if ((numInClusters = *msg++) && //复制ZDP_MatchDescReq发送的GenericApp_ClusterList
(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 that match.
epDesc = epList;
while ( epDesc ) //扫描本节点的全部endpoint
{
// Don't search 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 ) //一旦profileID匹配 且endpoint的ClusterList和ZDP_MatchDescReq发送的GenericApp_ClusterList
{ //中有相同的endpiont值
uint8 *uint8Buf = (uint8 *)ZDOBuildBuf;
// Are there matching input clusters?
if ((ZDO_AnyClusterMatches( numInClusters, inClusters,
sDesc->AppNumInClusters, sDesc->pAppInClusterList )) ||
// Are there matching output clusters?
(ZDO_AnyClusterMatches( numOutClusters, outClusters,
sDesc->AppNumOutClusters, sDesc->pAppOutClusterList )))
{
// Notify the endpoint of the match.
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 ); //这个我十分不解,它发送了ZDO_MATCH_DESC_RSP_SENT消息
} //但在GenericApp没有相关参数,不过这个不影响我们的分析
uint8Buf[epCnt++] = sDesc->EndPoint; //非常关键的匹配EndPoint列表,这个就是Match_Desc_rsp回传的内容之一
}
}
if ( allocated )
{
osal_mem_free( sDesc );
}
}
epDesc = epDesc->nextDesc;
}
// Send the message only if at least one match found.
if ( epCnt ) //有匹配的EndPoint
{
if ( ZSuccess == ZDP_MatchDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_SUCCESS,
ZDAppNwkAddr.addr.shortAddr, epCnt, (uint8 *)ZDOBuildBuf, inMsg->SecurityUse ) ) //在这里本节点的shortAddr作为参数发送了,还有
{ //匹配EndPoint列表
#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 );
}
}
而Match_Desc_rsp的帧格式同样在ZigBee Specification中,有兴趣的同学可以自己去看看。
现在功德圆满了,local device发送 Match_Desc_rep给remote device,remote device回应了Match_Desc_rsp给local device,我们再回过头看看local device如何处理获取的信息的。
GenericApp_ProcessZDOMsgs中
switch ( inMsg->clusterID )
......
case Match_Desc_rsp:
{
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
if ( pRsp )
{
if ( pRsp->status == ZSuccess && pRsp->cnt ) //这个很关键,之前ZDO_ProcessMatchDescReq中如果不匹配也会发送Match_Desc_rsp数据不过
{ //它们的status被改成了ZDP_INVALID_REQTYPE或cnt=0,所以函数直接忽视了。
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]; //获得匹配endPoint,当然不一定只有一个
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
osal_mem_free( pRsp );
}
}
break;
终于讲完了,了解了Client Services后以前很多糊里糊涂的地方一下子豁然开朗了,还有ZIGBEE SPECIFICATION这个600多页的文档真的很不错。 |
|