基于上一章的代码改为coordinator与endDevice之间使用单播模式通讯。单播故名思议就是点对点通讯,一个节点通过一个网络地址唯一的找到另一个节点。zigbee协议中可使用16位短地址或64位IEEE地址这两个地址类型。
64位IEEE地址:
全球唯一标识,一般在芯片出厂时烧录进芯片,在工作时从芯片中读出。全球唯一,理论上没有两个IEEE地址相同的节点;
16位短地址:
在某个zigbee网络中唯一存在。协调器的短地址总是为1,其余节点短地址向他们的父节点获取。当一个设备接入网络后其父节点会产生一个随机数作为他的短地址,然后这个节点会使用这条短地址在网络内广播一条数据“声明自己的存在”。如果这时网络中有另一个设备具有相同的短地址也会广播一条数据表示”地址冲突“,这时这两台地址冲突的节点都会重新获取新的短地址。重复这个操作直到网络中没有重复的短地址存在。
本实验基于16位短地址寻址,当网络形成后按下endDevice按键s1发送一条单播数据给coordinator,coordinator收到endDevice的数据后记录他的16位短地址。当按下coordinator的按键s1时,以之前记录的16位短地址发送一条单播数据。可以再这两台设备的串口上看到他们收到的数据内容。
知识点:
从实验需求可以看出我们必须在代码中区别当前设备的类型,即当前设备是coordinator、router还是endDevice,不同的模式处理方式是不一样的。在zstack协议栈中我们可以使用宏ZSTACK_DEVICE_BUILD的值来判断当前模式,这个宏可能出现的值有以下三种,即三种工作模式:
开发中可以通过一个简单的if--else语句判断当前处于哪种模式,例如如果当前是endDevice模式就打印”helloworld“的代码如下:
if ( ZSTACK_DEVICE_BUILD == DEVICE_BUILD_ENDDEVICE ) {
HalUARTStr(0, "helloworld!\r\n");
}
ZSTACK_DEVICE_BUILD是在预编译阶段被定义的,在ZGlobals.h中定义
代码分析:
初始化部分:
与广播和组播不同,单播初始化时需要将目的地址初始化为单播模式,位置在TestApp.c的TestApp_Init()中:
模式为16位短地址的单播模式,shortAddr是具体的单播地址,这个在发送时会填写具体地址:
接收部分:
与广播与组播相同,同样是在函数TestApp_MessageMSGCB()中处理接收到的数据,接收到后打印数据内容,如果是coordinator则记录对方短地址:
void TestApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case TESTAPP_CLUSTERID:
HalUARTStr(0, "rcvd:");
HalUARTStr(0, (uint8 *)pkt->cmd.Data);
HalUARTStr(0, "\r\n");
//coordinator模式下记录源地址,用于返回数据
if ( ZSTACK_DEVICE_BUILD == DEVICE_BUILD_COORDINATOR ) {
if ( otherAddr == 0 && pkt->srcAddr.addrMode == afAddr16Bit ) {
otherAddr = pkt->srcAddr.addr.shortAddr;
}
}
break;
}
}
发送部分:
发送部分依然是在按键处理中,每当按下一次按键后就发送一条数据。coordinator与endDevice的发送流程是不一样的,主要区别在于短地址的获取。endDevice的发送目的地址就是coordinator的目的地址即总是0x0000,而coordinator的发送目的地址是endDevice的短地址,这个需要在接收数据包中获取。因此第一条数据必须是从endDevice发送到coordinator,因为一开始coordinator是不知道endDevice的短地址的,这时按键不发送数据。
void TestApp_HandleKeys( byte shift, byte keys )
{
static int count = 0;
char str[20] = "send data ---> ";
//stone:add********************/
if( keys & HAL_KEY_SW_6 ) {
if ( networkState == 0 ) {
return; //组网不成功时不发送数据
}
if ( ZSTACK_DEVICE_BUILD == DEVICE_BUILD_COORDINATOR ) {
if ( otherAddr == 0 ) {
return; //coordinator在还没有获取到endDevice地址的情况下不发送
} else {
TestApp_DstAddr.addr.shortAddr = otherAddr; // 将获取到的endDevice的短地址作为发送地址
}
}
if ( ZSTACK_DEVICE_BUILD == DEVICE_BUILD_ENDDEVICE ) {
TestApp_DstAddr.addr.shortAddr = 0; //coordinator 的地址总是为0
}
str[15] = count / 100 % 10 + '0';
str[16] = count / 10 % 10 + '0';
str[17] = count % 10 + '0';
str[18] = '\0';
if( ++count >= 1000 ) count = 0;
//发送数据
if ( AF_DataRequest( &TestApp_DstAddr, &TestApp_epDesc,
TESTAPP_CLUSTERID,
(byte)osal_strlen( str ) + 1,
(byte *)&str,
&TestApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.
HalUARTStr(0, "send success!\r\n");
}
else
{
// Error occurred in request to send.
HalUARTStr(0, "send fail!\r\n");
}
}
//************end***************/
}
实验:
在组网成功后,先按下endDevice的按键s1,发送一条单播数据到coordinator。当coordinator收到endDevice的数据包后也就同时获取到了endDevice的短地址,这时双方都可以通过按键s1互发数据了。