您的位置:首页 > 理论基础 > 计算机网络

ZigBee协议栈初始化网络启动流程

2014-12-03 20:15 337 查看
ZigBee的基本流程:由协调器的组网(创建PAN ID),终端设备和路由设备发现网络以及加入网络。

基本流程:main()->osal_init_system()->osalInitTasks()->ZDApp_Init(),进协议栈初始化函数ZDApp_Init()。

1.1 进入程序入口main()。

ZMain.c中

C++ Code

int main( void )

{

// Turn off interrupts

osal_int_disable( INTS_ALL );

// Initialization for board related stuff such as LEDs

HAL_BOARD_INIT();

// Make sure supply voltage is high enough to run

zmain_vdd_check();

// Initialize board I/O

InitBoard( OB_COLD );

// Initialze HAL drivers

HalDriverInit();

// Initialize NV System

osal_nv_init( NULL );

// Initialize the MAC

ZMacInit();

// Determine the extended address

zmain_ext_addr();

// Initialize basic NV items

zgInit();

#ifndef NONWK

// Since the AF isn't a task, call it's initialization routine

afInit();

#endif

// Initialize the operating system

osal_init_system();

// Allow interrupts

osal_int_enable( INTS_ALL );

// Final board initialization

InitBoard( OB_READY );

// Display information about this device

zmain_dev_info();

/* Display the device info on the LCD */

#ifdef LCD_SUPPORTED

zmain_lcd_init();

#endif

#ifdef WDT_IN_PM1

/* If WDT is used, this is a good place to enable it. */

WatchDogEnable( WDTIMX );

#endif

osal_start_system(); // No Return from here

return 0; // Shouldn't get here.

} // main()

1.2 给任务添加ID

sapi.c中

C++ Code

void osalInitTasks( void ) //为各自进程添加ID 用于任务的查找

{

uint8 taskID = 0;

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);

osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

macTaskInit( taskID++ );

nwk_init( taskID++ );

Hal_Init( taskID++ );//硬件抽象层初始化

#if defined( MT_TASK )

MT_TaskInit( taskID++ );

#endif

APS_Init( taskID++ );

ZDApp_Init( taskID++ );//判断如果协调器节点建立网络、如果终端节点加入网络

SAPI_Init( taskID );

}

1.3 初始化ZigBee协议栈网络

ZDApp.c

C++ Code

void ZDApp_Init( uint8 task_id )

{

// 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.

// Check for manual "Hold Auto Start"

//检测到有手工设置HAL_KEY_SW_1则会设置devState = DEV_HOLD,从而避开网络初始化

ZDAppCheckForHoldKey();

// Initialize ZDO items and setup the device - type of device to create.

ZDO_Init(); //通过判断预编译来开启一些函数功能

// 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

// Start the device?

if ( devState != DEV_HOLD )

{

ZDOInitDevice( 0 );

}

else

{

// Blink LED to indicate HOLD_START

HalLedBlink ( HAL_LED_4, 0, 50, 500 );

}

ZDApp_RegisterCBs();

} /* ZDApp_Init() */

如果设置devState为DEV_HOLD,则不会执行ZDOInitDevice;反之,系统会调用此函数是设备组网或者入网。看下这个函数完成的功能是什么样子的。ZDOInitDevice是设备在网络中启动。它会读取NV中的ZCD_NV_STARTUP_OPTION选项决定是否恢复网络状态。如果应用层强制进行新的join操作,它应该在调用这个函数之前设置ZCD_NV_STARTUP_OPTION中的ZCD_STARTOPT_DEFAULT_NETWORK_STATE位。可以调用zgWrieStartupOptions()函数完成这些设置。

1.4 初始化设备(启动网络和设置网络类型)

ZDApp.c

C++ Code

uint8 ZDOInitDevice( uint16 startDelay )

