AF_DataRequest函数 解读
作用
Z-Stack 中发送数据通过在应用层调用函数void SampleApp_SendFlashMessage( uint16 flashTime )完成,其中flash Time 为发送的数据,这个函数在应用中通过调用AF_DataRequest函数来实现。
原型
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t \*srcEP,*
*uint16 cID, uint16 len, uint8 \*buf, uint8 \*transID,*
*uint8 options, uint8 radius )
参数解析
afAddrType_t *dstAddr
该参数是一个结构体的指针。在该参数中除了指定了网络地址外,还需要指定目的地址的模式参数。
其定义如下:
typedef struct
{
union
{
uint16 shortAddr;
} addr;
afAddrMode_t addrMode; //afAddrMode_t是一个枚举类型 模式参数
byte endPoint; //指定的端点号 端点241—254保留端点 范围 1-240
} afAddrType_t;
其中,afAddrMode_t
定义如下:
typedef enum
{
afAddrNotPresent = AddrNotPresent, //按照绑定表进行绑定传输
afAddr16Bit = Addr16Bit, // 指定目标网络地址进行单薄传输 16位
afAddrGroup = AddrGroup, // 组播传输
afAddrBroadcast = AddrBroadcast // 广播传输
} afAddrMode_t;
对应的枚举如下:
enum
{
AddrNotPresent = 0,
AddrGroup = 1,
Addr16Bit = 2,
Addr64Bit = 3, // 指定IEEE地址进行单播传输 64位
AddrBroadcast = 15
};
注意:
-
ZigBee设备有两种类型的地址。一种是64位IEEE地址(物理),即MAC地址,另一种是16位网络地址。
-
64位地址使全球唯一的地址,设备将在它的生命周期中一直拥有它。它通常由制造商或者被安装时设置。这些地址由IEEE来维护和分配。
-
16为网络地址是当设备加入网络后由协调器或路由器分配的。它在网络中是唯一的,用来在网络中鉴别设备和发送数据。
endPointDesc_t *srcEP
是一个结构体的指针,源网络地址描述,每个终端都必须要有一个ZigBeezz的简单描述。
typedef struct
{
byte endPoint; //端点号
byte *task_id; // Pointer to location of the Application task ID.
SimpleDescriptionFormat_t *simpleDesc; //设备的简单描述
afNetworkLatencyReq_t latencyReq; //枚举结构 必须用 noLatencyReqs 填充
} endPointDesc_t;
SimpleDescriptionFormat_t
其中,SimpleDescriptionFormat_t
是目标设备的简单描述结构
typedef struct
{
byte EndPoint; //EP ID (EP=End Point)
uint16 AppProfId; // profile ID(剖面ID)
uint16 AppDeviceId; // Device ID
byte AppDevVer:4; //Device Version 0x00 为 Version 1.0
byte Reserved:4; // AF_V1_SUPPORT uses for AppFlags:4.
byte AppNumInClusters; //终端支持的输入簇的个数
cId_t *pAppInClusterList; //指向输入Cluster ID列表的指针
byte AppNumOutClusters; //输出簇的个数
cId_t *pAppOutClusterList; //指向输出Cluseter ID列表的指针
} SimpleDescriptionFormat_t;
-
端口
- 1个字节的编号(0---255),数据接收和发送的基本单元(数据发送时必须指定接收端的某个端点),在模块通信的时候,发送和接收双方必须指定端点号和网络地址
- 点要是用必须定义注册,并且挂钩到摸个任务(如应用层任务)
- 1个端点只能挂钩一个任务(同一个端点的数据在多个任务里执行,这样也不合理),一个任务可以挂钩多个端点(一个任务我挂载 5 6 7三个端点 是可以的),端点对所有任务是公用的 定义一个少一个(总数是一定的,比如定义了6号端点 就不能再定义6号端点了)
-
簇
-
每个端点可以定义多个簇:端点就相当于房子,簇就相当于房子里的人
-
发送的时候指定是哪个端点里的那个簇(相当于房子里的哪个人),簇不需要注册 发送函数如下:
-
MyApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;//设置模式 MyApp_DstAddr.addr.shortAddr = 0x0000;//设置接收网络地址 MyApp_DstAddr.endPoint = 12;//MyApp_ENDPOINT;//端点 char theMessageData[] = "endPoint = 12 CLUSTERID=12";//数据地址 AF_DataRequest(&MyApp_DstAddr,//目标地址 &MyApp_epDesc,//端点描述符 12,//MyApp_CLUSTERID,//端点镞 (byte)osal_strlen( theMessageData ) + 1,//多少个字节 (byte *)&theMessageData,//发送数组的首地址 &MyApp_TransID,//发送计数每发送一次加一 AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) ;
-
afNetworkLatencyReq_t
typedef enum
{
noLatencyReqs,
fastBeacons,
slowBeacons
} afNetworkLatencyReq_t;
用于控制用于控制Zigbee设备发送Beacon消息的速率。它定义了三个枚举值:
- noLatencyReqs 表示该设备没有进行网络延迟请求。
- fastBeacons 表示该设备发送Beacon消息的速率较快,即高速Beacons。
- slowBeacons 表示该设备发送Beacon消息的速率为标准速率,即普通Beacons。
这个枚举类型在Z-Stack协议栈中的某些源文件中出现过,主要用于控制Beacon消息的发送速率,从而影响Zigbee网络的性能和功耗。例如,在af.c文件中,该枚举类型用于控制Beacon消息的传输速率和延迟请求的状态等。
- Beacon,信标。通信术语,例
一般无线网卡都是做所谓的被动式扫描(passive scanning),也叫背景扫描。
开启OS下的无线网络管理程序或是XP内建管理程序,无线网络卡其实都在从ISM 频道一直轮番扫描。
等待扫到无线基地台(如AP)的Beacon 才会显示这区域有哪些SSID。而基地台的Beacon传送频繁frame 会比较占用无线频宽资源。
cID
簇ID
len
要发送的数据的长度
*buf
指向发送数据缓冲的指针
*transID
事务序列号指针。如果消息缓存发送,这个函数将增加这个数字
options
- AF_ACK_REQUEST 0x10 要求APS应答,这是应用层的应答,只在直接发送(单播)时使用。
- AF_DISCV_ROUTE 0x20 总要包含这个选项
- AF_SKIP_ROUTING 0x80 设置这个选项将导致设备跳过路由而直接发送消息。终点设备将不向其父亲发送消息。在直接发送(单播)和广播消息时很好用。
radius
最大的跳数,用默认值AF_DEFAULT_RADIUS
-
含义
在Zigbee网络中,AF_DataRequest()是一个函数,用于向目标节点发送一个Zigbee数据的帧。 radius是一个参数,它指定了数据帧的传输范围,既可以通过设置数据传输的距离,也可以指定跳数(hops)。
具体来说,radius的作用是控制Zigbee数据帧从源节点向目标节点传输的距离或跳数。设备通过最大跳数(MaxHops)来限制数据帧的跳数,这样可以防止数据帧无限制地转发,避免网络资源的浪费和性能下降。将radius设置为0表示数据帧只能由源节点直接发送到目标节点。将radius设置为255则表示数据帧可以进行无限次转发,直到到达目标节点或达到最大跳数。
需要注意的是,radius参数会影响网络传输的性能和延迟,因此需要根据实际应用场景中的需求进行设置。如果将radius参数设置得太小,可能会导致数据丢失或无法到达目标设备;如果将radius参数设置得太大,可能会影响网络性能和消耗网络资源。 -
什么是“跳数”
在Zigbee网络中,跳数(Hops)是指一个数据包从源设备传输到目标设备所涉及的路由器和重复器(中间设备)的数量。每经过一个中间设备,数据包的跳数加一。Zigbee设备使用跳数来限制数据包的转发次数,以避免网络资源浪费和性能下降,同时保障网络中数据包的传输质量。跳数越多,代表数据包需要经过更多设备才能到达目标设备,其延迟也会相应增加。
在Zigbee网络中,每个设备都有一个最大跳数(Max Hops)的参数,它表示设备可以转发的数据包所允许的最大跳数。当数据包的跳数达到设备的最大跳数时,设备就不再转发该数据包,并将其丢弃。这样可以避免数据包在网络中反复转发,避免对网络的负载和性能造成影响,同时也可以避免数据包在网络中无限制地传递,降低网络的安全性。
需要注意的是,并不是所有的Zigbee设备都允许转发数据包,例如终端设备(End-Device)只能连接一个Parent路由器,不能进行转发。而具有路由功能的设备(Router)和重复器(Repeater)则可以充当一跳或多跳的中间设备,帮助数据包传输到目标设备。
返回值
typedef enum
{
afStatus_SUCCESS,
afStatus_FAILED = 0x80,
afStatus_MEM_FAIL,
afStatus_INVALID_PARAMETER
} afStatus_t;
函数定义
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
// Verify destination address 判断目的地址
req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr;
// 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 != afAddrGroup &&
dstAddr->addrMode != afAddrNotPresent )
{
return afStatus_INVALID_PARAMETER;
}
req.dstAddr.addrMode = dstAddr->addrMode;
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 = TRUE;//(uint8)((options & AF_DISCV_ROUTE) ? 1 : 0);
req.radiusCounter = radius;
if (len > afDataReqMTU( &mtu ) )
{
if (apsfSendFragmented)
{
req.txOptions |= AF_FRAGMENTED | APS_TX_OPTIONS_ACK;
stat = (*apsfSendFragmented)( &req );
}
else
{
stat = afStatus_INVALID_PARAMETER;
}
}
else
{
stat = APSDE_DataReq( &req );
}
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;
}