当我们选择了终端、路由器、或者协调器的时候,来看一下程序中是怎么判断的。也就是如何作为其中的各个角色进行启动,是加入网络,还是形成网络。因为我们在这三个设备上使用的一套代码。首先,我们可以看到下面的三张图,这个是以SampleApp例程为例子。从三幅图中我们可以看来,当选择不同的设备类型编译时,下面加载的配置文件是不一样的。
下面是f8wCoord.cfg文件中的配置信息。这个协调器中的编译选项比路由器结点的编译选项相比多了一个-DZDO_COORDINATOR选项。
/* Common To All Applications */
-DCPU32MHZ // CC2430s Run at 32MHz
-DFORCE_MAC_NEAR // MAC code in NEAR
-DROOT=__near_func // MAC/ZMAC code in NEAR
-DMAC_CFG_APP_PENDING_QUEUE=TRUE
/* Coordinator Settings */
-DZDO_COORDINATOR // Coordinator Functions
-DRTR_NWK // Router Functions
/* Optional Settings */
-DBLINK_LEDS // LED Blink Functions
/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic // Ptr declaration
下面是终端结点的配置信息。f8wEndev.cfg
/* Common To All Applications */
-DCPU32MHZ // CC2430s Run at 32MHz
-DFORCE_MAC_NEAR // MAC code in NEAR
-DROOT=__near_func // MAC/ZMAC code in NEAR
/* Optional Settings */
-DMAC_OPT_FFD=0 // ZigBee RFD 应该是决定了是终端结点
-DBLINK_LEDS // LED Blink Functions
/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic // Ptr declaration
下面是路由器结点的配置信息,f8wRouter.cfg,在这里没有协调器的编译选项
/* Common To All Applications */
-DCPU32MHZ // CC2430s Run at 32MHz
-DFORCE_MAC_NEAR // MAC code in NEAR
-DROOT=__near_func // MAC/ZMAC code in NEAR
-DMAC_CFG_APP_PENDING_QUEUE=TRUE
/* Router Settings */
-DRTR_NWK // Router Functions
/* Optional Settings */
-DBLINK_LEDS // LED Blink Functions
/* Compiler keywords */
-DCONST="const __code"
-DGENERIC=__generic // Ptr declaration
从上面的三个配置文件的内容,我们来看一下这三个配置文件的区别。其实区别就在上面红色标注的部分。协调器比路由结点多了-DZDO_COORDINATOR // Coordinator Functions
这句话,我们也可以看到就是在协调器结点中,也定义了路由器结点的选项,也就是 -DRTR_NWK // Router Functions,
其实这也说明了,在加载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文件中,有下面的代码:
#if defined( HOLD_AUTO_START )
devStates_t devState = DEV_HOLD;
#else
devStates_t devState = DEV_INIT;
#endif
#if defined( ZDO_COORDINATOR ) && !defined( SOFT_START )
//定义了ZDO_COORDINATOR,没有定义SOFT_START执行下面的配置
// Set the default to coodinator
devStartModes_t devStartMode = MODE_HARD;
#else//其它情况
devStartModes_t devStartMode = MODE_JOIN; // Assume joining
//devStartModes_t devStartMode = MODE_RESUME;
// if already "directly joined"
// to parent. Set to make the device do an Orphan scan.
#endif
在协调器中定义了编译选项非自动启动模式HOLD_AUTO_START和软启动模式SOFT_START,这里可以得知各个选项的值:devStates_t devState = DEV_HOLD; devStartModes_t devStartMode = MODE_JOIN;在Zglobals.h文件中可以看到。
#if defined ( SOFT_START )
#define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_SOFT
#elif defined( ZDO_COORDINATOR )
#define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_COORDINATOR
#elif defined (RTR_NWK)
#define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_ROUTER
#else
#define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_ENDDEVICE
#endif
// Values for ZCD_NV_LOGICAL_TYPE (zgDeviceLogicalType)
#define ZG_DEVICETYPE_COORDINATOR 0x00
#define ZG_DEVICETYPE_ROUTER 0x01
#define ZG_DEVICETYPE_ENDDEVICE 0x02
#define ZG_DEVICETYPE_SOFT 0x03
在AF.h文件中,
// Node Logical Types
#define NODETYPE_COORDINATOR 0x00
#define NODETYPE_ROUTER 0x01
#define NODETYPE_DEVICE 0x02
在ZDConfig.c文件中。
NodeDescriptorFormat_t ZDO_Config_Node_Descriptor =
{
#if defined( ZDO_COORDINATOR ) && !defined( SOFT_START )
NODETYPE_COORDINATOR,
#elif defined (RTR_NWK)
NODETYPE_ROUTER,
#else
NODETYPE_DEVICE, // Logical Type
#endif
........
}
这些变量都会在下面的分析中展示其作用。我们可以看到这个协调器中各个变量的赋值是个什么情况,也就是加粗的部分。我们知道还要从ZDApp_Init()函数分析
void ZDApp_Init( byte task_id )
{
uint8 capabilities;
// Save the task ID
ZDAppTaskID = task_id;
// Initialize the ZDO global device short address storage
ZDAppNwkAddr.addrMode = Addr16Bit;
ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR;
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer. 加载IEEE地址
// Check for manual "Hold Auto Start"
//打开电源时,检测到有手工设置SW_1则会设置devState = DEV_HOLD,从而不进行网络初始化
ZDAppCheckForHoldKey();
// Initialize ZDO items and setup the device - type of device to create.
ZDO_Init(); //初始化ZDO条目,并设置设备的启动方式是协调器,还是别的
// Register the endpoint description with the AF
// This task doesn't have a Simple description, but we still need
// to register the endpoint.
afRegister( (endPointDesc_t *)&ZDApp_epDesc );
#if defined( ZDO_USERDESC_RESPONSE )
ZDApp_InitUserDesc();
#endif // ZDO_USERDESC_RESPONSE
// set broadcast address mask to support broadcast filtering
NLME_GetRequest(nwkCapabilityInfo, 0, &capabilities);
NLME_SetBroadcastFilter( capabilities );
// Start the device? 是否启动设备?如果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灯,也就是蓝色的灯闪烁
// Blink LED to indicate HOLD_START
HalLedBlink ( HAL_LED_4, 0, 50, 500 );
}
ZDApp_RegisterCBs();
} /* ZDO_Init() */
我们首先看一下ZDO_Init( void )函数
void ZDO_Init( void )
{
// Initialize ZD items
#if defined ( REFLECTOR )
ZDO_EDBind = NULL;
#endif
// Setup the device - type of device to create.
ZDODeviceSetup();
}
static void ZDODeviceSetup( void )
{
#if defined( ZDO_COORDINATOR )
NLME_CoordinatorInit(); //这个函数执行
#endif
#if defined ( REFLECTOR )//源绑定操作
#if defined ( 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,指示初始化设备。这时就应该到应用程序来处理的,决定来初始化为协调器,还是路由器了。
void SAPI_Init( byte task_id )
{
..............................................
if ( HalKeyRead () == HAL_KEY_SW_5)
{
// If SW5 is pressed and held while powerup, force auto-start and nv-restore off and reset
//如果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
// Set an event to start the application
osal_set_event(task_id, ZB_ENTRY_EVENT);
}
我们看了一下startOptions选项表示的是什么意思。下面的代码在ZComDef.h文件中,
#define ZCD_STARTOPT_DEFAULT_CONFIG_STATE 0x01
#define ZCD_STARTOPT_DEFAULT_NETWORK_STATE 0x02
#define ZCD_STARTOPT_AUTO_START 0x04
#define ZCD_STARTOPT_CLEAR_CONFIG ZCD_STARTOPT_DEFAULT_CONFIG_STATE
#define ZCD_STARTOPT_CLEAR_STATE ZCD_STARTOPT_DEFAULT_NETWORK_STATE
通过宏定义可以看出,他们都是默认的选项。可以看到在程序的最后启动了ZB_ENTRY_EVENT事件,
UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )
{
............................................
if ( events & ZB_ENTRY_EVENT )
{
uint8 startOptions;
// Give indication to application of device startup 这里这个函数是一空函数
zb_HandleOsalEvent( ZB_ENTRY_EVENT );
// LED off cancels HOLD_AUTO_START blink set in the stack
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
{
// blink leds and wait for external input to config and restart
HalLedBlink(HAL_LED_2, 0, 50, 500);
}
return (events ^ ZB_ENTRY_EVENT );
}
............................................
}
我们看一下ZCD_NV_STARTUP_OPTION的初始值是什么,在下面的函数中写入了ZCD_NV_STARTUP_OPTION的初始值,初始值为0.这个函数,在uint8 zgInit( void )中被调用。
uint8 zgReadStartupOptions( void )
{
// Default to Use Config State and Use Network State
uint8 startupOption = 0;
// This should have been done in ZMain.c, but just in case.
if ( osal_nv_item_init( ZCD_NV_STARTUP_OPTION,
sizeof(startupOption),
&startupOption ) == ZSUCCESS )
{
// Read saved startup control
osal_nv_read( ZCD_NV_STARTUP_OPTION,
0,
sizeof( startupOption ),
&startupOption);
}
return ( startupOption );
}
由于#define ZCD_STARTOPT_AUTO_START 0x04所以下面的判断语句不成立,也就是没有执行zb_StartRequest();函数。
if ( startOptions & ZCD_STARTOPT_AUTO_START )
这时也就是网络没有形成,没有具体确定那个是协调器,还是作为路由器。下面就是通过应用程序的按键来确定。下面是灯设备,也就是SimpleController.c文件中的按键个事件的处理过程。
void zb_HandleKeys( uint8 shift, uint8 keys )
{
uint8 startOptions;
uint8 logicalType;
// Shift is used to make each button/switch dual purpose.
if ( shift )
{
if ( keys & HAL_KEY_SW_1 )
{
}
if ( keys & HAL_KEY_SW_2 )
{
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
}
}
else
{
if ( keys & HAL_KEY_SW_1 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// Key 1 starts device as a coordinator
//当按下按键1时,读取配置信息,通过读取NV中的ZCD_NV_LOGICAL_TYPE条目,判断设备的逻辑类型,
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )
{
logicalType = ZG_DEVICETYPE_COORDINATOR;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
}
// Do more configuration if necessary and then restart device with auto-start bit set
// write endpoint to simple desc...dont pass it in start req..then reset
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
else
{
// Initiate a binding
zb_AllowBind( myAllowBindTimeout );
}
}
if ( keys & HAL_KEY_SW_2 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// Key 2 starts device as a router
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )
{
logicalType = ZG_DEVICETYPE_ROUTER;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
}
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
else
{
}
}
if ( keys & HAL_KEY_SW_3 )
{
}
if ( keys & HAL_KEY_SW_4 )
{
}
}
}
在 ZGlobals.c文件中,我们可以找到ZCD_NV_LOGICAL_TYPE的初始值是什么?
static CONST zgItem_t zgItemTable[] =
{
#if defined ( NV_INIT )
{
ZCD_NV_LOGICAL_TYPE, sizeof(zgDeviceLogicalType), &zgDeviceLogicalType
},
{
ZCD_NV_POLL_RATE, sizeof(zgPollRate), &zgPollRate
}
...............................,
}
在这个文件中我们还可以看到下面的这句话,
// Device Logical Type
uint8 zgDeviceLogicalType = DEVICE_LOGICAL_TYPE;
前面我们也有看到
#if defined ( SOFT_START )
#define DEVICE_LOGICAL_TYPE ZG_DEVICETYPE_SOFT
#define ZG_DEVICETYPE_SOFT 0x03
我们也可以看到在这个文件中的编译选项有 NV_INIT,并且在uint8 zgInit( void )函数中,对这个结构体数组进行了初始化。也就是说最后NV中的ZCD_NV_LOGICAL_TYPE条目被初始化了ZG_DEVICETYPE_SOFT值,所以if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )判断不成功,执行下面的两条语句。也就是设置设备的逻辑类型为协调器,并且写入到ZCD_NV_LOGICAL_TYPE的条目中。
logicalType = ZG_DEVICETYPE_COORDINATOR;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
下面的语句就是语句就是写入了自动启动项,并且最后重新启动了系统。我们看一下重新启动后的流程
在void SAPI_Init( byte task_id )函数中触发ZB_ENTRY_EVENT事件,进入UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )函数,对ZB_ENTRY_EVENT事件进行处理。
if ( events & ZB_ENTRY_EVENT )
{
uint8 startOptions;
// Give indication to application of device startup
zb_HandleOsalEvent( ZB_ENTRY_EVENT );
// LED off cancels HOLD_AUTO_START blink set in the stack
HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
if ( startOptions & ZCD_STARTOPT_AUTO_START )//这时这个判断就是成立的
{
zb_StartRequest();
}
else
{
// blink leds and wait for external input to config and restart
HalLedBlink(HAL_LED_2, 0, 50, 500);
}
return (events ^ ZB_ENTRY_EVENT );
}
判断成立的话,就会进入zb_StartRequest()函数。下面重点看一下zb_StartRequest()
void zb_StartRequest()
{
uint8 logicalType;
// Start the device
// start delay = min(NWK_START_DELAY, zgStartDelay) + rand() - only for fresh start, not restore
if ( zgStartDelay < NWK_START_DELAY )
zgStartDelay = 0;
else
zgStartDelay -= NWK_START_DELAY;
/*check that bad combinations of compile flag definitions and device type 这时这里的ZCD_NV_LOGICAL_TYPE条目为ZG_DEVICETYPE_COORDINATOR
#define ZG_DEVICETYPE_COORDINATOR 0x00(协调器)
#define ZG_DEVICETYPE_ROUTER 0x01(路由器)
#define ZG_DEVICETYPE_ENDDEVICE 0x02(终端)
#define ZG_DEVICETYPE_SOFT 0x03(可选择类型)*/
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
if ( ( logicalType > ZG_DEVICETYPE_ENDDEVICE ) ||
#if defined( RTR_NWK )
#if defined( ZDO_COORDINATOR )
// Only RTR or Coord possible
( logicalType == ZG_DEVICETYPE_ENDDEVICE ) ||
#else
// Only RTR possible
( logicalType != ZG_DEVICETYPE_ROUTER ) ||
#endif
#else
#if defined( ZDO_COORDINATOR )
// Error
( 1 ) ||
#else
// only ED possible
( logicalType != ZG_DEVICETYPE_ENDDEVICE ) ||
#endif
#endif
( 0 ) )
{
// error configuration
SAPI_SendCback( SAPICB_START_CNF, ZInvalidParameter, 0 );
}
else
{
ZDOInitDevice(zgStartDelay);
}
return;
}
经过一系列的错误检测,可以得出上面的if分支不成立,会执行else分支也就是ZDOInitDevice(zgStartDelay);函数。这个函数,在上面的文章中也有分析到,这个函数中就分了NV_RESTORE编译选项的定义与否,由于这里没有定义这个选项,所以会直接执行ZDAppDetermineDeviceType();。
uint8 ZDOInitDevice( uint16 startDelay )
{
uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
uint16 extendedDelay = 0;
devState = DEV_INIT; // Remove the Hold state
// Initialize leave control logic
ZDApp_LeaveCtrlInit();
// Check leave control reset settings
ZDApp_LeaveCtrlStartup( &devState, &startDelay );
// Leave may make the hold state come back
if ( devState == DEV_HOLD )
return ( ZDO_INITDEV_LEAVE_NOT_STARTED ); // Don't join - (one time).
#if defined ( NV_RESTORE )
// Get Keypad directly to see if a reset nv is needed.
// Hold down the SW_BYPASS_NV key (defined in OnBoard.h)
// while booting to skip past NV Restore.
if ( HalKeyRead() == SW_BYPASS_NV )
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
else
{
// Determine if NV should be restored
networkStateNV = ZDApp_ReadNetworkRestoreState();
}
if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
networkStateNV = ZDApp_RestoreNetworkState();
}
else
{
// Wipe out the network state in NV
NLME_InitNV();
NLME_SetDefaultNV();
}
#endif
if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE )
{
ZDAppDetermineDeviceType();
// Only delay if joining network - not restoring network state
extendedDelay = (uint16)((NWK_START_DELAY + startDelay)
+ (osal_rand() & EXTENDED_JOINING_RANDOM_MASK));
}
// Initialize device security
ZDApp_SecInit( networkStateNV );
// Trigger the network start
ZDApp_NetworkInit( extendedDelay );
return ( networkStateNV );
}
在ZDAppDetermineDeviceType();函数中,对设备进行了判断。
void ZDAppDetermineDeviceType( void )
{
if ( zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE )
return;
#if defined ( SOFT_START )
if ( zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR )
{
devStartMode = MODE_HARD; // Start as a coordinator
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
}
else
{
if ( zgDeviceLogicalType == ZG_DEVICETYPE_ROUTER )
{
softStartAllowCoord = FALSE; // Don't allow coord to start
continueJoining = TRUE;
}
devStartMode = MODE_JOIN; // Assume joining
}
#endif // SOFT_START
}
由于定义了SOFT_START编译选项,因为在按下S1按键后,把ZG_DEVICETYPE_COORDINATOR值写入了ZCD_NV_LOGICAL_TYPE条目中,在系统重新启动后,通过初始化zgDeviceLogicalType= ZG_DEVICETYPE_COORDINATOR所以这样就作为了一个协调器进行正常的启动了。后面的启动过程和前面分析是一样的形成网络,点亮绿色的灯。调用网络的初始化函数,触发ZDAppTaskID,任务中的ZDO_NETWORK_INIT事件处理。
void ZDApp_NetworkInit( uint16 delay )
{
if ( delay )
{
// Wait awhile before starting the device
osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );
}
else
{
osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
}
}
UINT16 ZDApp_event_loop( byte task_id, UINT16 events )
{
if ( events & ZDO_NETWORK_INIT )
{
// Initialize apps and start the network
devState = DEV_INIT;
ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,
DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );
// Return unprocessed events
return (events ^ ZDO_NETWORK_INIT);
}
}
从上面的分析可以得出ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
devStartMode = MODE_HARD;,
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
ZStatus_t ret;
ret = ZUnsupportedMode;
#if defined(ZDO_COORDINATOR)
if ( logicalType == NODETYPE_COORDINATOR )
{
if ( startMode == MODE_HARD )
{
devState = DEV_COORD_STARTING; //调用网络的格式化函数形成网络
ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,
zgDefaultStartingScanDuration, beaconOrder,
superframeOrder, false );
}
else if ( startMode == MODE_RESUME )
{
// Just start the coordinator
devState = DEV_COORD_STARTING;
ret = NLME_StartRouterRequest( beaconOrder, beaconOrder, false );
}
else
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
#endif
}
}
#endif // !ZDO_COORDINATOR
#if !defined ( ZDO_COORDINATOR ) || defined( SOFT_START )
if ( logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE )
{
if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) )
{
devState = DEV_NWK_DISC;
#if defined( MANAGED_SCAN )
ZDOManagedScan_Next();
ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC );
#else
ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
#endif
}
else if ( startMode == MODE_RESUME )
{
if ( logicalType == NODETYPE_ROUTER )
{
ZMacScanCnf_t scanCnf;
devState = DEV_NWK_ORPHAN;
/* if router and nvram is available, fake successful orphan scan */
scanCnf.hdr.Status = ZSUCCESS;
scanCnf.ScanType = ZMAC_ORPHAN_SCAN;
scanCnf.UnscannedChannels = 0;
scanCnf.ResultListSize = 0;
nwk_ScanJoiningOrphan(&scanCnf);
ret = ZSuccess;
}
else
{
devState = DEV_NWK_ORPHAN;
ret = NLME_OrphanJoinRequest(
zgDefaultChannelList,
zgDefaultStartingScanDuration );
}
}
else
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
#endif
}
}
#endif //!ZDO COORDINATOR || SOFT_START
if ( ret != ZSuccess )
osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
}
其实路由器的判断形成过程于其极其的相似,也是这个文件,只是把按键改成了K2,也就改变了zgDeviceLogicalType变量的值。