1、再谈 ZigBee 中的绑定机制这里主要再讨论一下绑定的机制,绑定是 ZigBee 中应该是比较重要的一个部分。前面的几篇文章也对绑定有了具体的分析,主要分析了两种绑定方式,介绍了绑定的流程,源代码方面。这里主要是理清整个绑定在组网中的概念。绑定是和 EndPoint 紧密联系在一起的,其中很多是自己通过看资料,自己的一些理解,当中肯定有不正确的地方,欢迎有兴趣的一起讨论。ZigBee 中还有一个重要的概念端点,理解的不是很清楚,现在再一次总结分析一下,端点是应用对象存在的地方,ZigBee 允许多个应用同时位于一个节点上,例如一个节点具有控制灯光的功能,又具有感应温度的功能,又具有收发文本消
2、息的功能,这种设计有利于复杂 ZigBee 设备的出现。我们可以从 ZigBee 的体系结构图中可以看到可以有 240 个应用,也就是说一个物理的ZigBee 设备的话,可以有 240 个具体的应用,例如上面提到的其中的三种具体的应用。一共有二个特殊的端点,即端点 0 和端点 255。端点 0 用于整个 ZigBee 设备的配置和管理。应用程序可以透过端点 0 与 ZigBee 堆栈的其它层通讯,因而实现对这些层的初始化和配置。附属在端点 0 的对象被称为 ZigBee 设备对象(ZDO)。端点 255 用于向所有端点的广播。端点 241 到 254 是保留端点。 所有端点都使用应用支持子层(
3、APS)提供的服务。APS 透过网络层和安全服务提供层与端点相接,并为数据传送、安全和固定服务,因此能够适配不同但兼容的设备,如带灯的开关。 下面是终端的描述符的结构体定义。typedef structbyte endPoint; /EP 号byte *task_id; / 指向任务编号的指针.SimpleDescriptionFormat_t *simpleDesc; /设备的简单描述afNetworkLatencyReq_t latencyReq; /枚举类型 endPointDesc_t;/设备的简单描述结构typedef structbyte EndPoint; /EPIDuint16
4、 AppProfId; / Profile IDuint16 AppDeviceId; / Device IDbyte AppDevVer:4; / Device Versionbyte Reserved:4; /AF_V1_SUPPORT uses for AppFlags:4. Reservedbyte AppNumInClusters; /输入命令个数cId_t *pAppInClusterList; /输入命令列表byte AppNumOutClusters; /输出命令个数cId_t *pAppOutClusterList; /输出命令列表 SimpleDescriptionForm
5、at_t;下面是在 SerialApp 程序中简单描述符的定义。const SimpleDescriptionFormat_t SerialApp_SimpleDesc =SERIALAPP_ENDPOINT, / int Endpoint;SERIALAPP_PROFID, / uint16 AppProfId2;SERIALAPP_DEVICEID, / uint16 AppDeviceId2;SERIALAPP_DEVICE_VERSION, / int AppDevVer:4;SERIALAPP_FLAGS, / int AppFlags:4;SERIALAPP_MAX_CLUSTER
6、S, / byte AppNumInClusters;(cId_t *)SerialApp_ClusterList, / byte *pAppInClusterList;SERIALAPP_MAX_CLUSTERS, / byte AppNumOutClusters;(cId_t *)SerialApp_ClusterList / byte *pAppOutClusterList;const endPointDesc_t SerialApp_epDesc =SERIALAPP_ENDPOINT,在 TI 给的例子中都只是定义了一个端点,猜想是不是每一个应用中都必须有一个相应的端点,也就会有一个
7、相应的端点描述符。例如这里的三个应用,一个节点具有控制灯光的功能,又具有感应温度的功能,又具有收发文本消息的功能,那么需要占用三个端点号,也就会需要三个端点的描述符,因为在发送数据的函数中会用到这个端点的描述符。AF_DataRequest( 在绑定的应用中必须要用到端点的描述符,可不可以这样理解就是说,在绑定时其实并不是两个设备之间的绑定,其实质是在这两个设备上两个端点之间的绑定,再进一步说就是两个应用之间的绑定,因为在一个终端中可能有很多的应用,也就是端点,可不以在一个端点中只和其中的一个应用进行绑定,也就是只和其中的一个端点进行绑定,其他的端点可以使用别的地址方式,如直接地址模式,或者是
8、广播地址的方式,进行数据的处理。虽然和同一个设备进行了绑定,但是其中的应用并不相同。描述符匹配是不是就是这个意思。如果两个设备没有相同的描述符是不会绑定成功的。case Match_Desc_rsp:ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );if ( pRsp )if ( pRsp-status = ZSuccess SerialApp_DstAddr.addr.shortAddr = pRsp-nwkAddr;/ Take the first endpoint, Can be changed to search t
9、hrough endpointsSerialApp_DstAddr.endPoint = pRsp-epList0;/ Light LEDHalLedSet( HAL_LED_4, HAL_LED_MODE_ON );osal_mem_free( pRsp );Break;在下面的函数中是绑定必须要执行一个处理函数,这个函数就是处理和回应对 Match_Desc_req 消息。这个函数在绑定的第三篇文章中也有分析到。void ZDO_ProcessMatchDescReq( zdoIncomingMsg_t *inMsg )uint8 epCnt = 0;uint8 numInClusters
10、;uint16 *inClusters = NULL;uint8 numOutClusters;uint16 *outClusters = NULL;epList_t *epDesc;SimpleDescriptionFormat_t *sDesc = NULL;uint8 allocated;uint8 *msg;uint16 aoi;uint16 profileID;/ Parse the incoming messagemsg = inMsg-asdu;aoi = BUILD_UINT16( msg0, msg1 );profileID = BUILD_UINT16( msg2, msg
11、3 );msg += 4;if ( ADDR_BCAST_NOT_ME = NLME_IsAddressBroadcast(aoi) )ZDP_MatchDescRsp( inMsg-TransSeq, return;else if ( (ADDR_NOT_BCAST = NLME_IsAddressBroadcast(aoi) return;numInClusters = *msg+;if ( numInClusters )inClusters = (uint16*)osal_mem_alloc( numInClusters * sizeof( uint16 ) );msg = ZDO_Co
12、nvertOTAClusters( numInClusters, msg, inClusters );numOutClusters = *msg+;if ( numOutClusters )outClusters = (uint16 *)osal_mem_alloc( numOutClusters * sizeof( uint16 ) );msg = ZDO_ConvertOTAClusters( numOutClusters, msg, outClusters );/* First count the number of endpoints that match. typedef struc
13、tendPointDesc_t *epDesc;eEP_Flags flags;pDescCB pfnDescCB; / Dont use if this function pointer is NULL.void *nextDesc; epList_t;*/epDesc = epList;while ( epDesc )/扫描本节点的全部 EP,看是否有匹配的?这个是一个链表的形式存储的。/ Dont search endpoint 0 and check if response is allowed /不扫描端点 0if ( epDesc-epDesc-endPoint != ZDO_EP
14、 allocated = TRUE;elsesDesc = epDesc-epDesc-simpleDesc;allocated = FALSE;if ( sDesc / If there are no search input/ouput clusters respond/在这里对 EP 中的输入/输出簇列表进行了比较,也就是 ZDP_MatchDescReq 发送来的,SerialApp_ClusterListif ( (numInClusters = 0) ZDO_MatchDescRspSent_t *pRspSent = (ZDO_MatchDescRspSent_t *) osal
15、_msg_allocate( bufLen );if (pRspSent)pRspSent-hdr.event = ZDO_MATCH_DESC_RSP_SENT;pRspSent-nwkAddr = inMsg-srcAddr.addr.shortAddr;pRspSent-numInClusters = numInClusters;pRspSent-numOutClusters = numOutClusters;if (numInClusters)pRspSent-pInClusters = (uint16*) (pRspSent + 1);osal_memcpy(pRspSent-pIn
16、Clusters, inClusters, numInClusters * sizeof(uint16);elsepRspSent-pInClusters = NULL;if (numOutClusters)pRspSent-pOutClusters = (uint16*)(pRspSent + 1) + numInClusters;osal_memcpy(pRspSent-pOutClusters, outClusters, numOutClusters * sizeof(uint16);elsepRspSent-pOutClusters = NULL;osal_msg_send( *epD
17、esc-epDesc-task_id, (uint8 *)pRspSent );uint8BufepCnt+ = sDesc-EndPoint;/ 匹配 EndPoint 列表,这个就是Match_Desc_rsp 回传的内容之一if ( allocated )osal_mem_free( sDesc );epDesc = epDesc-nextDesc;/ Send the message only if at least one match found. 如果发现至少有一个匹配的以后,发送匹配消息if ( epCnt )if ( ZSuccess = ZDP_MatchDescRsp( i
18、nMsg-TransSeq, #endifelse#if defined( LCD_SUPPORTED )HalLcdWriteScreen( “Match Desc Req“, “Non Matched“ );#endifif ( inClusters )osal_mem_free( inClusters );if ( outClusters )osal_mem_free( outClusters );从上面的代码内容中也可以看到,当两个节点绑定时,进行的匹配实质是描述符之间的匹配。当然绑定时可能有多个的描述符的匹配,不知道我这样的理解是否正确,如果网友有这方面的经验欢迎讨论一下!这里还有一
19、点就是绑定服务只能在“互补”设备之间建立。那就是,只有分别在两个节点的简单描述结构体(simple descriptor structure)中,同时注册了相同的命令标识符(command_id )并且方向相反(一个属于输出指令“output”,另一个属于输入指令“input”),才能成功建立绑定。通过查看 TI 给我例子程序中,只有开头的例程才算是真正意义上的一个是输出,一个是输入。对于灯结点是输入,const cId_t zb_InCmdListNUM_IN_CMD_CONTROLLER =TOGGLE_LIGHT_CMD_ID;/ Define SimpleDescriptor for
20、Switch deviceconst SimpleDescriptionFormat_t zb_SimpleDesc =MY_ENDPOINT_ID, / EndpointMY_PROFILE_ID, / Profile IDDEV_ID_CONTROLLER, / Device IDDEVICE_VERSION_CONTROLLER, / Device Version0, / ReservedNUM_IN_CMD_CONTROLLER, / Number of Input Commands(cId_t *) zb_InCmdList, / Input Command ListNUM_OUT_
21、CMD_CONTROLLER, / Number of Output Commands(cId_t *) NULL / Output Command List;对于开关结点是输出。const cId_t zb_OutCmdListNUM_OUT_CMD_SWITCH =TOGGLE_LIGHT_CMD_ID;/ Define SimpleDescriptor for Switch deviceconst SimpleDescriptionFormat_t zb_SimpleDesc =MY_ENDPOINT_ID, / EndpointMY_PROFILE_ID, / Profile IDDE
22、V_ID_SWITCH, / Device IDDEVICE_VERSION_SWITCH, / Device Version0, / ReservedNUM_IN_CMD_SWITCH, / Number of Input Commands(cId_t *) NULL, / Input Command ListNUM_OUT_CMD_SWITCH, / Number of Output Commands(cId_t *) zb_OutCmdList / Output Command List;可以在 GenericApp 和 SerialApp 的例程中看到,并没有严格的按照这样的命令来。例
23、如下面的 SampleApp 例程中,当然这样也是两个设备中的命令也是相反的,只是没有开关那个例程中更加直观,const cId_t GenericApp_ClusterListGENERICAPP_MAX_CLUSTERS =GENERICAPP_CLUSTERID;const SimpleDescriptionFormat_t GenericApp_SimpleDesc =GENERICAPP_ENDPOINT, / int Endpoint;GENERICAPP_PROFID, / uint16 AppProfId2;GENERICAPP_DEVICEID, / uint16 AppDe
24、viceId2;GENERICAPP_DEVICE_VERSION, / int AppDevVer:4;GENERICAPP_FLAGS, / int AppFlags:4;GENERICAPP_MAX_CLUSTERS, / byte AppNumInClusters;(cId_t *)GenericApp_ClusterList, / byte *pAppInClusterList;GENERICAPP_MAX_CLUSTERS, / byte AppNumInClusters;(cId_t *)GenericApp_ClusterList / byte *pAppInClusterLi
25、st;APS 绑定表是在静态 RAM 中定义的一张表,定义在 nwk_globals.c 中。表的大小可以通过 f8wConfig.cfg 中的/* Maximum number of entries in the Binding table. */-DNWK_MAX_BINDING_ENTRIES=10/* Maximum number of cluster IDs for each binding table entry. */-DMAX_BINDING_CLUSTER_IDS=5只有定义了 REFLECTOR 或者 COORDINATOR_BINDING 才能包含此表,用REFLECTO
26、R 编译选项来支持 APS 层的源绑定。邦定表结构 BindingEntry_ttypedef structuint16 srcIdx; / Address Manager indexuint8 srcEP;uint8 dstGroupMode; / Destination address type; 0 - Normal address index, 1 - / Group addressuint16 dstIdx; / This field is used in both modes (group and non-group) to / save NV and RAM space / ds
27、tGroupMode = 0 - Address Manager index/ dstGroupMode = 1 - Group Addressuint8 dstEP;uint8 numClusterIds;uint16 clusterIdListMAX_BINDING_CLUSTER_IDS;/ Dont use MAX_BINDING_CLUSTERS_ID when/ using the clusterIdList field. Use/ gMAX_BINDING_CLUSTER_IDS BindingEntry_t;srcIdx 源地址(绑定记录的源地址)的地址管理器索引,地址管理器保
28、存着源地址的 IEEE 地址和短地址。srcEP -源终端dstGroupMode -目的地址类型。0 普通地址1 组地址dstIdx -若 dstGroupMode 为 0,则包含目的地址的地址管理器索引,若dstGroupMode 为 1,则包含目的组地址dstEP -目的终端numClusterIds -clusterIdList 中的入口数目clusterIdList -簇 ID 列表。列表的最大数目定义由MAX_BINDING_CLUSTER_IDS f8wConfig.cfg指定还有一点就是绑定设备之间的通信方式更加的灵活,这主要体现在那里呢我想可能有下面几个原因,一是在前面也有介绍绑定有四种方式,主要介绍了两种一种是通过协调器,另一种是不通过协调器的绑定,这样可选择性多,但使用点对点的通信时,必须要通过 IEEE 地址得到网络中的短地址,也必须借助协调器进行,协调器的短地址是知道。第二个原因时:绑定也可以实现一对多的绑定,也就是相当于了组广播了,第三,绑定有较多的 API 操作进行,当终端结点离开或者有一个新的设备加入网络时,可以主动完成绑定过程,绑定的分析就到这里吧。如果有什么不对的地方,欢迎一起讨论。