注意:以下所有内容均以TI公司的CC2530和Z-Stack为硬软件平台为实验背景讲述。
在一般的ZigBee教程中,子节点如何向协调器发送消息已经被描述的非常清楚了:即子节点直接使用API向地址为0x0000的协调器发送消息即可。用到的函数如下:
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,uint16 cID, uint16 len, uint8 *buf, uint8 *transID,uint8 options, uint8 radius )
其中第一个参数dstAddr即为目标节点的地址。例如做一个点对点的通信,向协调器发数据,则dstAddr应该这样实例化:
afAddrType_t Point_To_Point_DstAddr;//点对点通信
Point_To_Point_DstAddr.addrMode = (afAddrMode_t)afAddr16Bit;//点播
Point_To_Point_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
Point_To_Point_DstAddr.addr.shortAddr = 0x0000;//发送给协调器,0x0000是协调器的地址
要使协调器向子节点发送数据,只需要知道子节点的地址即可。在许多深入讲解ZigBee通信协议的书中,对ZigBee网络节点的地址分配机制都做了详细的介绍,依据一些公式和描述该网络拓扑结构的参数可以计算出每个节点的地址。这也就似乎意味着如果一个网络拓扑结构固定的ZigBee网络,则其节点的地址也是固定的,大可以通过事先计算将节点地址算出来,再进行通信,则就没有一点问题。但是在项目开发阶段,我们很难做到这一点:固定拓扑结构。而且这需要修改ZigBee协议栈中关于网络拓扑结构类型的预先定义。所以,比较可靠的方法是:当ZigBee子节点加入网络后的第一时间,即向协调器发送一条消息,告诉协调器它的地址及认为给它加上的编号。这样,在协调器端,则会形成一个编号和短地址的对应表,协调器根据这张表向相应的子节点发送数据。
具体实现过程可以是这样的:
在子节点端,在SampleApp_ProcessEvent函数中,处理节点网络状态改变的分支中,可以开启一个定时器,在处理定时器计时完成的代码中向协调器发送该节点的短地址。
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (SampleApp_NwkState == DEV_ZB_COORD)
|| (SampleApp_NwkState == DEV_ROUTER)
|| (SampleApp_NwkState == DEV_END_DEVICE)
//|| (SampleApp_NwkState == DEV_NWK_DISC)
)
{
// Start sending the periodic message in a regular interval.
osal_start_timerEx( SampleApp_TaskID,
SEND_ADDR_MSG_EVT,
SEND_ADDR_STEP_TIMEOUT);
}
else
{
// Device is no longer in the network
}
break;
在处理SEND_ADDR_MSG_EVT事件中,可以这样做:
if (events & SEND_ADDR_MSG_EVT)
{
HalUARTWrite(0,"开始发送",4);
if (AF_DataRequest( &Point_To_Point_DstAddr, &SampleApp_epDesc,
SAMPLEAPP_POINT_TO_POINT_CLUSTERID,
4,
sendAddr,
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS)
{
HalUARTWrite(0,"成功发送",4);
}
else
{
HalUARTWrite(0,"发送失败",4);
}
其中sendAddr为一个uint8类型的数组,存储了该节点的编号(人为编号)。这样,当协调器收到这个数据包时,即可以知道这个节点的短地址(数据包中自带)和编号(来自数据包中的数据体)。
这样,在协调器端,就知道了这个节点的短地址,接下来利用这个短地址就可以向这个节点发送数据了。