{

uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;

uint16 extendedDelay = 0;

if ( devState == DEV_HOLD )

{

// Initialize the RAM items table, in case an NV item has been updated.

zgInitItems( FALSE );

}

ZDConfig_InitDescriptors();

//devtag.071807.todo - fix this temporary solution

_NIB.CapabilityInfo = ZDO_Config_Node_Descriptor.CapabilityFlags;

devState = DEV_INIT; // Remove the Hold state

// 函数读取NV项目ZCD_NV_LEAVE_CTRL的值,ZDApp_LeaveCtrl指向这个值

// Initialize leave control logic

ZDApp_LeaveCtrlInit();

// Check leave control reset settings//设备的断开会造成DEV_HOLD状态

ZDApp_LeaveCtrlStartup( &devState, &startDelay );

// Leave may make the hold state come back

if ( devState == DEV_HOLD )

{

//设置启动选项

// Set the NV startup option to force a "new" join.

zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );

//通知应用层触发事件

// Notify the applications

osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );

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

{

// 通过读取ZCD_NV_STARTUP_OPTION选项决定是否进行网络恢复

// 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 the security for type of device

ZDApp_SecInit( networkStateNV );

// 触发启动网络

// Trigger the network start

ZDApp_NetworkInit( extendedDelay );

// set broadcast address mask to support broadcast filtering 用于处理合法的广播地址

NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags );

return ( networkStateNV );

}

这个函数注意功能:初始化设备配置,ZDAppDetermineDeviceType()设置网络类型(协调、路由、终端),ZDApp_NetworkInit( extendedDelay )初始化网络并开启或加入网络。

1.5 定时开启网络

ZDApp.c

进入ZDApp_NetworkInit()函数,等待一段时间在执行ZDO_NETWORK_INIT,跳入事件处理ZDApp层ZDAPP_EVENT_LOOP()函数开启网络。

C++ Code

void ZDApp_NetworkInit( uint16 delay )

{

if ( delay )

{

// Wait awhile before starting the device

osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );

//发送ZDO_NETWORK_INIT(网络初始化)消息到 ZDApp层,转到ZDApp层,ZDApp_event_loop()函数。

}

else

{

osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );

}

}

1.6 启动设备

ZDApp.c

ZDApp_event_loop()函数是回调函数,循环处理主事件。设备逻辑类型,启动模式,信标时间,超帧长度

C++ Code

UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )

{

uint8 *msg_ptr;

if ( events & SYS_EVENT_MSG )

{

while ( (msg_ptr = osal_msg_receive( ZDAppTaskID )) )

{

ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );

// Release the memory

osal_msg_deallocate( msg_ptr );

}

// Return unprocessed events

return (events ^ SYS_EVENT_MSG);

}

if ( events & ZDO_NETWORK_INIT )

{

// Initialize apps and start the network

devState = DEV_INIT;

//设备逻辑类型,启动模式,信标时间,超帧长度,接着转到去启动设备,转到ZDO_StartDevice()

ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,

DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );

// Return unprocessed events

return (events ^ ZDO_NETWORK_INIT);

}

if ( ZSTACK_ROUTER_BUILD )

{

if ( events & ZDO_NETWORK_START )

{

ZDApp_NetworkStartEvt();

// Return unprocessed events

return (events ^ ZDO_NETWORK_START);

}

if ( events & ZDO_ROUTER_START )

{

if ( nwkStatus == ZSuccess )

{

if ( devState == DEV_END_DEVICE )

devState = DEV_ROUTER;

osal_pwrmgr_device( PWRMGR_ALWAYS_ON );

}

else

{

// remain as end device!!

}

osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );

// Return unprocessed events

return (events ^ ZDO_ROUTER_START);

}

}

if ( events & ZDO_STATE_CHANGE_EVT )

{

ZDO_UpdateNwkStatus( devState );

// At start up, do one MTO route discovery if the device is a concentrator

if ( zgConcentratorEnable == TRUE )

{

// Start next event

osal_start_timerEx( NWK_TaskID, NWK_MTO_RTG_REQ_EVT, 100 );

}

// Return unprocessed events

return (events ^ ZDO_STATE_CHANGE_EVT);

}

