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 len
SrcAddress,源地址,包括如下东东
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