寻址方式
地址类型(Addresstypes)
ZigBee设备有两种类型的地址。一种是64位IEEE地址,即MAC地址,另一种是16位网络地址。
64位地址使全球唯一的地址,设备将在它的生命周期中一直拥有它。它通常由制造商或者被安装时设置。这些地址由IEEE来维护和分配。
16为网络地址是当设备加入网络后分配的。它在网络中是唯一的,用来在网络中鉴别设备和发送数据。
Z-Stack寻址(Addressinginz-stack)
为了向一个在ZigBee网络中的设备发送数据,应用程序通常使用AF_DataRequest()函数。数据包将要发送给一个afAddrType_t(在ZComDef.h中定义)类型的目标设备。
Typedefstruct
{
union{
uint16shortAddr;
}addr;
afAddrMode_taddrMode;
byteendPoint;
}afAddrType_t;
注意,除了网络地址之外,还要指定地址模式参数。目的地址模式可以设置为以下几个值:typedef enum
{
afAddrNotPresent=AddrNotPresent,
afAddr16Bit=Addr16Bit,
afAddrGroup=AddrGroup,
afAddrBroadcast=AddrBroadcast
}afAddrMode_t;
因为在Zigbee中,数据包可以单点传送(unicast),多点传送(multicast)或者广播传送,所以必须有地址模式参数。一个单点传送数据包只发送给一个设备,多点传送数据包则要传送给一组设备,而广播数据包则要发送给整个网络的所有节点。
这个将在下面详细解释。
单点传送(Unicast)
Uicast是标准寻址模式,它将数据包发送给一个已经知道网络地址的网络设备。将afAddrMode设置为Addr16Bit并且在数据包中携带目标设备地址。
间接传送(Indirect)
当应用程序不知道数据包的目标设备在哪里的时候使用的模式。
将模式设置为AddrNotPresent并且目标地址没有指定。取代它的是从发送设备的栈的绑定表中查找目标设备。这种特点称之为源绑定。当数据向下发送到达栈中,从绑定表中查找并且使用该目标地址。这样,数据包将被处理成为一个标准的单点传送数据包。如果在绑定表中找到多个设备,则向每个设备都发送一个数据包的拷贝。有一个选项可以讲绑定表保存在协调器(Coordinator)当中。发送设备将数据包发送给协调器,协调器查找它栈中的绑定表,然后将数据发送给最终的目标设备。这个附加的特性叫做协调器绑定(CoordinatorBinding)。
广播传送(broadcast)
当应用程序需要将数据包发送给网络的每一个设备时,使用这种模式。地址模式设置为AddrBroadcast。
目标地址可以设置为下面广播地址的一种:
NWK_BROADCAST_SHORTADDR_DEVALL(0xFFFF)——数据包将被传送到网络上的所有设备,包括睡眠中的设备。对于睡眠中的设备,数据包将被保留在其父亲节点直到查询到它,或者消息超时(NWK_INDIRECT_MSG_TIMEOUT在f8wConifg.cfg中)。
NWK_BROADCAST_SHORTADDR_DEVRXON(0xFFFD)——数据包将被传送到网络上的所有在空闲时打开接收的设备(RXONWHENIDLE),也就是说,除了睡眠中的所有设备。
NWK_BROADCAST_SHORTADDR_DEVZCZR(0xFFFC)——数据包发送给所有的路由器,包括协调器。
0xFFFE--通过绑定表中的地址进行发送。
组寻址(GroupAddressing)
当应用程序需要将数据包发送给网络上的一组设备时,使用该模式。地址模式设置为afAddrGroup并且addr.shortAddr设置为组ID。
在使用这个功能呢之前,必须在网络中定义组。(参见Z-stackAPI文档中的aps_AddGroup()函数)。注意组可以用来关联间接寻址。再绑定表中找到的目标地址可能是是单点传送或者是一个组地址。另外,广播发送可以看做是一个组寻址的特例。
重要设备地址(ImportantDeviceAdresses)
应用程序可能需要知道它的设备地址和父亲地址。
使用下面的函数获取设备地址(在ZStackAPI中定义):
1、NLME_GetShortAddr()——返回本设备的16位网络地址
2、NLME_GetExtAddr()——返回本设备的64位扩展地址使用下面的函数获取该设备的父亲设备的地址:
1、NLME_GetCoordShortAddr()——返回本设备的父亲设备的16位网络地址
2、NLME_GetCoordExtAddr()——返回本设备的父亲设备的64位扩展地址
数据的发送,广播、组播、点对点
AF_DataRequest(afAddrType_t*dstAddr,endPointDesc_t*srcEP,uint16cID,uint16len,uint8*buf,uint8*transID,uint8options,uint8radius);
AF_DataRequest函数最终调用APSDE_DataReq原语,而我们只需要了解AF_DataRequest函数的参数,就可非常灵活的以各种方式来发送数据。
AF_DataRequest函数的调用会触发afDataConfirm(...)函数
数据的发送结果也由afDataConfirm(...)函数返回
而AF_DataRequest函数返回的值并不是真正的发送结果。
函数参数说明
*dstAddr--发送目的地址+端点地址和传送模式
*srcEP--源(答复或确认)终端的描述(比如操作系统中任务ID等)源EP
cID--被Profile指定的有效的集群号
len--发送数据长度
*buf--发送数据缓冲区
*transID--任务ID号
options--有效位掩码的发送选项
radius--传送跳数,通常设置为AF_DEFAULT_RADIUS
afAddrType_t*dstAddr
Typedef struct
{
union{
uint16shortAddr; //短地址}addr;
afAddrMode_taddrMode; //传送模式
byteendPoint; //端点号
}afAddrType_t;
endPointDesc_t*srcEP
Typedefstruct
{
byteendPoint;//端点号
byte*task_id;//那一个任务的端点号
SimpleDescriptionFormat_t*simpleDesc; //简单的端点描述 afNetworkLatencyReq_tlatencyReq;
}endPointDesc_t;
SimpleDescriptionFormat_t
Typedefstruct
{
byteEndPoint; //EP
uint16AppProfId; //应用规范ID
uint16AppDeviceId; //特定规范ID的设备类型
byteAppDevVer:4; //特定规范ID的设备的版本
byteReserved:4; //AF_V1_SUPPORTusesforAppFlags:4.
byteAppNumInClusters; //输入簇ID的个数
cId_t*pAppInClusterList; //输入簇ID的列表
byteAppNumOutClusters; //输出簇ID的个数
cId_t*pAppOutClusterList; //输出簇ID的列表
}SimpleDescriptionFormat_t;
ClusterID--具体应用串ID
uint8 options
发送模式选项有如下选项
#defineAF_FRAGMENTED0x01
#defineAF_ACK_REQUEST0x10
#defineAF_DISCV_ROUTE0x20
#defineAF_EN_SECURITY0x40
#defineAF_SKIP_ROUTING0x80
其中AF_ACK_REQUEST为发送后需要接收方的确认
uint8 radius 传输跳数或传输半径,默认值为10
广播发送
广播发送时,分为三种广播,如果想使用广播发送,则只需将dstAddr->addrMode设为AddrBroadcast,dstAddr->addr->shortAddr设置为相应的广播类型即可。
具体的定义如下:
NWK_BROADCAST_SHORTADDR_DEVALL(0xFFFF)——数据包将被传送到网络上的所有设备,包括睡眠中的设备。对于睡眠中的设备,数据包将被保留在其父亲节点直到查询到它,或者消息超时。
NWK_BROADCAST_SHORTADDR_DEVRXON(0xFFFD)——数据包将被传送到网络上的所有在空闲时打开接收的设备(RXONWHENIDLE),也就是说,除了睡眠中的所有设备。
NWK_BROADCAST_SHORTADDR_DEVZCZR(0xFFFC)——数据包发送给所有的路由器,包括协调器。
组播发送
如果设备想传输数据到某一组设备,那么只需将dstAddr->addrMode设为AddrGroup,dstAddr->addr->shortAddr设置为相应的组ID即可。
代码如下:
//Setupfortheflashcommand'sdestinationaddress-Group1
SampleApp_Flash_DstAddr.addrMode=(afAddrMode_t)afAddrGroup;
SampleApp_Flash_DstAddr.endPoint=SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr=SAMPLEAPP_FLASH_GROUP;
//Fillouttheendpointdescription.
SampleApp_epDesc.endPoint=SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id=&SampleApp_TaskID;SampleApp_epDesc.simpleDesc
=(SimpleDescriptionFormat_t*)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq=noLatencyReqs;
根据上面代码的配置,然后使用AF_DataRequest()函数来进行组播发送。
点对点的发送
点对点的传输需要知道目标设备的短地址,需要将dstAddr->addrMode设为Addr16Bit,dstAddr->addr->shortAddr设置为目标设备的短地址即可。
代码如下:
SampleApp_Flash_DstAddr.addrMode=(afAddrMode_t)afAddr16Bit;
SampleApp_Flash_DstAddr.endPoint=SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr=0x00;//Fillouttheendpointdescription.
SampleApp_epDesc.endPoint=SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id=&SampleApp_TaskID;
SampleApp_epDesc.simpleDesc
=(SimpleDescriptionFormat_t*)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq=noLatencyReqs;
根据上面代码的配置,然后使用AF_DataRequest()函数来进行点对点发送。
绑定设备数据的发送
绑定设备数据的发送目标设备可以是一个设备、也可以是多个设备、还可以是一组设备,这要看绑定表中的绑定信息。
绑定设备数据的发送,需要将dstAddr->addrMode设为AddrNotPresent,dstAddr->addr->shortAddr可以忽略,cID设置为绑定时注册的命令号。代码如下:
dstAddr.addrMode=afAddrNotPresent; //Settheendpoint
dstAddr.endPoint=sapi_epDesc.simpleDesc->EndPoint; //Fillouttheendpointdescription.
sapi_epDesc.endPoint=zb_SimpleDesc.EndPoint;
sapi_epDesc.task_id=&sapi_TaskID;
sapi_epDesc.simpleDesc=(SimpleDescriptionFormat_t*)&zb_SimpleDesc;
sapi_epDesc.latencyReq=noLatencyReqs;
根据上面代码的配置,然后使用AF_DataRequest()函数来进行绑定数据的发送。
数据的接收
当收到数据时会触发afIncomingData函数,afIncomingData函数会对信息进行过滤,看是否为本设备的信息,是的话进而调用afBuildMSGIncoming函数,代码如下:
if((aff->ProfileID==epProfileID)||((epDesc->endPoint==ZDO_EP)&&(aff->ProfileID==ZDO_PROFILE_ID)))
{
{
afBuildMSGIncoming(aff,epDesc,SrcAddress,LinkQuality,SecurityUse,timestamp);
}
}
在afBuildMSGIncoming 函数中根据需要发送到的任务ID,添加相应任务的AF_INCOMING_MSG_CMD事件。在相应的AF_INCOMING_MSG_CMD事件中会对信息做进一步的处理,代码如下:
MSGpkt->hdr.event=AF_INCOMING_MSG_CMD;
MSGpkt->groupId=aff->GroupID;
MSGpkt->clusterId=aff->ClusterID;
afCopyAddress(&MSGpkt->srcAddr,SrcAddress);
MSGpkt->srcAddr.endPoint=aff->SrcEndPoint;
MSGpkt->endPoint=epDesc->endPoint;
MSGpkt->wasBroadcast=aff->wasBroadcast;
MSGpkt->LinkQuality=LinkQuality;
MSGpkt->SecurityUse=SecurityUse;
MSGpkt->timestamp=timestamp;
MSGpkt->cmd.TransSeqNumber=0;
MSGpkt->cmd.DataLength=aff->asduLength;
if(MSGpkt->cmd.DataLength)
{
MSGpkt->cmd.Data=(byte*)(MSGpkt+1);
osal_memcpy(MSGpkt->cmd.Data,asdu,MSGpkt->cmd.DataLength);}
Else
{
MSGpkt->cmd.Data=NULL;
}
afIncomingData函数的参数每个参数的详细说明如下:
aps_FrameFormat_t*afftypedefstruct{
byteFrmCtrl; //传输模式标识0x0C;与那些信息有关
byteXtndFrmCtrl; //0x00byteDstEndPoint;//目的EP
byteSrcEndPoint; //源端EP
uint16GroupID; //组ID号
uint16ClusterID; //接收的串
uint16ProfileID; //源模式标识符
bytewasBroadcast; //是否为广播传输0x00
byteapsHdrLen; //
byte*asdu; //应用数据
byteasduLength; //ASDU的长度
byteApsCounter; //每接收一次会加1
uint8transID; //任务ID号
uint8BlkCount; //
uint8AckBits; //接收确认选项
}aps_FrameFormat_t;
zAddrType_t*SrcAddresstypedefstruct{
union{
uint16shortAddr; //16位短地址ZLongAddr_textAddr;//64位长地址}addr;
byteaddrMode; //地址模式}zAddrType_t;
组的加入或退出
APSME-ADD-GROUP.request{GroupAddress,Endpoint} 原语用来将设备添加到某组中APSME-REMOVE-GROUP.request{GroupAddress,Endpoint} 原语用来将设备从某组中删除。
其中的参数只有组地址和端点号,没有短地址等,添加或删除组成员只能在本地设备进行,不能远程进行,比如一个设备直接添加或删除另一个设备。
代码如下:
//设置EP
#defineSAMPLEAPP_ENDPOINT20 //配置组表结构
SampleApp_Group.ID=0x0001;
osal_memcpy(SampleApp_Group.name,"Group1",7); /添加到组
aps_AddGroup(SAMPLEAPP_ENDPOINT,&SampleApp_Group);
//指定组ID
#defineSAMPLEAPP_FLASH_GROUP0x0001 //设置EP
#defineSAMPLEAPP_ENDPOINT20 //从组中移除
aps_RemoveGroup(SAMPLEAPP_ENDPOINT,SAMPLEAPP_FLASH_GROUP);