zigbee端末掉线和重连的问题 cc2530协议栈2.5.1a
掉线:一般都什么样的问题容易引起掉线呢?比如硬件,软件的那些方面呢?协议栈哪里呢?
重连:要说掉线不好分析,若能重连也可以。
1:设备掉线重连:
掉线后进入下面回调函数
void ZDO_SyncIndicationCB( uint8 type, uint16 shortAddr )
产生ZDO_NWK_JOIN_REQ
之后进入到
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
case ZDO_NWK_JOIN_REQ:
devStartMode = MODE_RESUME;//改为resume模式
2.设备断电后重新上电,直接就是resume模式
ZDApp_NetworkInit( 0 );//初始化网络
启动osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );
进入到UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
if ( events & ZDO_NETWORK_INIT )
devState = DEV_INIT;//初始化状态
ZDO_StartDevice();//开始入网
进入后执行最后一个else,以孤儿方式组网
devState = DEV_NWK_ORPHAN;
ret = NLME_OrphanJoinRequest( zgDefaultChannelList,
zgDefaultStartingScanDuration );
等待回调函数
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
把结果通知ZDO_NWK_JOIN_IND
在此处void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
case ZDO_NWK_JOIN_IND:
进入端末处理
ZDApp_ProcessNetworkJoin();
else if ( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_REJOIN )
if (nwkStatus == ZSuccess)
devState = DEV_END_DEVICE;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );////至此入网成功
否则失败了
else
{
if ( devStartMode == MODE_RESUME )、、、掉线后恢复网络失败后到此处
{
if ( ++retryCnt <= MAX_RESUME_RETRY )//////此处非常不明白为什么第一次执行后,就判断由resume改成rejoin模式呢?上面路由节点是3次后换模式
{
if ( _NIB.nwkPanId == 0xFFFF || _NIB.nwkPanId == INVALID_PAN_ID )
devStartMode = MODE_JOIN;
else
{
devStartMode = MODE_REJOIN;
_tmpRejoinState = true;
}
}
// Do a normal join to the network after certain times of rejoin retries
else if( AIB_apsUseInsecureJoin == true )///////此处改为join模式还能恢复到原来的网络了吗?
{
devStartMode = MODE_JOIN;
}
resume模式恢复网络失败后,清楚表后,重新执行网络初始化
// setup a retry for later...
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ (osal_rand()& EXTENDED_JOINING_RANDOM_MASK)) );
}
之后再次进入void ZDO_StartDevice()//再次加入网络
这次执行路由或者终端节点处理中的
if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) )//////上1次执行的else的resume模式
devState = DEV_NWK_DISC;
ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );////发现网络,这里具体是什么作用不是太清楚,开始模式为join和rejoin时,入网都要先执行NLME_NetworkDiscoveryRequest,进入case ZDO_NWK_DISC_CNF:尝试大于2次后再执行NLME_ReJoinRequest吗?为什么这样做呢?
等待回调函数
ZStatus_t ZDO_NetworkDiscoveryConfirmCB(uint8 status)
ZDApp_SendMsg( ZDO_NWK_DISC_CNF,)
进入处理消息
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
case ZDO_NWK_DISC_CNF:
若尝试大于2次
else if ( devStartMode == MODE_REJOIN )
{
devState = DEV_NWK_REJOIN;//////切换rejoin方式入网
if ( NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel) != ZSuccess )
////////////////////以rejoin方式组网也是在ZDO_JoinConfirmCB等待入网的结果,成功则切换devState = DEV_END_DEVICE;osal_set_event( ZDAppTaskID, /////////////////////ZDO_STATE_CHANGE_EVT );失败则重新初始化网络
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
为什么有些设备就是容易掉线,甚至有的失败执行上述重连过程也连不回来的,最坏的情况当协调器允许入网时候,这个设备竟然重新入网而不是恢复原来的网络,上述重连过程我理解的对吗?哪里可能有问题导致重连失败呢?上述过程都是协议栈原来的代码,我并没有进行修改。
抓包发现,重连的设备开始阶段都会发送orphan Notification,
若协调器相应了回复coordinator realignment,则非常大的概率就成功入网继续Device Announce
若协调器没有响应,则掉线设备恢复网络失败,此时设备是否应该重新发送呢?但上面程序中指执行一次NLME_OrphanJoinRequest,失败后if ( ++retryCnt <= MAX_RESUME_RETRY )切换模式rejoin了。而改为NLME_ReJoinRequest方式入网。
但抓包发现能恢复原来网络的大多是orphan Notification,之后协调器及时回复coordinator realignment的。发送rejoin是较少的。
接着楼上的问题:
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
{
if ( Status == ZSUCCESS )
{nwkStateReJoin = FALSE;
else
{nwkStateReJoin = TRUE;
用nwkStateReJoin 这个标志位来判断掉线重连状态的。为什么有时候设备是能上下通信的,而nwkStateReJoin =true呢?
或者说在哪里能准确判断这个端末是否在线呢?
尝试过在sapi中case ZDO_STATE_CHANGE:
SAPI_StartConfirm(ZB_SUCCESS或ZB_INIT);
但发现有时候不可靠呢?有时候断线后重连后并未执行此处SAPI_StartConfirm
非常棒的对终端设备入网流程处理的研究,为了更加清晰的了解整个过程,请下载最新的协议栈Z-Stack Home 1.2.2a,在Z-Stack Developer Guide里面有专门介绍终端设备入网,断线,orphan,rejoin这块的状态机转换图。
我把你的红体子抄下来,进行回复了。
if ( devStartMode == MODE_RESUME )、、、掉线后恢复网络失败后到此处
{
if ( ++retryCnt <= MAX_RESUME_RETRY )//////此处非常不明白为什么第一次执行后,就判断由resume改成rejoin模式呢?上面路由节点是3次后换模式
这个地方虽然写了要判断多次,实际上跟你判断一样,在Resume状态只判断了一次,然后直接进入Rejoin状态的。因为在resume状态,节点发送orphan notification出来,等待父设备回复,如果父设备没有回复就直接去找网络了
else if( AIB_apsUseInsecureJoin == true )///////此处改为join模式还能恢复到原来的网络了吗?
如果改成join以后,可以加到原来的网络,但也是有可能加到其他网络去。所以如果需要一直让设备处于Rejoin状态的话,就要如下的改动。
void ZDApp_NetworkInit( uint16 delay ) { + if ( devStartMode == MODE_REJOIN ) + { + _tmpRejoinState = true; + } if ( delay ) { // Wait awhile before starting the device osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay ); } else { osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); } }
ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );////发现网络,这里具体是什么作用不是太清楚,开始模式为join和rejoin时,入网都要先执行NLME_NetworkDiscoveryRequest,进入case ZDO_NWK_DISC_CNF:尝试大于2次后再执行NLME_ReJoinRequest吗?为什么这样做呢?
发现网络就是去信道上搜索网络,节点会发送beacon Request,然后其他有接收设备能力的设备会发送beacon出来,beacon里面就会带有网络相关的信息,为了让节点能够开始rejoin过程,这个建议你通过空中sniffer 去看下到底发生了什么。
3次的目的在于确实这个发送beacon的设备一个可靠的设备,另外可以收集更多的beacon,用于挑选一个最好的作为父设备入网。
为什么有些设备就是容易掉线,甚至有的失败执行上述重连过程也连不回来的,最坏的情况当协调器允许入网时候,这个设备竟然重新入网而不是恢复原来的网络,上述重连过程我理解的对吗?哪里可能有问题导致重连失败呢?上述过程都是协议栈原来的代码,我并没有进行修改。
抓包发现,重连的设备开始阶段都会发送orphan Notification,
若协调器相应了回复coordinator realignment,则非常大的概率就成功入网继续Device Announce
掉线的根本原因的节点给父设备发数据,没有ACK,即便重发也没有ACK,节点就会触发断线,进入Resume状态。
那么没有ACK的可能比较多,节点射频性能差,两点之间有阻挡物,环境干扰,等等。
如果节点从rejoin 到join状态以后,那么协调器必须要在入网允许的情况下,节点才能加。Rejoin是不需要这个判断的。
Orphan 就是resume这个状态发出来的
@VV
感谢回复
非常感谢@VV的回复
1.在掉线的情况下我们是不允许改变成join模式的,核心的问题还是为什么在orphan或者rejoin模式下一直也连不回去呢?我们就让终端开门狗复位重启,连回去的概率就大大增加了。但还是有连不回去的情况发生。但可能休息一段不确定的时间,终端在重启后还能连回去。这问题到底是出在哪里呢?
2.抓包发现掉线的终端重启后第一次发送orphan。若协调器应答并回复realgnment,则重连成功。但有时有些掉线的设备即使重启后都不发送orphan,可能是哪里出了问题呢?都是网络初始化执行同样的过程。
3.orphan失败后,终端进入rejoin模式。但抓包发现,此时能成功恢复网络的都是终端发出了rejoin,并且协调器ack 他们的第三个字节相同,然后协调器rejoin response,则终端恢复网络成功。失败的情况下终端一直没有发出rejoin request,请问是终端没有发出呢,还是只有成功的情况下才会发出呢?
4.您上面回复的解释说掉线都是终端发出后,没有收到协调器的ack。但问题23,我抓包感觉终端都没有发出orphan或者rejoin request。当然重连失败了。不知道终端出了什么问题。
5.终端发出orphan后,协调器为什么没有回复realignment呢?这段代码在哪里呢?是如何处理的,是协调器没有接到呢,还是接到后处理发现不对而没有回复呢?
@lei chen9
请问您的这个问题解决了吗?
我现在也是ZED离网后,一直beacon request,能收到父节点的beacon回复,但就是不发rejoin request,不能重新入网。
@lei chen9
1, 在重启之前你的节点处于什么状态,时discover 状态吗?如果是discover状态的话,那么节点有没有收到合适的beacon,信号强度足够好。
你使用的是哪个版本的协议栈?
代码做下修改
void ZDApp_NetworkInit( uint16 delay ) { + if ( devStartMode == MODE_REJOIN ) + { + _tmpRejoinState = true; + } if ( delay ) { // Wait awhile before starting the device osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay ); } else { osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); } }
2, 有没有可能没有抓到orphan,状态机每次重新都会执行到resume模式
3,跟第一个问题类似,检查下。
@sinan chen,
按照上面回答的第一个问题,尝试下。
@VV你好,
我的问题在这个判断里,LQI值始终为0,请问LQI是在哪里计算的呢?我用是sniffer捕捉信号强度是没问题的
if ( ( pBeacon->LQI > gMIN_TREE_LQI ) &&
( ( pBeacon->permitJoining == TRUE ) || ( _tmpRejoinState ) ) )
{
Z-Stack Home 1.2.2a.44539 这个版本可以按你的方法修改吗? 让dev一直处于 rejion状态@VV
受教了,讲解的很清楚明白