西北师范大学计算机科学与工程学院 无线传感器网络技术基于ZigBee协议栈的网络通信索国瑞2013秋选课班suogr@foxmail.com教9楼C区181号信箱教学群号:31696867西北师大计算机学院索国瑞:suogr @ foxmail.com目的描述验证基于ZigBee 2007协议栈的网络通信要求 设定一个ZigBee协调器,周期性的以广播的形式向终端节点发送数据,终端节点收到数据将回复信息给协调器,协调器收到终端节点回复的信息后通过串口发送到上位PC机 设定若干个ZigBee终端节点,接收到协调器发来的信息后,使自己相应的LED灯状态翻转,同时向协调器回复一个字符串 利用ZigBee 2007协议栈,分别通过广播、单播和组播方式进行,注意分别不同效应2013年11月28日星期四3西北师大计算机学院索国瑞:suogr @ foxmail.com※ 如何通过节点的网络地址得到节点的MAC地址※ 如何通过节点的MAC地址查询节点的网络地址※ 如何获得网络的拓扑结构ZigBee网络中的设备 三种类型的设备※ 协调器Coordinator 负责建立网络,配置网络。系统上电后,协调器会自动选择一个信道,然后选择一个网络号,建立网络 一旦网络建立,协调器与路由器的功能就一致了※ 路由器Router2013年11月28日星期四5西北师大计算机学院索国瑞:suogr @ foxmail.com无线基于ZigBee协议栈的网络通信传感器目的描述网络基础设定与预备知识技术广播和单播通信组播通信76869613:号群2013QQ年11月28日星期四2西北师大计算机学院索国瑞:suogr @ foxmail.com基础设定与预备知识利用前述第一到第四个工程中的相关知识实验反映的意义 进一步完善网络通信形式※ 广播※ 单播※ 组播 逐步进入网络管理的范畴,为后续实验打基础※ 如何查看节点的网络地址※ 如何查看节点的父节点的网络地址2013年11月28日星期四4西北师大计算机学院索国瑞:suogr @ foxmail.com 允许节点加入网络 进行数据的路由 辅助其它子节点通信 若某个节点是通过路由器加入网络,则该节点就是该路由器的子节点Child Node※ 终端节点End-device 只需要加入已经建立的网络即可 不具备网络维护功能 设备类型的选择是在ZigBee协议栈中编译时根据不同的编译选项来确定的,如※ ZDO_COORDINATOR表示协调器※ RTR_NWK表示路由器2013年11月28日星期四6西北师大计算机学院索国瑞:suogr @ foxmail.comZigBee网络中的设备地址 通过设备地址标识不同的设备,ZigBee中有两种地址 64bit的IEEE地址,也叫MAC地址或者扩展地址Extended Address。是全球唯一的,每个CC2530单片机的IEEE地址在出厂时就已定义好了,当然,初学时可以利用SmartRF Flash Programmer修改 16bit的网络地址,也叫逻辑地址或短地址。是在设备加入ZigBee网络时,按照一定的算法计算得到并分配给加入网络的设备。网络地址在某个网络中是唯一的,主要有两个功能※ 在网络中标识不同的设备※ 在网络数据传输时指定目的地址和源地址2013年11月28日星期四7西北师大计算机学院索国瑞:suogr @ foxmail.com网络地址计算中可得唯一结果的参考公式如下: d:该设备深度 Cskip:某父节点的路由器子设备之间的地址间隔 终端节点的网络地址※ An = Aparent + Cskip(d) * Rm + n 上述计算表示Aparent这个父设备分配的第n个终端设备的地址An2013年11月28日星期四9西北师大计算机学院索国瑞:suogr @ foxmail.comCskip位置配置范例2013年11月28日星期四11西北师大计算机学院索国瑞:suogr @ foxmail.comZigBee网络中的地址分配机制ZigBee网络中的地址分配机制叫分布式分配机制Distributed Addressing Scheme。协调器在建立网络以后,使用0x0000作为自己的网络地址,在路由器和终端节点加入网络后,父设备会自动给它分配16位的网络地址。 因网络地址16位,最多可以分配给65536个节点 地址的分配取决于整个网络的架构,由三个参数※ 网络的最大深度Lm※ 每个父节点拥有的子节点的最大数目Cm※ 每个父节点拥有的子节点中路由器的最大数目Rm2013年11月28日星期四8西北师大计算机学院索国瑞:suogr @ foxmail.com 上述计算公式中※ 父节点分配的第一个路由器地址=父设备地址+1※ 父节点分配的第二个路由器地址=父设备地址+1+Cskip(d)※ 父节点分配的第三个路由器地址=父设备地址+1+2×Cskip(d)※ 依次运算,可以计算出网络中各个设备的节点地址※ 可知协调器是该网络中所有节点的最初的地址计算的参照2013年11月28日星期四10西北师大计算机学院索国瑞:suogr @ foxmail.com网络拓扑结构例图2013年11月28日星期四12西北师大计算机学院索国瑞:suogr @ foxmail.com前述例子中,对协调器而言,路由器子设备的地址间隔计算时,d=0,Cm=5,Rm=3,Lm=3,则 Cskip(d=0) = (1+Cm-Rm-CmRmLm-d-1)/(1-Rm)=(1+5-3-5×3(3-0-1))/(1-3) = (3-45)/(-2) = 21据此,与协调器相连的三个路由器的网络地址如下 路由器1的网络地址 = 协调器网络地址 + 1= 0x0000+1 = 0x0001 路由器2的网络地址=协调器网络地址+1+Cskip(d)= 0x0000+1+21 = 0x0016 路由器3的网络地址 = 协调器网络地址 + 1 + 2×Cskip(d=0) = 0x0000+1+2×21 = 0x002B2013年11月28日星期四13西北师大计算机学院索国瑞:suogr @ foxmail.com= 0x0001+1 = 0x0002 路由器5的网络地址=路由器1网络地址+1 +Cskip(d=1)= 0x0001+1+6 = 0x0008 路由器6的网络地址 = 路由器1网络地址 + 1 + 2×Cskip(d=1) = 0x0001+1+2×6 = 0x000E与路由器1相连的终端节点的网络地址如下 终端节点3的网络地址=Aparent+Cskip(d=1)Rm+n = 0x0001 + 6×3 + 1 = 0x0014 终端节点4的网络地址=Aparent+Cskip(d=1)Rm+n = 0x0001 + 6×3 + 2 = 0x0015 2013年11月28日星期四15西北师大计算机学院索国瑞:suogr @ foxmail.com单播、组播和广播在ZigBee网络中进行数据通信主要是三种类型 广播:Broadcast,一个节点发送的数据包,网络中的所有节点都可以收到 单播:Unicast,网络中两个节点之间进行数据包的收发过程 组播:Multicast,也叫多播,网络中的某个节点发送的数据包,只有和该节点属于同一组的节点才能收到上述过程在ZigBee协议栈中是用函数来实现数据的发送,其中的第一个参数控制数据通信的类型 数据发送函数原型如下2013年11月28日星期四17西北师大计算机学院索国瑞:suogr @ foxmail.com与协调器相连的终端节点的网络地址计算 终端节点1的网络地址=Aparent+Cskip(d=0)Rm+n = 0x0000 + 21×3 + 1 = 0x0040 终端节点2的网络地址=Aparent+Cskip(d=0)Rm+n = 0x0000 + 21×3 + 2 = 0x0041 对于路由器1而言,路由器子设备之间的地址间隔 Cskip(d=1) = (1+Cm-Rm-CmRmLm-d-1)/(1-Rm)=(1+5-3-5×3(3-1-1))/(1-3) = (3-15)/(-2) = 6据此,与路由器1相连的三个路由器的网络地址如下 路由器4的网络地址 = 路由器1网络地址 + 1 2013年11月28日星期四14西北师大计算机学院索国瑞:suogr @ foxmail.com通过上述实例可知: 对应ZigBee网络,只要知道Lm、Cm、Rm三个参数,整个网络设备的地址是可以计算出来的 同一个父节点相连的终端节点的网络地址是连续的,但同一个父节点相连的路由器节点的网络地址通常是不连续的在ZigBee协议栈里,三个参数对应于前述讨论的参数 MAX_DEPTH: Lm MAX_ROUTES: Rm MAX_CHILDREN:Cm2013年11月28日星期四16西北师大计算机学院索国瑞:suogr @ foxmail.comafStatus_t AF_DataRequest(afAddrType_t *dstAddr,endPointDesc_t *srcEP,uint16 cID,uint16 len,uint8 *buf,uint8 *transID,uint8 options,uint8 radius)上述函数声明中第一个参数的具体类型定义如下typedef struct{2013年11月28日星期四18西北师大计算机学院索国瑞:suogr @ foxmail.comunion{uint16 shortAddr;ZLongAddr_t extAddr;}addr;afAddrMode_t addrMode;byte endPoint; uint16 panId;}afAddrType_t;对于afAddrMode_t的具体定义如下typedef enum{2013年11月28日星期四19西北师大计算机学院索国瑞:suogr @ foxmail.com上述参数都是常数,在ZigBee协议栈中已经定义enum{AddrNotPresent =0,AddrGroup =1,Addr16Bit =2,Addr64Bit =3,AddrBroadcast =15};常用的数据发送过程 定义一个afAddrType_t 类型的变量 afAddrType_t SendDataAddr;2013年11月28日星期四21西北师大计算机学院索国瑞:suogr @ foxmail.com广播和单播通信协调器流程 初始化 建立网络 广播发送数据 是否收到节点返回的回复数据?不是则继续监测 是则通过串口发送到上位机终端节点流程 初始化 加入网络 是否收到协调器发送的数据?不是则继续监测2013年11月28日星期四23西北师大计算机学院索国瑞:suogr @ foxmail.comafAddrNotPresent = AddrNotPresent,afAddr16Bit = Addr16Bit,afAddrGroup = AddrGroup,afAddrBroadcast = AddrBroadcast} afAddrMode_t;由上述内容可知 当addrMode = AddrBroadcast时,以广播方式发送数据 当addrMode = AddrGroup时,以组播方式发送数据 当addrMode = Addr16Bit时,以单播方式发送数据2013年11月28日星期四20西北师大计算机学院索国瑞:suogr @ foxmail.com 将其addrMode参数设置为Addr16Bit SendDataAddr.addrMode= (afAddrMode_t)Addr16Bit;SendDataAddr.addr.shortAddr=0xZZZZ※其中,ZZZZ代表目的节点的网络地址 调用AF_DataRequest函数发送数据即可AF_DataRequest(&SendDataAddr,……) 以上是以单播方式为例讲述的,在具体情况下,要注意参数类型的对应2013年11月28日星期四22西北师大计算机学院索国瑞:suogr @ foxmail.com 是则将LED灯状态取反 向协调器发送回复数据2013年11月28日星期四24西北师大计算机学院索国瑞:suogr @ foxmail.com协调器代码文件Coordinator.c在前述工程的Coordinator.c文件中修改,注意备份关键代码如下:/*SUOGR 20131109 要求注释所有修改*///蓝色区域为追加或者被改动过的,注意和原始文档//的区别/* * INCLUDES */#include \"OSAL.h\"#include \"AF.h\"#include \"ZDApp.h\"#include \"ZDObject.h\"#include \"ZDProfile.h\"2013年11月28日星期四25西北师大计算机学院索国瑞:suogr @ foxmail.com/* HAL */#include \"hal_lcd.h\"#include \"hal_led.h\"#include \"hal_key.h\"#include \"hal_uart.h\"//add suogr#include \"OSAL_Nv.h\" //为可能的存储过程准备define SEND_TO_ALL_EVENT 0x01 //定义发送事件//end add/* * GLOBAL VARIABLES */// Cluster IDs.2013年11月28日星期四27西北师大计算机学院索国瑞:suogr @ foxmail.com GENERICAPP_FLAGS, // int AppFlags:4; GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters; (cId_t *)GenericApp_ClusterList, // byte *pAppInClusterList; 0,// old = GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters; (cId_t *)NULL //old = GenericApp_ClusterList // byte *pAppInClusterList;}; endPointDesc_t GenericApp_epDesc;//add suogr2013年11月28日星期四29西北师大计算机学院索国瑞:suogr @ foxmail.com//Add suogr #include
#include \"Coordinator.h\"// Add end//mark suogr//#include \"GenericApp.h\"//mark end#include \"DebugTrace.h\"#if !defined( WIN32 ) #include \"OnBoard.h\"#endif2013年11月28日星期四26西北师大计算机学院索国瑞:suogr @ foxmail.comconst cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] ={ GENERICAPP_CLUSTERID };const SimpleDescriptionFormat_t GenericApp_SimpleDesc ={ GENERICAPP_ENDPOINT, // int Endpoint; GENERICAPP_PROFID, // uint16 AppProfId[2]; GENERICAPP_DEVICEID, // uint16 AppDeviceId[2]; GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;2013年11月28日星期四28西北师大计算机学院索国瑞:suogr @ foxmail.comdevStates_t GenericApp_NwkState;//存储网络状态的变量//add end/ * LOCAL VARIABLES */byte GenericApp_TaskID; byte GenericApp_TransID; ………………void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );void GenericApp_SendTheMessage( void );…………2013年11月28日星期四30西北师大计算机学院索国瑞:suogr @ foxmail.comvoid GenericApp_Init( byte task_id ){halUARTCfg_t uartConfig; GenericApp_TaskID = task_id; GenericApp_TransID = 0; GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT; GenericApp_epDesc.task_id = &GenericApp_TaskID; GenericApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc; GenericApp_epDesc.latencyReq = noLatencyReqs; afRegister( &GenericApp_epDesc );2013年11月28日星期四31西北师大计算机学院索国瑞:suogr @ foxmail.com if ( events & SYS_EVENT_MSG ) { MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID ); while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) {………… case AF_INCOMING_MSG_CMD: //收到新事件 GenericApp_MessageMSGCB( MSGpkt ); break; 2013年11月28日星期四33西北师大计算机学院索国瑞:suogr @ foxmail.com default:break;}osal_msg_deallocate((uint8 *)MSGpkt);MSGpkt=(afIncomingMSGPacket_t *)osal_msg_receive(GenericApp_TaskID);}return(events ^ SYS_EVENT_MSG);}if (events & SEND_TO_ALL_EVENT)//数据发送事件处理{2013年11月28日星期四35西北师大计算机学院索国瑞:suogr @ foxmail.com…………uartConfig.configured = TRUE;uartConfig.baudRate = HAL_UART_BR_115200;uartConfig.flowControl = FALSE;uartConfig.callBackFunc = NULL; HalUARTOpen(0,&uartConfig);}以上是任务初始化函数的主体部分,注意其中没有使用串口的回调函数UINT16 GenericApp_ProcessEvent( ……){ afIncomingMSGPacket_t *MSGpkt;…………2013年11月28日星期四32西北师大计算机学院索国瑞:suogr @ foxmail.com case ZDO_STATE_CHANGE: //建立网络后设置事件GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);if(GenericApp_NwkState==DEV_ZB_COORD){osal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,10000);}break;………………2013年11月28日星期四34西北师大计算机学院索国瑞:suogr @ foxmail.comGenericApp_SendTheMessage();osal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,10000);return(events ^ SEND_TO_ALL_EVENT);}return 0;}上述代码中,定时器定时为10svoid GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )2013年11月28日星期四36西北师大计算机学院索国瑞:suogr @ foxmail.com{ char buf[20];unsigned char buffer[2] = {0x0A,0x0D}; switch ( pkt->clusterId ) { case GENERICAPP_CLUSTERID: osal_memcpy(buf,pkt->cmd.Data,20); HalUARTWrite(0,buf,20); HalUARTWrite(0,buffer,2); break;……}}2013年11月28日星期四37西北师大计算机学院索国瑞:suogr @ foxmail.com注意:上述代码是以广播方式发送,网络地址注意是0xFFFF。 使用广播通信时,网络地址可以有三种※ 0xFFFF:该数据包在全网广播,包括处于休眠状态的节点※ 0xFFFD:该数据包只发往所有未处于休眠状态的节点※ 0xFFFC:该数据包发往网络中的所有路由器节点2013年11月28日星期四39西北师大计算机学院索国瑞:suogr @ foxmail.com#include \"DebugTrace.h\"#if !defined( WIN32 ) #include \"OnBoard.h\"#endif/* HAL */#include \"hal_lcd.h\"#include \"hal_led.h\"#include \"hal_key.h\"#include \"hal_uart.h\"2013年11月28日星期四41西北师大计算机学院索国瑞:suogr @ foxmail.comvoid GenericApp_SendTheMessage( void ){ unsigned char *theMessageData = \"Coordinator send!\";afAddrType_t my_DstAddr;my_DstAddr.addrMode=(afAddrMode_t)AddrBroadcast;my_DstAddr.endPoint=GENERICAPP_ENDPOINT;my_DstAddr.addr.shortAddr=0xFFFF; AF_DataRequest( &my_DstAddr, &GenericApp_epDesc, GENERICAPP_CLUSTERID, osal_strlen( theMessageData ) + 1, theMessageData, &GenericApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS); }2013年11月28日星期四38西北师大计算机学院索国瑞:suogr @ foxmail.com终端节点编码处理在前述工程中的Enddevice.c文件中修改,注意备份/* * INCLUDES */#include \"OSAL.h\"#include \"AF.h\"#include \"ZDApp.h\"#include \"ZDObject.h\"#include \"ZDProfile.h\"//Add suogr #include #include \"Coordinator.h\"// Add end2013年11月28日星期四40西北师大计算机学院索国瑞:suogr @ foxmail.comconst cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] ={ GENERICAPP_CLUSTERID };const SimpleDescriptionFormat_t GenericApp_SimpleDesc ={ GENERICAPP_ENDPOINT, // int Endpoint; GENERICAPP_PROFID, // uint16 AppProfId[2]; GENERICAPP_DEVICEID, // uint16 AppDeviceId[2]; GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;2013年11月28日星期四42西北师大计算机学院索国瑞:suogr @ foxmail.com GENERICAPP_FLAGS, // int AppFlags:4; //modi suogr 0, // modi end (cId_t *)NULL, GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList}endPointDesc_t GenericApp_epDesc;byte GenericApp_TaskID; byte GenericApp_TransID;2013年11月28日星期四43西北师大计算机学院索国瑞:suogr @ foxmail.com GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT; GenericApp_epDesc.task_id = &GenericApp_TaskID; GenericApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc; GenericApp_epDesc.latencyReq = noLatencyReqs; afRegister( &GenericApp_epDesc );…………}UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )2013年11月28日星期四45西北师大计算机学院索国瑞:suogr @ foxmail.com case AF_INCOMING_MSG_CMD: //收到新事件 GenericApp_MessageMSGCB( MSGpkt ); break; ………… default:break;}osal_msg_deallocate((uint8 *)MSGpkt);MSGpkt=(afIncomingMSGPacket_t *)osal_msg_receive(GenericApp_TaskID);}return(events ^ SYS_EVENT_MSG);}2013年11月28日星期四47西北师大计算机学院索国瑞:suogr @ foxmail.comdevStates_t GenericApp_NwkState;//存储网络状态的变量void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt );void GenericApp_SendTheMessage( void );…………void GenericApp_Init( byte task_id ){ GenericApp_TaskID = task_id; GenericApp_NwkState = DEV_INIT; GenericApp_TransID = 0;…………2013年11月28日星期四44西北师大计算机学院索国瑞:suogr @ foxmail.com{ afIncomingMSGPacket_t *MSGpkt;………… if ( events & SYS_EVENT_MSG ) { MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID ); while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) { …………2013年11月28日星期四46西北师大计算机学院索国瑞:suogr @ foxmail.comreturn 0;}上述代码是事件处理函授,如果收到协调器发来的数据,则调用下面的函数对收到的数据进行处理void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ){ char *recvbuf; switch ( pkt->clusterId ) { case GENERICAPP_CLUSTERID: osal_memcpy(recvbuf,pkt->cmd.Data,osal_strlen(\"Coordinator send!\")+1);2013年11月28日星期四48西北师大计算机学院索国瑞:suogr @ foxmail.comif(osal_memcmp(recvbuf,\"Coordinator send!\{GernericApp_SendTheMessage();}else{ } //可以添加出错时的处理代码break;}}当正确接收到协调器发来的数据后,回复消息过程如下:2013年11月28日星期四49西北师大计算机学院索国瑞:suogr @ foxmail.com my_DstAddr.addr.shortAddr =0x0000; AF_DataRequest( &my_DstAddr, &GenericApp_epDesc, GENERICAPP_CLUSTERID, osal_strlen(theMessageData)+1, theMessageData, &GenericApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ); HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);2013年11月28日星期四51西北师大计算机学院索国瑞:suogr @ foxmail.com组播通信参照前述广播和单播通信过程,组织组播过程的实验基本思路:协调器周期性的以组播的形式向路由器发送数据,路由器收到数据后,使自身节点的LED状态翻转,同时向协调器发送回复字符串。协调器收到路由器发回的数据后,通过串口输出到上位机基本组织 在组织网络时,将一个协调器和两个路由器加入同一个组中,再将另一个路由器不加入该组,注意观察实验现象。协调器流程 初始化2013年11月28日星期四53西北师大计算机学院索国瑞:suogr @ foxmail.comvoid GenericApp_SendTheMessage( void ){ unsigned char *theMessageData = \"EndDevice received!\"; afAddrType_t my_DstAddr; my_DstAddr.addrMode =(afAddrMode_t)Addr16Bit; my_DstAddr.endPoint = GENERICAPP_ENDPOINT;2013年11月28日星期四50西北师大计算机学院索国瑞:suogr @ foxmail.com调试设置好串口助手将协调器选定,下载程序到协调器将若干个终端节点选定,下载程序到其中注意先复位或者打开协调器电源,然后再复位终端节点,以保证运行观察效果一般的实验现象: 每隔10s,串口会显示几个字符串“EndDevice received!”,同时终端节点的LED每个10s会点亮一次2013年11月28日星期四52西北师大计算机学院索国瑞:suogr @ foxmail.com 建立网络 组播发送数据 是否收到节点返回的回复数据?不是则继续监测 是则通过串口发送到上位机路由器节点流程 初始化 加入网络 是否收到协调器发送的数据?不是则继续监测 是则将LED灯状态取反 向协调器发送回复数据2013年11月28日星期四54西北师大计算机学院索国瑞:suogr @ foxmail.com节点分组实现 在apsgroups.h文件中有asp_Group_t的定义#define APS_GROUP_NAME_LEN 16typedef struct{uint16 ID;uint8 name[APS_GROUP_NAME_LEN];}aps_Group_t;每个组都有一个特定的ID,然后是组名,在name中一般程序中的定义参考代码aps_Group_t GenericApp_Group;2013年11月28日星期四55西北师大计算机学院索国瑞:suogr @ foxmail.com协调器代码文件Coordinator.c在前述工程的Coordinator.c文件中修改,注意备份关键代码如下:/*SUOGR 20131109 要求注释所有修改*/#include \"OSAL.h\"#include \"AF.h\"#include \"ZDApp.h\"#include \"ZDObject.h\"#include \"ZDProfile.h\"#include #include \"Coordinator.h\"#include \"DebugTrace.h\"2013年11月28日星期四57西北师大计算机学院索国瑞:suogr @ foxmail.comconst cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] ={ GENERICAPP_CLUSTERID };const SimpleDescriptionFormat_t GenericApp_SimpleDesc ={ GENERICAPP_ENDPOINT, // int Endpoint; GENERICAPP_PROFID, // uint16 AppProfId[2]; GENERICAPP_DEVICEID, // uint16 AppDeviceId[2]; GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;2013年11月28日星期四59西北师大计算机学院索国瑞:suogr @ foxmail.comGenericApp_Group.ID=0x0001;GenericApp_Group.name[0]=6; //字符串长度osal_memcpy(&(GenericApp_Group.name[1]),\"Group1\6);……aps_AddGroup(GENERICAPP_ENDPOINT,&GenericApp_Group); //加入组中2013年11月28日星期四56西北师大计算机学院索国瑞:suogr @ foxmail.com#if !defined( WIN32 ) #include \"OnBoard.h\"#endif#include \"hal_lcd.h\"#include \"hal_led.h\"#include \"hal_key.h\"#include \"hal_uart.h\"#include \"OSAL_Nv.h\" //为可能的存储过程准备//add suogr#include \"aps_groups.h\" //为组播准备头文件//add enddefine SEND_TO_ALL_EVENT 0x01 //定义发送事件2013年11月28日星期四58西北师大计算机学院索国瑞:suogr @ foxmail.com GENERICAPP_FLAGS, // int AppFlags:4; GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters; (cId_t *)GenericApp_ClusterList, // byte *pAppInClusterList; 0,// old = GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters; (cId_t *)NULL //old = GenericApp_ClusterList // byte *pAppInClusterList;}; endPointDesc_t GenericApp_epDesc;devStates_t GenericApp_NwkState;2013年11月28日星期四60西北师大计算机学院索国瑞:suogr @ foxmail.combyte GenericApp_TaskID; byte GenericApp_TransID;//add suograps_Group_t GenericApp_Group; //add end………………void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );void GenericApp_SendTheMessage( void );static void rxCB(uint8 port,uint8 event); …………2013年11月28日星期四61西北师大计算机学院索国瑞:suogr @ foxmail.com…………uartConfig.configured = TRUE;uartConfig.baudRate = HAL_UART_BR_115200;uartConfig.flowControl = FALSE;uartConfig.callBackFunc = NULL; HalUARTOpen(0,&uartConfig); GenericApp_Group.ID=0x0001; //初始化组号 GenericApp_Group.name[0]6; //组名字符数 osal_memcpy(&(GenericApp_Group.name[1]),\"Group1\}以上是任务初始化函数的主体部分,主要完成端口初始化和组号初始化2013年11月28日星期四63西北师大计算机学院索国瑞:suogr @ foxmail.com………… case AF_INCOMING_MSG_CMD: //收到新事件 GenericApp_MessageMSGCB( MSGpkt ); break; case ZDO_STATE_CHANGE: //建立网络后设置事件GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);if(GenericApp_NwkState==DEV_ZB_COORD){ aps_Addgroup(GENERICAPP_ENDPOINT,&GenericApp_Group); //建立网络后,加入组2013年11月28日星期四65西北师大计算机学院索国瑞:suogr @ foxmail.comvoid GenericApp_Init( byte task_id ){halUARTCfg_t uartConfig; GenericApp_TaskID = task_id; GenericApp_TransID = 0; GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT; GenericApp_epDesc.task_id = &GenericApp_TaskID; GenericApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc; GenericApp_epDesc.latencyReq = noLatencyReqs; afRegister( &GenericApp_epDesc );2013年11月28日星期四62西北师大计算机学院索国瑞:suogr @ foxmail.comUINT16 GenericApp_ProcessEvent( ……){ afIncomingMSGPacket_t *MSGpkt;………… if ( events & SYS_EVENT_MSG ) { MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID ); while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) {2013年11月28日星期四64西北师大计算机学院索国瑞:suogr @ foxmail.comosal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,10000);}break;……………… default:break;}osal_msg_deallocate((uint8 *)MSGpkt);MSGpkt=(afIncomingMSGPacket_t *)osal_msg_receive(GenericApp_TaskID);}2013年11月28日星期四66西北师大计算机学院索国瑞:suogr @ foxmail.comreturn(events ^ SYS_EVENT_MSG);}if (events & SEND_TO_ALL_EVENT)//发送组播数据事件处理{GenericApp_SendTheMessage();osal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,10000);return(events ^ SEND_TO_ALL_EVENT);}return 0;}2013年11月28日星期四67西北师大计算机学院索国瑞:suogr @ foxmail.com break;……}}当接收到路由器发送的回复信息后,读取并输出到串口void GenericApp_SendTheMessage( void ){ unsigned char *theMessageData = \"Coordinator send!\";afAddrType_t my_DstAddr;my_DstAddr.addrMode=(afAddrMode_t)AddrGroup;my_DstAddr.endPoint=GENERICAPP_ENDPOINT;2013年11月28日星期四69西北师大计算机学院索国瑞:suogr @ foxmail.com路由器节点编码处理工程文件处理:Workspace中选RouterEB,再将Coordinator.c文件禁止编译即可。编译后下载到路由器节点即可,该节点启动后就具有了路由器的功能在前述工程中的Enddevice.c文件中修改,注意备份#include \"OSAL.h\"#include \"AF.h\"#include \"ZDApp.h\"#include \"ZDObject.h\"#include \"ZDProfile.h\"#include #include \"Coordinator.h\"#include \"DebugTrace.h\"2013年11月28日星期四71西北师大计算机学院索国瑞:suogr @ foxmail.com上述代码中,定时器定时为10svoid GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ){ char buf[17];unsigned char buffer[2] = {0x0A,0x0D}; switch ( pkt->clusterId ) { case GENERICAPP_CLUSTERID: osal_memcpy(buf,pkt->cmd.Data,17); HalUARTWrite(0,buf,17); HalUARTWrite(0,buffer,2);2013年11月28日星期四68西北师大计算机学院索国瑞:suogr @ foxmail.commy_DstAddr.addr.shortAddr=GenericApp_Group.ID; AF_DataRequest( &my_DstAddr, &GenericApp_epDesc, GENERICAPP_CLUSTERID, osal_strlen( theMessageData ) + 1, theMessageData, &GenericApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS); }上述函数实现了组播发送,此时地址模式设置为AddrGroup,网络地址设置为组ID2013年11月28日星期四70西北师大计算机学院索国瑞:suogr @ foxmail.com#if !defined( WIN32 ) #include \"OnBoard.h\"#endif#include \"hal_lcd.h\"#include \"hal_led.h\"#include \"hal_key.h\"#include \"hal_uart.h\"// add suogr#include \"aps_groups.h\" //使用组播功能要求#define SEND_DATA_EVENT 0x01// add end2013年11月28日星期四72西北师大计算机学院索国瑞:suogr @ foxmail.comconst cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] ={ GENERICAPP_CLUSTERID };const SimpleDescriptionFormat_t GenericApp_SimpleDesc ={ GENERICAPP_ENDPOINT, // int Endpoint; GENERICAPP_PROFID, // uint16 AppProfId[2]; GENERICAPP_DEVICEID, // uint16 AppDeviceId[2]; GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;2013年11月28日星期四73西北师大计算机学院索国瑞:suogr @ foxmail.comdevStates_t GenericApp_NwkState;//存储网络状态的变量void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt );void GenericApp_SendTheMessage( void );…………void GenericApp_Init( byte task_id ){ GenericApp_TaskID = task_id; GenericApp_NwkState = DEV_INIT; GenericApp_TransID = 0;…………2013年11月28日星期四75西北师大计算机学院索国瑞:suogr @ foxmail.com…………}以上代码是任务初始化函数,实现端口的初始化和组号的初始化UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events ){ afIncomingMSGPacket_t *MSGpkt;………… if ( events & SYS_EVENT_MSG ) { MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );2013年11月28日星期四77西北师大计算机学院索国瑞:suogr @ foxmail.com GENERICAPP_FLAGS, // int AppFlags:4; //modi suogr 0, // modi end (cId_t *)NULL, GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList}endPointDesc_t GenericApp_epDesc;byte GenericApp_TaskID; byte GenericApp_TransID;aps_Group_t GenericApp_Group; //组播2013年11月28日星期四74西北师大计算机学院索国瑞:suogr @ foxmail.com GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT; GenericApp_epDesc.task_id = &GenericApp_TaskID; GenericApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc; GenericApp_epDesc.latencyReq = noLatencyReqs; afRegister( &GenericApp_epDesc ); GenericApp_Group.ID=0x0001; //初始化组号 GenericApp_Group.name[0]6; //组名字符数 osal_memcpy(&(GenericApp_Group.name[1]),\"Group1\2013年11月28日星期四76西北师大计算机学院索国瑞:suogr @ foxmail.com while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) { ………… case AF_INCOMING_MSG_CMD: //收到新事件 GenericApp_MessageMSGCB( MSGpkt ); break; case ZDO_STATE_CHANGE: //加入网络后加入组GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);if(GenericApp_NwkState==DEV_ROUTER){ 2013年11月28日星期四78西北师大计算机学院索国瑞:suogr @ foxmail.comaps_Addgroup(GENERICAPP_ENDPOINT,&GenericApp_Group); }break;………… default:break;}osal_msg_deallocate((uint8 *)MSGpkt);MSGpkt=(afIncomingMSGPacket_t *)osal_msg_receive(GenericApp_TaskID);}return(events ^ SYS_EVENT_MSG);}2013年11月28日星期四79西北师大计算机学院索国瑞:suogr @ foxmail.comif(osal_memcmp(buf,\"Coordinator send!\{GernericApp_SendTheMessage();}else{ } //可以添加出错时的处理代码break;}}当正确接收到协调器发来的数据后,调用GenericApp_SendTheMessage函数以单播的方式回复消息,过程如下:void GenericApp_SendTheMessage( void ){2013年11月28日星期四81西北师大计算机学院索国瑞:suogr @ foxmail.com &GenericApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ); HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);}将上述代码下载到预备纳入同一组的路由器中将加入组函数aps_AddGroup注释掉,即 case ZDO_STATE_CHANGE: //加入网络后加入组GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);if(GenericApp_NwkState==DEV_ROUTER){ 2013年11月28日星期四83西北师大计算机学院索国瑞:suogr @ foxmail.comreturn 0;}上述代码是事件处理函数,当路由器成功加入到网络后,调用aps_AddGroup加到组中void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ){ char buf[18]; switch ( pkt->clusterId ) { case GENERICAPP_CLUSTERID: osal_memcpy(buf,pkt->cmd.Data,osal_strlen(\"Coordinator send!\")+1);2013年11月28日星期四80西北师大计算机学院索国瑞:suogr @ foxmail.com unsigned char *theMessageData = \"Router received!\"; afAddrType_t my_DstAddr; my_DstAddr.addrMode =(afAddrMode_t)Addr16Bit; my_DstAddr.endPoint = GENERICAPP_ENDPOINT; my_DstAddr.addr.shortAddr =0x0000; AF_DataRequest( &my_DstAddr, &GenericApp_epDesc, GENERICAPP_CLUSTERID, osal_strlen(theMessageData)+1, theMessageData,2013年11月28日星期四82西北师大计算机学院索国瑞:suogr @ foxmail.com//aps_Addgroup(GENERICAPP_ENDPOINT, &GenericApp_Group); }break;将上述代码下载到预备不纳入组中的路由器节点中2013年11月28日星期四84西北师大计算机学院索国瑞:suogr @ foxmail.com调试设置好串口助手将协调器选定,下载程序到协调器将若干个路由器选定,分别下载纳入组中的程序和不纳入组中的程序到其中注意先复位或者打开协调器电源,然后再复位路由器,以保证运行观察效果一般的实验现象: 每隔10s,串口会显示几个字符串“Router received!”,同时纳入组中的路由器的LED每隔10s会点亮一次 没纳入组中的路由器其LED始终处于熄灭状态2013年11月28日星期四85西北师大计算机学院索国瑞:suogr @ foxmail.com本章要点2013年11月28日星期四87西北师大计算机学院索国瑞:suogr @ foxmail.com变化处理不同的节点收到协调器的信息后回复的数据要有所不同,如何实现?组外节点是以哑吧节点的形式标识的,有没有其它更动态的呈现形式?根据协调器广播、组播的不同信息,路由器回复的数据要有所不同,如何实现?2013年11月28日星期四86西北师大计算机学院索国瑞:suogr @ foxmail.com作业2013年11月28日星期四88