zigbee保持常连接的实现方法

xiaoxiao2021-02-27  290

一、前言

        终端在第一次连接的时候通常会发一个连接请求(beacon request)给协调器,协调器接受到它的请求后就会给它分配一个短地址,后续通讯的时候终端只需要拿短地址和协调器通讯即可。实际上终端遇到特殊情况是会和协调器发起重连的:1.终端重上电的时候。2.协调器重上电的时候。3.终端离开网络后又重新加入网络。而重连的时候终端和协调器会进行大量数据的交互,从重连到正常发送数据需要一定时间,而且重连对通讯信号强度有要求,信号不好的时候重连会失败。而公司的终端设备是一个低功耗设备,发送完数据就必需进入休眠状态,而且设备之间有金属板阻隔,信号不太强,而且限制重连的时候只发送一个beacon request,所以一般要重连几次才连上,信号不好的情况甚至很难重连。

二、zigbee保持常连接的方法

       zigbee之所以需要重连,个人认为是为了实现自组网和网络自愈的能力,当与终端最近的节点断开了,终端可以通过重连的方式去连接另外一个节点,网络就会重新恢复。代价就是在重连的过程中无法控制设备。还有在星型接的网络里面,重连其实是没必要的,反而增加了网络负担。我想要的效果是只要网络一通就能控制设备,显然利用原有的zigbee协议栈是满足不了要求的,需要更改zigbee协议栈。用抓包工具分析zigbee在断开网络的数据帧,发现网络重连是由终端发起的,因为终端有些是休眠设备,一旦休眠了,协调器是探测不到的,所以问题解决的方向是不让终端发起重连请求。还有一个关键点是终端断开连接的时候会发送一个声明“我是孤儿节点,谁来领养我”,那么可以推理去掉这部分代码应该可以实现不重连。

       这部分源代码在ZDObject.c文件里面,注释掉两行代码即可“

//devState = DEV_NWK_ORPHAN; //---long modify 20170503 //ret = NLME_OrphanJoinRequest( zgDefaultChannelList,zgDefaultStartingScanDuration );”源码如下:

/********************************************************************* * @fn ZDO_StartDevice * * @brief This function starts a device in a network. * * @param logicalType - Device type to start //设备种类:协调器,路由器,终端 * startMode - indicates mode of device startup //启动的模式MODE_JOIN,MODE_RESUME,MODE_HARD,MODE_REJOIN * beaconOrder - indicates time betwen beacons * superframeOrder - indicates length of active superframe * @return none */ void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder ) { ZStatus_t ret; #if defined ( ZIGBEE_FREQ_AGILITY ) static uint8 discRetries = 0; #endif #if defined ( ZIGBEE_COMMISSIONING ) static uint8 scanCnt = 0; #endif ret = ZUnsupportedMode; if ( ZG_BUILD_COORDINATOR_TYPE && logicalType == NODETYPE_COORDINATOR ) { if ( startMode == MODE_HARD ) { devState = DEV_COORD_STARTING; ret = NLME_NetworkFormationRequest( zgConfigPANID, zgApsUseExtendedPANID, zgDefaultChannelList, zgDefaultStartingScanDuration, beaconOrder, superframeOrder, false ); } else if ( startMode == MODE_RESUME ) { // Just start the coordinator devState = DEV_COORD_STARTING; ret = NLME_StartRouterRequest( beaconOrder, beaconOrder, false ); } else { #if defined( LCD_SUPPORTED ) HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" ); #endif } } 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 } 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 { ret = ZSuccess; //--long add 20170503 //devState = DEV_NWK_ORPHAN; //---long modify 20170503 //ret = NLME_OrphanJoinRequest( zgDefaultChannelList,zgDefaultStartingScanDuration ); } } else { #if defined( LCD_SUPPORTED ) HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" ); #endif } } if ( ret != ZSuccess ) { osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY ); } } 三、测试结果

       测试发现无论协调器重启,终端重启,终端重新进入网络都不会重连,协调器不在线的情况下,终端也只会重发几次而已,但是设备控制起来体验好多了,不会出现有时候由于网络不好需要控制好几次的问题。还需要注意的是该方法需要开启存储功能,把第一次和协调器组网的信息记录下来下次发送数据直接用协调器分配的短地址进行通讯即可。设置方法如下:

转载请注明原文地址: https://www.6miu.com/read-1980.html

最新回复(0)