作者:宋老师,华清远见嵌入式学院讲师。
ZigBee的基本流程:由协调器的组网(创建PAN ID),终端设备和路由设备发现网络以及加入网络。
基本流程:main()->osal_init_system()->osalInitTasks()->ZDApp_Init(),进协议栈初始化函数ZDApp_Init()。
1.1 进入程序入口main()。
ZMain.c中
C++ Code
int main( void ){// Turn off interruptsosal_int_disable( INTS_ALL );// Initialization for board related stuff such as LEDsHAL_BOARD_INIT();// Make sure supply voltage is high enough to runzmain_vdd_check();// Initialize board I/OInitBoard( OB_COLD );// Initialze HAL driversHalDriverInit();// Initialize NV Systemosal_nv_init( NULL );// Initialize the MACZMacInit();// Determine the extended addresszmain_ext_addr();// Initialize basic NV itemszgInit();#ifndef NONWK// Since the AF isn't a task, call it's initialization routineafInit();#endif// Initialize the Operating systemosal_init_system();// Allow interruptsosal_int_enable( INTS_ALL );// Final board initializationInitBoard( OB_READY );// Display information about this devicezmain_dev_info();/* Display the device info on the LCD */#ifdef LCD_SUPPORTEDzmain_lcd_init();#endif#ifdef WDT_IN_PM1/* If WDT is used, this is a good place to enable it. */WatchDogEnable( WDTIMX );#endifosal_start_system(); // No Return from herereturn 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++ );#endifAPS_Init( taskID++ );ZDApp_Init( taskID++ );//判断如果协调器节点建立网络、如果终端节点加入网络SAPI_Init( taskID );}
1.3 初始化ZigBee协议栈网络
ZDApp.c
C++ Code
void ZDApp_Init( uint8 task_id ){// Save the task IDZDAPPTaskID = task_id;// Initialize the ZDO global device short address storageZDAppNwkAddr.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_STARTHalLedBlink ( 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 logicZDApp_LeaveCtrlInit();// Check leave control reset settings//设备的断开会造成DEV_HOLD状态ZDApp_LeaveCtrlStartup( &devState, &startDelay );// Leave may make the hold state come backif ( devState == DEV_HOLD ){//设置启动选项// Set the NV startup option to force a "new" join.zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );//通知应用层触发事件// Notify the applicationsosal_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 restorednetworkStateNV = ZDApp_ReadNetworkRestoreState();}if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE ){networkStateNV = ZDApp_RestoreNetworkState();}else{// Wipe out the network state in NVNLME_InitNV();NLME_SetDefaultNV();}#endifif ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE )//如果是要启动新的网络{ZDAppDetermineDeviceType();//根据选项设置设备的网络类型,默认路由类型// Only delay if joining network - not restoring network stateextendedDelay = (uint16)((NWK_START_DELAY + startDelay)+ (osal_rand() & EXTENDED_JOINING_RANDOM_MASK));}// Initialize the security for type of deviceZDApp_SecInit( networkStateNV );// 触发启动网络// Trigger the network startZDApp_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 deviceosal_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 memoryosal_msg_deallocate( msg_ptr );}// Return unprocessed eventsreturn (events ^ SYS_EVENT_MSG);}if ( events & ZDO_NETWORK_INIT ){// Initialize apps and start the networkdevState = DEV_INIT;//设备逻辑类型,启动模式,信标时间,超帧长度,接着转到去启动设备,转到ZDO_StartDevice()ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_INIT);}if ( ZSTACK_ROUTER_BUILD ){if ( events & ZDO_NETWORK_START ){ZDApp_NetworkStartEvt();// Return unprocessed eventsreturn (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 eventsreturn (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 concentratorif ( zgConcentratorEnable == TRUE ){// Start next eventosal_start_timerEx( NWK_TaskID, NWK_MTO_RTG_REQ_EVT, 100 );}// Return unprocessed eventsreturn (events ^ ZDO_STATE_CHANGE_EVT);}if ( events & ZDO_COMMAND_CNF ){// User defined logic// Return unprocessed eventsreturn (events ^ ZDO_COMMAND_CNF);}if ( events & ZDO_NWK_UPDATE_NV ){ZDApp_SaveNetworkStateEvt();// Return unprocessed eventsreturn (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 callSystemReset();}if ( ZG_SECURE_ENABLED ){return ( ZDApp_ProcessSecEvent( task_id, events ) );}else{// Discard or make more handlersreturn 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;#endifret = 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 coordinatordevState = 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 );#elseret = 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 fromzgDefaultChannelList = 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 startedHalLedSet ( HAL_LED_3, HAL_LED_MODE_ON );// LED off forgets HOLD_AUTO_STARTHalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);#if defined ( ZBIT )SIM_SetColor(0xd0ffd0);#endifif ( devState == DEV_HOLD ){// Began with HOLD_AUTO_STARTdevState = DEV_COORD_STARTING;}}#if defined(BLINK_LEDS)elseHalLedSet ( HAL_LED_3, HAL_LED_MODE_Flash ); // Flash LED to show failure#endifosal_set_event( ZDAppTaskID, ZDO_NETWORK_START );}
文章来源:华清远见嵌入式学院,原文地址:http://www.embedu.org/Column/Column877.htm 更多相关嵌入式免费资料查看华清远见讲师博文》》
新闻热点
疑难解答