|
本帖最后由 shaomengchao 于 2010-12-8 01:36 编辑
在ZDApp_ProcessMsgCBs中首先调用的是ZDO_ParseEndDeviceBindReq处理消息,其实这个就是将inMsg里的封装信息传到bindReq里。为我们后面的关键ZDO_MatchEndDeviceBind调用做准备。下面我们仔细分析ZDO_MatchEndDeviceBind函数。
void ZDO_MatchEndDeviceBind( ZDEndDeviceBind_t *bindReq )
{
zAddrType_t dstAddr;
uint8 sendRsp = FALSE;
uint8 status;
// Is this the first request?
if ( matchED == NULL ) // 假设之前没有节点提出End_Device_Bind_req,这个match是空的
{
// Create match info structure
matchED = (ZDMatchEndDeviceBind_t *)osal_mem_alloc( sizeof ( ZDMatchEndDeviceBind_t ) );
if ( matchED )
{
// Clear the structure
osal_memset( (uint8 *)matchED, 0, sizeof ( ZDMatchEndDeviceBind_t ) );
// Copy the first request's information
if ( !ZDO_CopyMatchInfo( &(matchED->ed1), bindReq ) )
{
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
/*
matched是个关键的结构体,里面包含了coordinator节点存储的bind表的信息
typedef struct
{
ZDEndDeviceBind_t ed1;
ZDEndDeviceBind_t ed2;
uint8 state; // One of the above states
uint8 sending; // 0 - not sent, 1 - unbind, 2 bind - expecting response
uint8 transSeq;
uint8 ed1numMatched;
uint16 *ed1Matched;
uint8 ed2numMatched;
uint16 *ed2Matched;
}
上面的函数将我们从bindReq获取的bind节点1的信息也就是我们之前说的节点1的nwk地址、ieee地址、ep和簇列表存入了ed1
*/
}
else
{
status = ZDP_NO_ENTRY; //分配失败 立即发送End_Device_Bind_rsp帧,当然帧里面status 是 ZDP_NO_ENTRY
sendRsp = TRUE;
}
if ( !sendRsp )
{
// Set into the correct state
matchED->state = ZDMATCH_WAIT_REQ; //如果成功了当前状态为等待节点2的End_Device_Bind_req请求
// Setup the timeout
APS_SetEndDeviceBindTimeout( AIB_MaxBindingTime, ZDO_EndDeviceBindMatchTimeoutCB );//定时
}
}
else //这里就是节点2在节点1发出End_Device_Bind_req请求后重复之前的过程进入的部分
{
matchED->state = ZDMATCH_SENDING_BINDS; //节点1已经在matched表里面了
// Copy the 2nd request's information
if ( !ZDO_CopyMatchInfo( &(matchED->ed2), bindReq ) )
{
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
// Make a source match for ed1
matchED->ed1numMatched = ZDO_CompareClusterLists(
matchED->ed1.numOutClusters, matchED->ed1.outClusters,
matchED->ed2.numInClusters, matchED->ed2.inClusters, ZDOBuildBuf );
if ( matchED->ed1numMatched )
{
// Save the match list
matchED->ed1Matched = osal_mem_alloc( (short)(matchED->ed1numMatched * sizeof ( uint16 )) );
if ( matchED->ed1Matched )
{
osal_memcpy( matchED->ed1Matched, ZDOBuildBuf, (matchED->ed1numMatched * sizeof ( uint16 )) );
}
else
{
// Allocation error, stop
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
}
// Make a source match for ed2
matchED->ed2numMatched = ZDO_CompareClusterLists(
matchED->ed2.numOutClusters, matchED->ed2.outClusters,
matchED->ed1.numInClusters, matchED->ed1.inClusters, ZDOBuildBuf );
if ( matchED->ed2numMatched )
{
// Save the match list
matchED->ed2Matched = osal_mem_alloc( (short)(matchED->ed2numMatched * sizeof ( uint16 )) );
if ( matchED->ed2Matched )
{
osal_memcpy( matchED->ed2Matched, ZDOBuildBuf, (matchED->ed2numMatched * sizeof ( uint16 )) );
}
else
{
// Allocation error, stop
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
}
这里是比较节点1和节点2的输入和输出簇列表,节点1输出簇列表和节点2输入簇列表簇号相同的将存入matchED->ed1Matched里
而节点2输出簇列表和节点1输入簇列表簇号相同的将存入matchED->ed2Matched,如果没有分配成功的则发出
End_Device_Bind_rsp帧,帧状态为 ZDP_NO_ENTRY
if ( (sendRsp == FALSE) && (matchED->ed1numMatched || matchED->ed2numMatched) )
{
// Do the first unbind/bind state 之前如果一切顺利的话我们会进入这里
ZDMatchSendState( ZDMATCH_REASON_START, ZDP_SUCCESS, 0 );
}
else
{//如果没有匹配的则发出End_Device_Bind_rsp帧,帧状态为 ZDP_NO_MATCH
status = ZDP_NO_MATCH;
sendRsp = TRUE;
}
}
if ( sendRsp )
{
// send response to this requester
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = bindReq->srcAddr;
//
ZDP_EndDeviceBindRsp( bindReq->TransSeq, &dstAddr, status, bindReq->SecurityUse );
if ( matchED->state == ZDMATCH_SENDING_BINDS )
{//发送End_Device_Bind_rsp帧
// send response to first requester
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = matchED->ed1.srcAddr;
ZDP_EndDeviceBindRsp( matchED->ed1.TransSeq, &dstAddr, status, matchED->ed1.SecurityUse );
}
// Process ended - release memory used
//移除marched里的内容
ZDO_RemoveMatchMemory();
}
}
End_Device_Bind_rep绑定就是总体来说就是节点1的某个endpoint如果想与其他节点具有相同簇id的endpoint绑定,它先向coordinator发出请求,让coordinator将它的endpoint内容存入matched。如果在规定时间内有节点2做了同样的事,而它们的簇列表刚好有相同簇号的簇,于是它们就是能绑定了。具体绑定实现在 ZDMatchSendState里实现。而ZDMatchSendState真是个另人蛋疼的函数,里面利用它实现绑定,我们至少要3次调用它,真是麻烦死了。所以我们留到下次再说。 |
|