【转】zigbee终端无法重连的问题解决
zigbee终端无法重连的问题解决
1.zigbee重连的原因
(1)zigbee由于各种原因的干扰导致信号太差而掉线。
(2)协调器重启。
2.zigbee终端重连的处理
(1)zigbee掉线后会进入回调函数:void ZDO_SyncIndicationCB( uint8 type, uint16 shortAddr );
产生ZDO_NWK_JOIN_REQ,之后会重新初始化网络:
case ZDO_NWK_JOIN_REQ: //重连事件
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
retryCnt = 0;
devStartMode = MODE_RESUME; //让设备处于网络恢复模式(个人认为也是重连的模式)
_tmpRejoinState = true; //初始化临时状态为重连
osal_cpyExtAddr( ZDO_UseExtendedPANID, _NIB.extendedPANID ); //初始化ZDO为之前的PANID
zgDefaultStartingScanDuration = BEACON_ORDER_60_MSEC; //每60毫秒发送一个信标
ZDApp_NetworkInit( 0 ); //重新初始化网络产生ZDO_NETWORK_INIT事件
}
(2)接着会重新启动设备,按重连的方式初始化网络。
if ( events & ZDO_NETWORK_INIT )
{
// Initialize apps and start the network
devState = DEV_INIT;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER ); // Return unprocessed events
return (events ^ ZDO_NETWORK_INIT);
}
(3)启动设备的时候,终端节点是已孤儿节点(Orphan)来入网的。
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
...........
else if ( startMode == MODE_RESUME )
{
if ( logicalType == NODETYPE_ROUTER )
{
ZMacScanCnf_t scanCnf;
devState = DEV_NWK_ORPHAN; /* if router and nvram is available, fake successful orphan scan */
scanCnf.hdr.Status = ZSUCCESS;
scanCnf.ScanType = ZMAC_ORPHAN_SCAN;
scanCnf.UnscannedChannels = 0;
scanCnf.ResultListSize = 0;
nwk_ScanJoiningOrphan(&scanCnf); ret = ZSuccess;
}
else
{
devState = DEV_NWK_ORPHAN;
ret = NLME_OrphanJoinRequest( zgDefaultChannelList,
zgDefaultStartingScanDuration );
}
}
else
{
}
}
.....
}
(4)加入以孤儿节点的方式还是入网失败,则协议栈会让zigbee的入网模式改为MODE_JOIN或者MODE_REJOIN。
void ZDApp_ProcessNetworkJoin( void )
{
........
else if ( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_REJOIN )
{
// results of an orphaning attempt by this device
if (nwkStatus == ZSuccess)
{
// Verify NWK key is available before sending Device_annce
if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey() == false ) )
{
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); // wait for auth from trust center
devState = DEV_END_DEVICE_UNAUTH; // Start the reset timer for MAX UNAUTH time
ZDApp_ResetTimerStart( MAX_DEVICE_UNAUTH_TIMEOUT );
}
else
{ devState = DEV_END_DEVICE;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
// setup Power Manager Device
// The receiver is on, turn network layer polling off.
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
{
{
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
}
} if ( ZSTACK_ROUTER_BUILD )
{
// NOTE: first two parameters are not used, see NLMEDE.h for details
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
NLME_StartRouterRequest( 0, 0, false );
}
} ZDApp_AnnounceNewAddress();
}
}
else
{
if ( devStartMode == MODE_RESUME )
{
if ( ++retryCnt <= MAX_RESUME_RETRY )
{
//如果nwkPanId没有设置,则让设备入网模式设为第一次入网;如果nwkPanId有设置过则入网模式设为重新入网
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 )
{
devStartMode = MODE_JOIN;
}
}
// Clear the neighbor Table and network discovery tables.
nwkNeighborInitTable();
NLME_NwkDiscTerm(); // setup a retry for later...
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ (osal_rand()& EXTENDED_JOINING_RANDOM_MASK)) );
}
}
.......
}
}
(4)接着重新再次初始化设备,这次是以rejoin的方式来初始化设备的。其实在这里只是启动一个网络扫描而已: NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
..........
if ( ZG_BUILD_JOINING_TYPE && (logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE) )
{
if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) ) //根据当前启动模式是连接或者重连模式则启动一个网络扫描
{
devState = DEV_NWK_DISC; #if defined( MANAGED_SCAN )
ZDOManagedScan_Next();
ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC );
#else
ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );//启动网络扫描请求
#if defined ( ZIGBEE_FREQ_AGILITY )
if ( !( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE ) &&
( ret == ZSuccess ) && ( ++discRetries == 4 ) )
{
// For devices with RxOnWhenIdle equals to FALSE, any network channel
// change will not be recieved. On these devices or routers that have
// lost the network, an active scan shall be conducted on the Default
// Channel list using the extended PANID to find the network. If the
// extended PANID isn't found using the Default Channel list, an scan
// should be completed using all channels.
zgDefaultChannelList = MAX_CHANNELS_24GHZ;
}
#endif // ZIGBEE_FREQ_AGILITY
#if defined ( ZIGBEE_COMMISSIONING )
if (startMode == MODE_REJOIN && scanCnt++ >= 5 )
{
// When ApsUseExtendedPanID is commissioned to a non zero value via
// application specific means, the device shall conduct an active scan
// on the Default Channel list and join the PAN with the same
// ExtendedPanID. If the PAN is not found, an scan should be completed
// on all channels.
// When devices rejoin the network and the PAN is not found from
zgDefaultChannelList = MAX_CHANNELS_24GHZ;
}
#endif // ZIGBEE_COMMISSIONING
#endif
}
.......
if ( ret != ZSuccess )
{
osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
}
}
(5)有设备接入则会调用回调函数:ZDO_NetworkDiscoveryConfirmCB(uint8 status),在这个回调函数会产生ZDO_NWK_DISC_CNF事件。然后在void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )里面处理该事件,重连过程中会从NV中读取panid等数据, 最后发出重新连接的申请NLME_ NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel);
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
…….
switch ( msgPtr->event )
{
………..
case ZDO_NWK_DISC_CNF:
if (devState != DEV_NWK_DISC)
break;
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
// Process the network discovery scan results and choose a parent
// device to join/rejoin itself
networkDesc_t *pChosenNwk;
if ( ( (pChosenNwk = ZDApp_NwkDescListProcessing()) != NULL ) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
{
if ( devStartMode == MODE_JOIN )
{
devState = DEV_NWK_JOINING;
ZDApp_NodeProfileSync( pChosenNwk->stackProfile);
if ( NLME_JoinRequest( pChosenNwk->extendedPANID, pChosenNwk->panId,
pChosenNwk->logicalChannel,
ZDO_Config_Node_Descriptor.CapabilityFlags,
pChosenNwk->chosenRouter, pChosenNwk->chosenRouterDepth ) != ZSuccess )
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
} // if ( devStartMode == MODE_JOIN )
else if ( devStartMode == MODE_REJOIN )//重连的处理
{
ZStatus_t rejoinStatus; devState = DEV_NWK_REJOIN; // Before trying to do rejoin, check if the device has a valid short address
// If not, generate a random short address for itself
if ( _NIB.nwkDevAddress == INVALID_NODE_ADDR )
{
uint16 commNwkAddr;
//从NV里面读取网络信息
// Verify if the Network address has been commissioned by external tool
if ( ( osal_nv_read( ZCD_NV_COMMISSIONED_NWK_ADDR, 0,
sizeof(commNwkAddr),
(void*)&commNwkAddr ) == ZSUCCESS ) &&
( commNwkAddr != INVALID_NODE_ADDR ) )
{
_NIB.nwkDevAddress = commNwkAddr; // clear Allocate address bit because device has a commissioned address
_NIB.CapabilityFlags &= ~CAPINFO_ALLOC_ADDR;
}
else
{
_NIB.nwkDevAddress = osal_rand();
}
ZMacSetReq( ZMacShortAddress, (byte*)&_NIB.nwkDevAddress );
} // Check if the device has a valid PanID, if not, set it to the discovered Pan
if ( _NIB.nwkPanId == INVALID_PAN_ID )
{
_NIB.nwkPanId = pChosenNwk->panId;
ZMacSetReq( ZMacPanId, (byte*)&(_NIB.nwkPanId) );//设置新的panID到NV里面
} tmp = true;
ZMacSetReq( ZMacRxOnIdle, &tmp ); // Set receiver always on during rejoin // Perform Secure or Unsecure Rejoin depending on available configuration
if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey() == TRUE ) )
{
rejoinStatus = NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); //发出重新连接的申请
}
else
{
rejoinStatus = NLME_ReJoinRequestUnsecure( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel); //发出重新连接的申请
}
if ( rejoinStatus != ZSuccess )
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
} // else if ( devStartMode == MODE_REJOIN )
// The receiver is on, turn network layer polling off.
...........
}
}
else
{
if ( continueJoining )
{
zdoDiscCounter++;
ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY
+ ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) );
#endif
}
}
}
break;
..........
}
}
(6)设备入网成功会调用入网成功的回调函数ZDO_JoinConfirmCB(uint16 PanId, ZStatus_t Status),接着声明本设备的短地址(这样协调器才知道设备入网成功),并产生ZDO_STATE_CHANGE_EVT网络改变的事件。devState 的状态是在void ZDO_JoinConfirmCB( )里面改变的,ZDApp_ProcessNetworkJoin( void )里面才会处理入网成功。
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
{
(void)PanId; // remove if this parameter is used.
nwkStatus = (byte)Status; if ( Status == ZSUCCESS )
{
if ( ZSTACK_END_DEVICE_BUILD
|| (ZSTACK_ROUTER_BUILD && ((_NIB.CapabilityFlags & ZMAC_ASSOC_CAPINFO_FFD_TYPE) == 0)))
{
neighborEntry_t *pItem; // We don't need the neighbor table entries.
// Clear the neighbor Table to remove beacon information
nwkNeighborInitTable(); // Force a neighbor table entry for the parent
pItem = nwkNeighborFindEmptySlot();
if ( pItem != NULL )
{
osal_memset( pItem, 0x00, sizeof ( neighborEntry_t ) );
pItem->neighborAddress = _NIB.nwkCoordAddress;
osal_cpyExtAddr( pItem ->neighborExtAddr, _NIB. nwkCoordExtAddress );
pItem->panId = _NIB. nwkPanId;
pItem->linkInfo.rxLqi = DEF_LQI;
pItem->linkInfo.txCounter = DEF_LINK_COUNTER;
pItem->linkInfo.txCost = DEF_LINK_COST;
}
}
if ( (devState == DEV_HOLD) )
{
// Began with HOLD_AUTO_START
devState = DEV_NWK_JOINING;//改变devState状态,代表入网已经成功
} if ( !ZG_SECURE_ENABLED )
{
// Notify to save info into NV
ZDApp_NVUpdate();
}
}
else
{
} // Pass the join confirm to higher layer if callback registered
if (zdoCBFunc[ZDO_JOIN_CNF_CBID] != NULL )
{
zdoJoinCnf_t joinCnf; joinCnf.status = Status;
joinCnf.deviceAddr = _NIB.nwkDevAddress;
joinCnf.parentAddr = _NIB.nwkCoordAddress;
zdoCBFunc[ZDO_JOIN_CNF_CBID]( (void*)&joinCnf );
} // Notify ZDApp
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND, sizeof(osal_event_hdr_t), (byte*)NULL );
} //入网成功的处理
void ZDApp_ProcessNetworkJoin( void )
{
if ( (devState == DEV_NWK_JOINING) ||
((devState == DEV_NWK_ORPHAN) &&
(ZDO_Config_Node_Descriptor.LogicalType == NODETYPE_ROUTER)) )
{
}else if( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_REJOIN ){
.........
else //该处暗含:if(devState == DEV_NWK_JOINING)
{
// Assume from address conflict
if ( _NIB.nwkAddrAlloc == NWK_ADDRESSING_STOCHASTIC )
{
// Notify the network
ZDApp_AnnounceNewAddress();//声明本设备的短地址 // Notify apps
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );//告知网络状态改变
}
}
}
4.zigbee重连失败分析。
(1)重连成功与重连失败首先要用抓包工具Packet Sniffer来分析
下面是重连成功的图:能看的的数据包是===》Beancon Request==>协调器的回应包==》终端的NWK Rejoin Request 数据包 ===》终端的Data Request ==》协调器回应 NWK Rejoin Response包
下面是重连失败的图:能看到的数据包是 ===》Beancon Request==>协调器的回应包==》终端的NWK Rejoin Request 数据包 ===》 Beancon Request
*从上面的数据包对比可知,重连失败的数据包没有=》终端的Data Request《=, 这样导致终端无法得知之前连接的设备是否还在线,那么终端只能认为该网络是全新的网络,需要重新连接,不能重连旧设备。
接下来要查明为什么不发Data Request的包,查看代码发现某个地方设置不查询数据NLME_SetPollRate(0);当时写这行代码是为了zigbee设备能够更好的休眠,尽量减少数据的发送,故关闭数据轮询。把NLME_SetPollRate(0)注释掉即可解决问题,重启协调器,终端能够正常地重连到协调器上。
【转】zigbee终端无法重连的问题解决的更多相关文章
- 【转】ZigBee终端入网方式深入分析
前述 继之前对终端Direct Join的分析,发现很多东西还很模糊,存在很多问题.终于找到时间继续深入挖下去,这次应该比较完整地搞清了终端的入网机制,并纠正之前的几个认识偏差. 由于Z-Stack网 ...
- android 实现mqtt消息推送,以及不停断线重连的问题解决
前段时间项目用到mqtt的消息推送,整理一下代码,代码的原型是网上找的,具体哪个地址已经忘记了. 代码的实现是新建了一个MyMqttService,全部功能都在里面实现,包括连服务器,断线重连,订阅消 ...
- 终端下vim无法输入问题解决
最近回归vim时发现会偶尔出现vim无法输入,但光标在动的情况,一度怀疑是spf13的问题,后来经搜索,才发现是因为vim下,快捷键 Ctrl+s 的功能是停止输入,在IDE下编程时间长了,都有潜意识 ...
- FreeBSD 的xfce 终端动态标题不显示问题解决了:
tcsh配置,home目录创建.tcshrc, 写入以下配置 alias h history 25 alias j jobs -l alias la ls -aF alias lf ls -FA al ...
- zigbee
IEEE802.15.4定义了两种器件:全功能器件(FFD,Full-FunctionDevice),和简化功能器件(RFD,Reduced-functionDevice) 协调器:(coordina ...
- Ubuntu安装VMware Tools的方法
最后我将提供一个12版本的VMware Tools集合,包括了linux.iso. 背景: VMware Tools是VMware虚拟机中自带的一种增强工具,相当于VirtualBox中的增强功能(S ...
- 不同Mesh技术的比较-总结版
引言 在过去的几年里,Mesh 网络逐渐变得流行,随之会有越来越多的无线产品面世.Mesh 网络技术作为一种无线自组网技术是物联网的核心技术.物联网的概念现在也逐渐贴近人们的生活, 据预测 2011 ...
- Hbase shell详情
HBase 为用户提供了一个非常方便的使用方式, 我们称之为“HBase Shell”.HBase Shell 提供了大多数的 HBase 命令, 通过 HBase Shell 用户可以方便地创建.删 ...
- hbase shell下如何使用删除键
今天刚安装好了hbase,通过Secure CRT登录hbase shell,敲入错误命令无法使用删除键(Backspace或是Ctrl+Backspace都不管用)删除,后来在终端-->仿真下 ...
随机推荐
- 代码的坏味道(22)——不完美的库类(Incomplete Library Class)
坏味道--不完美的库类(Incomplete Library Class) 特征 当一个类库已经不能满足实际需要时,你就不得不改变这个库(如果这个库是只读的,那就没辙了). 问题原因 许多编程技术都建 ...
- ASP.NET MVC原理
仅此一文让你明白ASP.NET MVC原理 ASP.NET MVC由以下两个核心组成部分构成: 一个名为UrlRoutingModule的自定义HttpModule,用来解析Controller与 ...
- bzoj3208--记忆化搜索
题目大意: 花花山峰峦起伏,峰顶常年被雪,Memphis打算帮花花山风景区的人员开发一个滑雪项目. 我们可以把风景区看作一个n*n的地图,每个点有它的初始高度,滑雪只能从高处往低处滑[严格大于] ...
- DB2重启数据库实例
DB2重启数据库实例时,有时停止实例会失败,此时需要先确认没有应用链接数据库,然后再关闭数据库实例,并重新启动. 1.查看是否有活动的链接 命令:db2 list applications for d ...
- MySQL 优化之 MRR (Multi-Range Read:二级索引合并回表)
MySQL5.6中引入了MRR,专门来优化:二级索引的范围扫描并且需要回表的情况.它的原理是,将多个需要回表的二级索引根据主键进行排序,然后一起回表,将原来的回表时进行的随机IO,转变成顺序IO.文档 ...
- U盘安装Kali 出现cd-rom无法挂载 已解决
用U盘安装Kali Linux的过程中,出现cd-rom无法挂载的现象,百度坑比啊,醉了.下面亲测成功 出现无法挂载后,选择执行shell 第一步:df -m此时会看到挂载信息,最下面的是/dev/* ...
- 解除win7网络限速.
在电脑刚买或者系统重装了的时候,win7系统会默认限制20%的网络速度,限制了我们的上网速度,我们可以解决这个限制,让上网变得更快 下面是操作步骤 1.开始>运行 2.输入以下命令,然后确定 g ...
- 在rem布局下使用背景图片以及sprite
现在移动端页面用rem布局已经是一大流派了,成熟的框架如淘宝的flexiable.js,以及我的好友@墨尘写的更轻量级的hotcss.用rem作单位使得元素能够自适应后,还有一块需要关注的,那就是背景 ...
- ASP.NET MVC 视图(五)
ASP.NET MVC 视图(五) 前言 上篇讲解了视图中的分段概念.和分部视图的使用,本篇将会对Razor的基础语法简洁的说明一下,前面的很多篇幅中都有涉及到视图的调用,其中用了很多视图辅助器,也就 ...
- CSharpGL(28)得到高精度可定制字形贴图的极简方法
CSharpGL(28)得到高精度可定制字形贴图的极简方法 回顾 以前我用SharpFont实现了解析TTF文件从而获取字形贴图的功能,并最终实现了用OpenGL渲染文字. 使用SharpFont,美 ...