终端无法接收到单播数据
我把 f8wConfig.cfg文件中
-DRFD_RCVC_ALWAYS_ON 设置为 TURE
这样当有群组或广播消息时,由于接收机是一直打开着的,终端就可以马上接收到该消息,
而不需要发送data.request到父节点查询是否有发送给自己的数据.这个方法虽然增加了
终端的功耗,但是能达到网络中多有设备接收到组播消息时能同时动作的效果....
但是我发现当我这样设置的后,使发送方与接收方中间放置一个路由器,并确保发送方信号
无法直接到达到发送端,问题就来了.(所有节点使用的配置文件都是同一个f8wConfig.cfg文件)
我发送组播消息,接收方能接收得到,但是发送单播 消息时,接收方却无法接收到了!
组播消息路由器不会保存,而是直接转发,所以终端就能接收的到数据.这很好理解.单播无法接收我猜想是由于上级路由虽然接收到了发送给子节点的消息但是他不是立即发送给终端的,而是由终端发送data.request命令给给该路由,路由器再转发该数据包给终端,
设置后用协议分析仪看了终端发送出来的数据包,发现终端确实没有发送data_request,所以导致了终端无法接收到单播数据.
看过了代码,
在文件ZDConfig.c中
void ZDConfig_UpdateNodeDescriptor( void )
{
// Build the Node Descriptor
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
else if ( ZSTACK_ROUTER_BUILD )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER;
else if ( ZSTACK_END_DEVICE_BUILD )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICE;
ZDO_Config_Node_Descriptor.ComplexDescAvail = FALSE; // set elsewhere
ZDO_Config_Node_Descriptor.UserDescAvail = FALSE; // set elsewhere
ZDO_Config_Node_Descriptor.Reserved = 0; // Reserved
ZDO_Config_Node_Descriptor.APSFlags = 0; // NO APS flags
ZDO_Config_Node_Descriptor.FrequencyBand = NODEFREQ_2400; // Frequency Band
// MAC Capabilities
if ( ZSTACK_ROUTER_BUILD )
{
ZDO_Config_Node_Descriptor.CapabilityFlags
= (CAPINFO_DEVICETYPE_FFD | CAPINFO_POWER_AC | CAPINFO_RCVR_ON_IDLE);
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
ZDO_Config_Node_Descriptor.CapabilityFlags |= CAPINFO_ALTPANCOORD;
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
ZDO_Config_Node_Descriptor.CapabilityFlags = (CAPINFO_DEVICETYPE_RFD
#if ( RFD_RCVC_ALWAYS_ON == TRUE)
| CAPINFO_RCVR_ON_IDLE
#endif
);
}
// Manufacturer Code - *YOU FILL IN*
ZDO_Config_Node_Descriptor.ManufacturerCode[0] = 0;
ZDO_Config_Node_Descriptor.ManufacturerCode[1] = 0;
// Maximum Buffer Size
ZDO_Config_Node_Descriptor.MaxBufferSize = MAX_BUFFER_SIZE;
// Maximum Incoming Transfer Size Field
ZDO_Config_Node_Descriptor.MaxInTransferSize[0] = LO_UINT16( MAX_TRANSFER_SIZE );
ZDO_Config_Node_Descriptor.MaxInTransferSize[1] = HI_UINT16( MAX_TRANSFER_SIZE );
// Maximum Outgoing Transfer Size Field
ZDO_Config_Node_Descriptor.MaxOutTransferSize[0] = LO_UINT16( MAX_TRANSFER_SIZE );
ZDO_Config_Node_Descriptor.MaxOutTransferSize[1] = HI_UINT16( MAX_TRANSFER_SIZE );
// Server Mask
ZDO_Config_Node_Descriptor.ServerMask = 0;
// Descriptor Capability Field - extended active endpoint list and
// extended simple descriptor are not supported.
ZDO_Config_Node_Descriptor.DescriptorCapability = 0;
}
可以看到在终端类型的节点功能描述域使能了
CAPINFO_RCVR_ON_IDLE
继续跟踪CAPINFO_RCVR_ON_IDLE
在函数
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
// Data Confirmation message fields
uint8 sentEP; // This should always be 0
uint8 sentStatus;
afDataConfirm_t *afDataConfirm;
uint8 tmp;
switch ( msgPtr->event )
{
// Incoming ZDO Message
case AF_INCOMING_MSG_CMD:
ZDP_IncomingData( (afIncomingMSGPacket_t *)msgPtr );
break;
case ZDO_CB_MSG:
ZDApp_ProcessMsgCBs( (zdoIncomingMsg_t *)msgPtr );
break;
case AF_DATA_CONFIRM_CMD:
// This message is received as a confirmation of a data packet sent.
// The status is of ZStatus_t type [defined in NLMEDE.h]
// The message fields are defined in AF.h
afDataConfirm = (afDataConfirm_t *)msgPtr;
sentEP = afDataConfirm->endpoint;
sentStatus = afDataConfirm->hdr.status;
// Action taken when confirmation is received.
#if defined ( ZIGBEE_FREQ_AGILITY )
if ( pZDNwkMgr_ProcessDataConfirm )
pZDNwkMgr_ProcessDataConfirm( afDataConfirm );
#endif
(void)sentEP;
(void)sentStatus;
break;
case ZDO_NWK_DISC_CNF:
if (devState != DEV_NWK_DISC)
break;
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
if ( (((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->hdr.status == ZDO_SUCCESS) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
{
if ( devStartMode == MODE_JOIN )
{
devState = DEV_NWK_JOINING;
ZDApp_NodeProfileSync((ZDO_NetworkDiscoveryCfm_t *)msgPtr);
if ( NLME_JoinRequest( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->extendedPANID,
BUILD_UINT16( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdLSB, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdMSB ),
((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->logicalChannel,
ZDO_Config_Node_Descriptor.CapabilityFlags ) != ZSuccess )
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
}
else if ( devStartMode == MODE_REJOIN )
{
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 )
{
_NIB.nwkDevAddress = osal_rand();
ZMacSetReq( ZMacShortAddress, (byte*)&_NIB.nwkDevAddress );
}
if ( ZG_SECURE_ENABLED )
{
ZDApp_RestoreNwkKey();
}
// Check if the device has a valid PanID, if not, set it to the discovered Pan
if ( _NIB.nwkPanId == INVALID_PAN_ID )
{
_NIB.nwkPanId = BUILD_UINT16( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdLSB, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdMSB );
ZMacSetReq( ZMacPanId, (byte*)&(_NIB.nwkPanId) );
}
tmp = true;
ZMacSetReq( ZMacRxOnIdle, &tmp ); // Set receiver always on during rejoin
if ( NLME_ReJoinRequest( ZDO_UseExtendedPANID, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->logicalChannel) != ZSuccess )
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
}
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
{
// The receiver is on, turn network layer polling off.
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
}
else
{
if ( (ZG_SECURE_ENABLED) && (devStartMode == MODE_JOIN) )
{
ZDApp_SavedPollRate = zgPollRate;
NLME_SetPollRate( zgRejoinPollRate );
}
}
}
else
{
if ( continueJoining )
{
#if defined ( MANAGED_SCAN )
ZDApp_NetworkInit( MANAGEDSCAN_DELAY_BETWEEN_SCANS );
#else
zdoDiscCounter++;
ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY
+ ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) );
#endif
}
}
}
break;
case ZDO_NWK_JOIN_IND:
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
ZDApp_ProcessNetworkJoin();
}
break;
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 );
zgDefaultStartingScanDuration = BEACON_ORDER_60_MSEC;
ZDApp_NetworkInit( 0 );
}
break;
default:
if ( ZG_SECURE_ENABLED )
ZDApp_ProcessSecMsg( msgPtr );
break;
}
}
函数中有事件类型为
case ZDO_NWK_DISC_CNF:
if (devState != DEV_NWK_DISC)
break;
的分支.该分支中对节点功能域进行了判断和处理
// The receiver is on, turn network layer polling off.
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
可以发现,由于CAPINFO_RCVR_ON_IDLE域的使能,终端设备的轮询功能都被关闭,
这就是导致终端没有发送 data_request的原因.
把该处的三个函数参数改为 f8wConfig.cfg 中规定的值即可.
这样发送给终端的单播数据就可以正常接收到了,到了这里貌似问题就解决了!