if ( events & ZDO_COMMAND_CNF )

{

// User defined logic

// Return unprocessed events

return (events ^ ZDO_COMMAND_CNF);

}

if ( events & ZDO_NWK_UPDATE_NV )

{

ZDApp_SaveNetworkStateEvt();

// Return unprocessed events

return (events ^ ZDO_NWK_UPDATE_NV);

}

if ( events & ZDO_DEVICE_RESET )

{

// The device has been in the UNAUTH state, so reset

// Note: there will be no return from this call

SystemReset();

}

if ( ZG_SECURE_ENABLED )

{

return ( ZDApp_ProcessSecEvent( task_id, events ) );

}

else

{

// Discard or make more handlers

return 0;

}

}

1.7 开启网络

ZDObject.c

C++ Code

void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )

{

ZStatus_t ret;

#if defined ( ZIGBEE_FREQ_AGILITY )

static uint8 discRetries = 0;

#endif

#if defined ( ZIGBEE_COMMISSIONING )

static uint8 scanCnt = 0;

#endif

ret = ZUnsupportedMode;

if ( ZG_BUILD_COORDINATOR_TYPE && logicalType == NODETYPE_COORDINATOR ) //当设备作为协调器时,执行这个条件语句。

{

if ( startMode == MODE_HARD )

{

devState = DEV_COORD_STARTING;

//向网络层发送网络形成请求。当网络层执行 NLME_NetworkFormationRequest()建立网络后,将给予ZDO层反馈信息。

// 接着转去执行ZDApp层的 ZDO_NetworkFormationConfirmCB()函数

ret = NLME_NetworkFormationRequest( zgConfigPANID, zgApsUseExtendedPANID, 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

}

}

if ( ZG_BUILD_JOINING_TYPE && (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 );

#if defined ( ZIGBEE_FREQ_AGILITY )

if ( !( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE ) &&

( ret == ZSuccess ) && ( ++discRetries == 4 ) )

{

// For devices with RxOnWhenIdle equals to FALSE, any network channel

// change will not be recieved. On these devices or routers that have

// lost the network, an active scan shall be conducted on the Default

// Channel list using the extended PANID to find the network. If the

// extended PANID isn't found using the Default Channel list, an scan

// should be completed using all channels.

zgDefaultChannelList = MAX_CHANNELS_24GHZ;

}

#endif // ZIGBEE_FREQ_AGILITY

#if defined ( ZIGBEE_COMMISSIONING )

if (startMode == MODE_REJOIN && scanCnt++ >= 5 )

{

// When ApsUseExtendedPanID is commissioned to a non zero value via

// application specific means, the device shall conduct an active scan

// on the Default Channel list and join the PAN with the same

// ExtendedPanID. If the PAN is not found, an scan should be completed

// on all channels.

// When devices rejoin the network and the PAN is not found from

zgDefaultChannelList = MAX_CHANNELS_24GHZ;

}

#endif // ZIGBEE_COMMISSIONING

#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

}

}

if ( ret != ZSuccess )

osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );

}

1.8 开启网络事件

ZDApp.c

C++ Code

void ZDO_NetworkFormationConfirmCB( ZStatus_t Status )

{

nwkStatus = (byte)Status;

if ( Status == ZSUCCESS )

{

// LED on shows Coordinator started

HalLedSet ( HAL_LED_3, HAL_LED_MODE_ON );

// LED off forgets HOLD_AUTO_START

HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);

#if defined ( ZBIT )

SIM_SetColor(0xd0ffd0);

#endif

if ( devState == DEV_HOLD )

{

// Began with HOLD_AUTO_START

devState = DEV_COORD_STARTING;

}

}

#if defined(BLINK_LEDS)

else

HalLedSet ( HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED to show failure

#endif

osal_set_event( ZDAppTaskID, ZDO_NETWORK_START );

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: