ZStatk协调器 路由器 终端的确定Simple例程一 frank 编写.docx
《ZStatk协调器 路由器 终端的确定Simple例程一 frank 编写.docx》由会员分享,可在线阅读,更多相关《ZStatk协调器 路由器 终端的确定Simple例程一 frank 编写.docx(29页珍藏版)》请在冰豆网上搜索。
ZStatk协调器路由器终端的确定Simple例程一frank编写
Z-Statk协调器路由器终端的确定---Simple例程
(一)
当我们选择了终端、路由器、或者协调器的时候,来看一下程序中是怎么判断的。
也就是如何作为其中的各个角色进行启动,是加入网络,还是形成网络。
因为我们在这三个设备上使用的一套代码。
首先,我们可以看到下面的三张图,这个是以SampleApp例程为例子。
从三幅图中我们可以看来,当选择不同的设备类型编译时,下面加载的配置文件是不一样的。
下面是f8wCoord.cfg文件中的配置信息。
这个协调器中的编译选项比路由器结点的编译选项相比多了一个-DZDO_COORDINATOR选项。
/*CommonToAllApplications*/
-DCPU32MHZ //CC2430sRunat32MHz
-DFORCE_MAC_NEAR //MACcodeinNEAR
-DROOT=__near_func //MAC/ZMACcodeinNEAR
-DMAC_CFG_APP_PENDING_QUEUE=TRUE
/*CoordinatorSettings*/
-DZDO_COORDINATOR //CoordinatorFunctions
-DRTR_NWK //RouterFunctions
/*OptionalSettings*/
-DBLINK_LEDS //LEDBlinkFunctions
/*Compilerkeywords*/
-DCONST="const__code"
-DGENERIC=__generic //Ptrdeclaration
下面是终端结点的配置信息。
f8wEndev.cfg
/*CommonToAllApplications*/
-DCPU32MHZ //CC2430sRunat32MHz
-DFORCE_MAC_NEAR //MACcodeinNEAR
-DROOT=__near_func //MAC/ZMACcodeinNEAR
/*OptionalSettings*/
-DMAC_OPT_FFD=0 //ZigBeeRFD 应该是决定了是终端结点
-DBLINK_LEDS //LEDBlinkFunctions
/*Compilerkeywords*/
-DCONST="const__code"
-DGENERIC=__generic //Ptrdeclaration
下面是路由器结点的配置信息,f8wRouter.cfg,在这里没有协调器的编译选项
/*CommonToAllApplications*/
-DCPU32MHZ //CC2430sRunat32MHz
-DFORCE_MAC_NEAR //MACcodeinNEAR
-DROOT=__near_func //MAC/ZMACcodeinNEAR
-DMAC_CFG_APP_PENDING_QUEUE=TRUE
/*RouterSettings*/
-DRTR_NWK //RouterFunctions
/*OptionalSettings*/
-DBLINK_LEDS //LEDBlinkFunctions
/*Compilerkeywords*/
-DCONST="const__code"
-DGENERIC=__generic //Ptrdeclaration
从上面的三个配置文件的内容,我们来看一下这三个配置文件的区别。
其实区别就在上面红色标注的部分。
协调器比路由结点多了-DZDO_COORDINATOR //CoordinatorFunctions
这句话,我们也可以看到就是在协调器结点中,也定义了路由器结点的选项,也就是 -DRTR_NWK //RouterFunctions,
其实这也说明了,在加载f8wCoord.cfg文件时,我们可以通过应用程序来决定配置成协调器,还是配置成路由器。
还必须在配置了非自动启动模式HOLD_AUTO_START和软启动模式SOFT_START两个选项后,我们可以在SimpleControllerEB这个工程中和SimpleSwitchEB这个文件中,看到下面的编译选项,有什么不同点,也就是在作为协调器时,我们的编译选项多了一个非自动启动模式HOLD_AUTO_START模式。
在这个选择设备的类型这个下拉框中,我们没有发现和SampleApp例程一样有三个选项,也就是协调器,路由器,终端,这里就两个选项一个是SimpleControllerEB,另一个是SimpleSwitchEB,我们知道SimpleSwitchEB是终端结点,SimpleControllerEB可作为协调器结点,那我们的路由结点在那里呢?
从上面的分析可以看到一定是加载了 f8wCoord.cfg文件的,才可能成为路由器,其实协调器和路由器是通过程序中的按键来决定的,也就是用户的应用程序,其实这个工程和其它工程还有不同的地方就是协调器和路由器共用一个应用程序的文件,也就是SimpleController.c,而终端结点的应用在另一个文件SimpleSwitch.c。
这个工程所有共用的代码是sapi.c文件,这也为我们应用程序的编写提供了另一种思路。
开关设备SimpleSwitchEB无论按K1还是K2都是作为终端设备的,而灯设备SimpleControllerEB按键K1则作为协调器,按K2则作为路由器。
那下面我们就看看应用程序中是怎么来实现这样一个功能的。
下面首先是以协调器为例子。
图1协调器的编译选项的配置
还是在ZDApp.c文件中,有下面的代码:
#ifdefined(HOLD_AUTO_START)
devStates_tdevState=DEV_HOLD;
#else
devStates_tdevState=DEV_INIT;
#endif
#ifdefined(ZDO_COORDINATOR)&&!
defined(SOFT_START)
//定义了ZDO_COORDINATOR,没有定义SOFT_START执行下面的配置
//Setthedefaulttocoodinator
devStartModes_tdevStartMode=MODE_HARD;
#else//其它情况
devStartModes_tdevStartMode=MODE_JOIN; //Assume joining
//devStartModes_tdevStartMode=MODE_RESUME;
//ifalready"directlyjoined"
//toparent.SettomakethedevicedoanOrphanscan.
#endif
在协调器中定义了编译选项非自动启动模式HOLD_AUTO_START和软启动模式SOFT_START,这里可以得知各个选项的值:
devStates_tdevState=DEV_HOLD;devStartModes_tdevStartMode=MODE_JOIN;在Zglobals.h文件中可以看到。
#ifdefined(SOFT_START)
#defineDEVICE_LOGICAL_TYPEZG_DEVICETYPE_SOFT
#elifdefined(ZDO_COORDINATOR)
#defineDEVICE_LOGICAL_TYPEZG_DEVICETYPE_COORDINATOR
#elifdefined(RTR_NWK)
#defineDEVICE_LOGICAL_TYPEZG_DEVICETYPE_ROUTER
#else
#defineDEVICE_LOGICAL_TYPEZG_DEVICETYPE_ENDDEVICE
#endif
//ValuesforZCD_NV_LOGICAL_TYPE(zgDeviceLogicalType)
#defineZG_DEVICETYPE_COORDINATOR 0x00
#defineZG_DEVICETYPE_ROUTER 0x01
#defineZG_DEVICETYPE_ENDDEVICE 0x02
#defineZG_DEVICETYPE_SOFT 0x03
在AF.h文件中,
//NodeLogicalTypes
#defineNODETYPE_COORDINATOR 0x00
#defineNODETYPE_ROUTER 0x01
#defineNODETYPE_DEVICE 0x02
在ZDConfig.c文件中。
NodeDescriptorFormat_tZDO_Config_Node_Descriptor=
{
#ifdefined(ZDO_COORDINATOR)&&!
defined(SOFT_START)
NODETYPE_COORDINATOR,
#elifdefined(RTR_NWK)
NODETYPE_ROUTER,
#else
NODETYPE_DEVICE, //LogicalType
#endif
........
}
这些变量都会在下面的分析中展示其作用。
我们可以看到这个协调器中各个变量的赋值是个什么情况,也就是加粗的部分。
我们知道还要从ZDApp_Init()函数分析
voidZDApp_Init(bytetask_id)
{
uint8capabilities;
//SavethetaskID
ZDAppTaskID=task_id;
//InitializetheZDOglobaldeviceshortaddressstorage
ZDAppNwkAddr.addrMode=Addr16Bit;
ZDAppNwkAddr.addr.shortAddr=INVALID_NODE_ADDR;
(void)NLME_GetExtAddr(); //LoadthesaveExtAddrpointer. 加载IEEE地址
//Checkformanual"HoldAutoStart"
//打开电源时,检测到有手工设置SW_1则会设置devState=DEV_HOLD,从而不进行网络初始化
ZDAppCheckForHoldKey();
//InitializeZDOitemsandsetupthedevice-typeofdevicetocreate.
ZDO_Init(); //初始化ZDO条目,并设置设备的启动方式是协调器,还是别的
//RegistertheendpointdescriptionwiththeAF
//Thistaskdoesn'thaveaSimpledescription,butwestillneed
//toregistertheendpoint.
afRegister((endPointDesc_t*)&ZDApp_epDesc);
#ifdefined(ZDO_USERDESC_RESPONSE)
ZDApp_InitUserDesc();
#endif//ZDO_USERDESC_RESPONSE
//setbroadcastaddressmasktosupportbroadcastfiltering
NLME_GetRequest(nwkCapabilityInfo,0,&capabilities);
NLME_SetBroadcastFilter(capabilities);
//Startthedevice?
是否启动设备?
如果devState不是DEV_HOLD时,则启动设备,在上面的代码分析中,也可以看到,如果定义了HOLD_AUTO_START宏,则devState等于DEV_HOLD,不会启动设备。
如果按下了SW_1键devState也等于DEV_HOLD,也不会启动网络。
也就是说有两种方式可以设置非自动启动模式,一种是通过按键,一种通过宏定义
if(devState!
=DEV_HOLD)
{
ZDOInitDevice(0); //在本例程中没有定义HOLD_AUTO_START所以这个会成功执行
}
else
{
//如果定义了HOLD_AUTO_START,则等待延时或外部事件启动网络,并且LED4灯,也就是蓝色的灯闪烁
//BlinkLEDtoindicateHOLD_START
HalLedBlink(HAL_LED_4,0,50,500);
}
ZDApp_RegisterCBs();
}/*ZDO_Init()*/
我们首先看一下ZDO_Init(void)函数
voidZDO_Init(void)
{
//InitializeZDitems
#ifdefined(REFLECTOR)
ZDO_EDBind=NULL;
#endif
//Setupthedevice-typeofdevicetocreate.
ZDODeviceSetup();
}
staticvoidZDODeviceSetup(void)
{
#ifdefined(ZDO_COORDINATOR)
NLME_CoordinatorInit(); //这个函数执行
#endif
#ifdefined(REFLECTOR )//源绑定操作
#ifdefined(ZDO_COORDINATOR)
APS_ReflectorInit(APS_REFLECTOR_PUBLIC );//这个函数执行
#else
APS_ReflectorInit(APS_REFLECTOR_PRIVATE);
#endif
#endif
#if!
defined(ZDO_COORDINATOR)||defined(SOFT_START)
NLME_DeviceJoiningInit();
#endif
}
从上面的分析可知,由于编译了HOLD_AUTO_START选项后,devState==DEV_HOLD,所以不会进入ZDOInitDevice(0); 函数,而是闪烁LED4,指示初始化设备。
这时就应该到应用程序来处理的,决定来初始化为协调器,还是路由器了。
voidSAPI_Init(bytetask_id)
{
..............................................
if(HalKeyRead()==HAL_KEY_SW_5)
{
//IfSW5ispressedandheldwhilepowerup,forceauto-startandnv-restoreoffandreset
//如果SW5按下,并且打开电源,强迫关闭自动启动,并且不从NV中读出参数,并重启
startOptions=ZCD_STARTOPT_CLEAR_STATE|ZCD_STARTOPT_CLEAR_CONFIG;
//把默认的启动选项写入到NV中
zb_WriteConfiguration(ZCD_NV_STARTUP_OPTION,sizeof(uint8),&startOptions);
zb_SystemReset();//并重新启动系统
}
#endif//HAL_KEY
//Setaneventtostarttheapplication
osal_set_event(task_id,ZB_ENTRY_EVENT);
}
我们看了一下startOptions选项表示的是什么意思。
下面的代码在ZComDef.h文件中,
#defineZCD_STARTOPT_DEFAULT_CONFIG_STATE 0x01
#defineZCD_STARTOPT_DEFAULT_NETWORK_STATE0x02
#defineZCD_STARTOPT_AUTO_START 0x04
#defineZCD_STARTOPT_CLEAR_CONFIG ZCD_STARTOPT_DEFAULT_CONFIG_STATE
#defineZCD_STARTOPT_CLEAR_STATE ZCD_STARTOPT_DEFAULT_NETWORK_STATE
通过宏定义可以看出,他们都是默认的选项。
可以看到在程序的最后启动了ZB_ENTRY_EVENT事件,
UINT16SAPI_ProcessEvent(bytetask_id,UINT16events)
{
............................................
if(events&ZB_ENTRY_EVENT)
{
uint8startOptions;
//Giveindicationtoapplicationofdevicestartup 这里这个函数是一空函数
zb_HandleOsalEvent(ZB_ENTRY_EVENT);
//LEDoffcancelsHOLD_AUTO_STARTblinksetinthestack
HalLedSet(HAL_LED_4,HAL_LED_MODE_OFF);
//在上面当按下SW5按键后写入了默认的启动选项,这里进行了读取
zb_ReadConfiguration(ZCD_NV_STARTUP_OPTION,sizeof(uint8),&startOptions);
if(startOptions&ZCD_STARTOPT_AUTO_START)
{
zb_StartRequest();
}
else
{
//blinkledsandwaitforexternalinputtoconfigandrestart
HalLedBlink(HAL_LED_2,0,50,500);
}
return(events^ZB_ENTRY_EVENT);
}
............................................
}
我们看一下ZCD_NV_STARTUP_OPTION的初始值是什么,在下面的函数中写入了ZCD_NV_STARTUP_OPTION的初始值,初始值为0.这个函数,在uint8zgInit(void)中被调用。
uint8zgReadStartupOptions(void)
{
//DefaulttoUseConfigStateandUseNetworkState
uint8startupOption=0;
//ThisshouldhavebeendoneinZMain.c,butjustincase.
if(osal_nv_item_init(ZCD_NV_STARTUP_OPTION,
sizeof(startupOption),
&startupOption)==ZSUCCESS)
{
//Readsavedstartupcontrol
osal_nv_read(ZCD_NV_STARTUP_OPTION,
0,
sizeof(startupOption),
&startupOption);
}
return(startupOption);
}
由于#defineZCD_STARTOPT_AUTO_START 0x04所以下面的判断语句不成立,也就是没有执行zb_StartRequest();函数。
if(startOptions&ZCD_STARTOPT_AUTO_START)
这时也就是网络没有形成,没有具体确定那个是协调器,还是作为路由器。
下面就是通过应用程序的按键来确定。
下面是灯设备,也就是SimpleController.c文件中的按键个事件的处理过程。
voidzb_HandleKeys(uint8shift,uint8keys)
{
uint8startOptions;
uint8logicalType;
//Shiftisusedtomakeeachbutton/switchdualpurp