zigbee 空中消息溯源
消息发送到空中:
/*********************************************************************
* @fn AF_DataRequest
*
* @brief Common functionality for invoking APSDE_DataReq() for both
* SendMulti and MSG-Send.
*
* input parameters
*
* @param *dstAddr - Full ZB destination address: Nwk Addr + End Point.
* @param *srcEP - Origination (i.e. respond to or ack to) End Point Descr.
* @param cID - A valid cluster ID as specified by the Profile.
* @param len - Number of bytes of data pointed to by next param.
* @param *buf - A pointer to the data bytes to send.
* @param *transID - A pointer to a byte which can be modified and which will
* be used as the transaction sequence number of the msg.
* @param options - Valid bit mask of Tx options.
* @param radius - Normally set to AF_DEFAULT_RADIUS.
*
* output parameters
*
* @param *transID - Incremented by one if the return value is success.
*
* @return afStatus_t - See previous definition of afStatus_... types.
*/
uint8 AF_DataRequestDiscoverRoute = TRUE;
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
uint8 options, uint8 radius )
{
pDescCB pfnDescCB;
ZStatus_t stat;
APSDE_DataReq_t req;
afDataReqMTU_t mtu;
// Verify source end point
if ( srcEP == NULL )
{
return afStatus_INVALID_PARAMETER;
}
#if !defined( REFLECTOR )
if ( dstAddr->addrMode == afAddrNotPresent )
{
return afStatus_INVALID_PARAMETER;
}
#endif
// Validate broadcasting
if ( ( dstAddr->addrMode == afAddr16Bit ) ||
( dstAddr->addrMode == afAddrBroadcast ) )
{
// Check for valid broadcast values
if( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( dstAddr->addr.shortAddr ) )
{
// Force mode to broadcast
dstAddr->addrMode = afAddrBroadcast;
}
else
{
// Address is not a valid broadcast type
if ( dstAddr->addrMode == afAddrBroadcast )
{
return afStatus_INVALID_PARAMETER;
}
}
}
else if ( dstAddr->addrMode != afAddr64Bit &&
dstAddr->addrMode != afAddrGroup &&
dstAddr->addrMode != afAddrNotPresent )
{
return afStatus_INVALID_PARAMETER;
}
// Set destination address
req.dstAddr.addrMode = dstAddr->addrMode;
if ( dstAddr->addrMode == afAddr64Bit )
osal_cpyExtAddr( req.dstAddr.addr.extAddr, dstAddr->addr.extAddr );//数组 所以拷贝
else
req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr;//数字,直接赋值
req.profileID = ZDO_PROFILE_ID;
if ( (pfnDescCB = afGetDescCB( srcEP )) )
{
uint16 *pID = (uint16 *)(pfnDescCB(
AF_DESCRIPTOR_PROFILE_ID, srcEP->endPoint ));
if ( pID )
{
req.profileID = *pID;
osal_mem_free( pID );
}
}
else if ( srcEP->simpleDesc )
{
req.profileID = srcEP->simpleDesc->AppProfId;
}
req.txOptions = 0;
if ( ( options & AF_ACK_REQUEST ) &&
( req.dstAddr.addrMode != AddrBroadcast ) &&
( req.dstAddr.addrMode != AddrGroup ) )
{
req.txOptions |= APS_TX_OPTIONS_ACK;
}
if ( options & AF_SKIP_ROUTING )
{
req.txOptions |= APS_TX_OPTIONS_SKIP_ROUTING;
}
if ( options & AF_EN_SECURITY )
{
req.txOptions |= APS_TX_OPTIONS_SECURITY_ENABLE;
mtu.aps.secure = TRUE;
}
else
{
mtu.aps.secure = FALSE;
}
mtu.kvp = FALSE;
req.transID = *transID;
req.srcEP = srcEP->endPoint;
req.dstEP = dstAddr->endPoint;
req.clusterID = cID;
req.asduLen = len;
req.asdu = buf;
req.discoverRoute = AF_DataRequestDiscoverRoute;//(uint8)((options & AF_DISCV_ROUTE) ? 1 : 0);
req.radiusCounter = radius;
#if defined ( INTER_PAN )
req.dstPanId = dstAddr->panId;
if ( StubAPS_InterPan( dstAddr->panId, dstAddr->endPoint ) )
{
if ( len > INTERP_DataReqMTU() )
{
stat = afStatus_INVALID_PARAMETER;
}
else
{
stat = INTERP_DataReq( &req );
}
}
else
#endif // INTER_PAN
{
if (len > afDataReqMTU( &mtu ) )
{
if (apsfSendFragmented)
{
stat = (*apsfSendFragmented)( &req );
}
else
{
stat = afStatus_INVALID_PARAMETER;
}
}
else
{
stat = APSDE_DataReq( &req );
}
}
/*
* If this is an EndPoint-to-EndPoint message on the same device, it will not
* get added to the NWK databufs. So it will not go OTA and it will not get
* a MACCB_DATA_CONFIRM_CMD callback. Thus it is necessary to generate the
* AF_DATA_CONFIRM_CMD here. Note that APSDE_DataConfirm() only generates one
* message with the first in line TransSeqNumber, even on a multi message.
* Also note that a reflected msg will not have its confirmation generated
* here.
*/
if ( (req.dstAddr.addrMode == Addr16Bit) &&
(req.dstAddr.addr.shortAddr == NLME_GetShortAddr()) )
{
afDataConfirm( srcEP->endPoint, *transID, stat );
}
if ( stat == afStatus_SUCCESS )
{
(*transID)++;
}
return (afStatus_t)stat;
}指定要发送到的目标地址dstAddr,包括目的网络号,目的短地址或长地址,目的端点
typedef struct
{
union
{
uint16 shortAddr;
ZLongAddr_t extAddr;
} addr;
afAddrMode_t addrMode;
byte endPoint;
uint16 panId; // used for the INTER_PAN feature
} afAddrType_t;
指定发送的clustid,cID指定要发送的数据长度,len
指定要发送的数据,buf,即asdu,应用层负载
指定发送选项options,比如是否加密 AF_SKIP_ROUTING
要向对方说明本地端点描述符:srcEP
typedef struct
{
byte endPoint;
byte *task_id; // Pointer to location of the Application task ID.
SimpleDescriptionFormat_t *simpleDesc;
afNetworkLatencyReq_t latencyReq;
} endPointDesc_t;其实只用到了结构体里的两个东东req.profileID = srcEP->simpleDesc->AppProfId;
req.srcEP = srcEP->endPoint;
空中到来的消息:
/*********************************************************************
* @fn afIncomingData
*
* @brief Transfer a data PDU (ASDU) from the APS sub-layer to the AF.
*
* @param aff - pointer to APS frame format
* @param SrcAddress - Source address
* @param sig - incoming message's link quality
* @param SecurityUse - Security enable/disable
*
* @return none
*/
void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,
NLDE_Signal_t *sig, byte SecurityUse, uint32 timestamp )
{
endPointDesc_t *epDesc = NULL;
uint16 epProfileID = 0xFFFF; // Invalid Profile ID
epList_t *pList = epList;
#if !defined ( APS_NO_GROUPS )
uint8 grpEp = APS_GROUPS_EP_NOT_FOUND;
#endif
if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
{
#if !defined ( APS_NO_GROUPS )
// Find the first endpoint for this group
grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST );
if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
return; // No endpoint found
epDesc = afFindEndPointDesc( grpEp );
if ( epDesc == NULL )
return; // Endpoint descriptor not found
pList = afFindEndPointDescList( epDesc->endPoint );
#else
return; // Not supported
#endif
}
else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
{
// Set the list
if ( pList != NULL )
{
epDesc = pList->epDesc;
}
}
else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) )
{
pList = afFindEndPointDescList( epDesc->endPoint );
}
while ( epDesc )
{
if ( pList->pfnDescCB )
{
uint16 *pID = (uint16 *)(pList->pfnDescCB(
AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint ));
if ( pID )
{
epProfileID = *pID;
osal_mem_free( pID );
}
}
else if ( epDesc->simpleDesc )
{
epProfileID = epDesc->simpleDesc->AppProfId;
}
if ( (aff->ProfileID == epProfileID) ||
((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) )
{
{
afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig, SecurityUse, timestamp );
}
}
if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
{
#if !defined ( APS_NO_GROUPS )
// Find the next endpoint for this group
grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp );
if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
return; // No endpoint found
epDesc = afFindEndPointDesc( grpEp );
if ( epDesc == NULL )
return; // Endpoint descriptor not found
pList = afFindEndPointDescList( epDesc->endPoint );
#else
return;
#endif
}
else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
{
pList = pList->nextDesc;
if ( pList )
epDesc = pList->epDesc;
else
epDesc = NULL;
}
else
epDesc = NULL;
}
}
空中到来的消息经过协议栈的秘密传输,终于在af中被暴露出来,
aff,接收到的aps层帧结构,包括如下信息
typedef struct
{
byte FrmCtrl;
byte XtndFrmCtrl;
byte DstEndPoint;
byte SrcEndPoint;
uint16 GroupID;
uint16 ClusterID;
uint16 ProfileID;
uint16 macDestAddr;
byte wasBroadcast;
byte apsHdrLen;
byte *asdu;
byte asduLength;
byte ApsCounter;
uint8 transID;
uint8 BlkCount;
uint8 AckBits;
} aps_FrameFormat_t;
其中重要信息有:目的端点,源端点,组号,clustid,profileid,asdu(应用层负载),asdu lenSrcAddress,源地址,包括如下东东
typedef struct
{
union
{
uint16 shortAddr;
ZLongAddr_t extAddr;
} addr;
byte addrMode;
} zAddrType_t;SrcPanId,源网络号
sig,信号强度
SecurityUse,是否加密
timestamp,时间戳
可见,除了SrcPanId,sig,timestamp这几个元素是下层自动添加的,其他参数和使用afIncomingData发送过来的参数对应。
以下待续:
绑定是
源端点《--》目的地址+目的端点
每次建立一个绑定,都会在自身设备中创建一条这样的记录,
这样以后在发送数据的时候,只要指定源端点,而不必指定目的地址和目的端点,协议栈会从绑定表中直接读取出来目的地址和目的端点,将数据发给他们
而设备接收时,就跟平常一样接收就行。
但是还有一个clusterlist,似乎有点疑惑?答案:
1.绑定时使用的如果是clusterlist,双方可以通过绑定方式进行clusterid属于clusterlist的数据通信
2.双方简单描述符里的对应clusterlist都有同一个clusterid,则可以通过指定地址方式进行此clusterid的数据通信。
3.一般发命令的是outclusterlist,接收命令并回应的是inclusterlist,但是实验中发现没有这个规定。只要双方通信端点的clusterlist的方向相反,内容一样就可以对clusterlist的clusterid通信。
http://blog.csdn.net/songqqnew/article/details/8684315
浙公网安备 33010602011771号