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

作者:宋老师,华清远见嵌入式学院讲师。

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 );
        }

文章来源:华清远见嵌入式学院原文地址:http://www.embedu.org/Column/Column877.htm 更多相关嵌入式免费资料查看华清远见讲师博文》》

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

时间: 2024-08-29 02:22:36

第1章 ZigBee协议栈初始化网络启动流程的相关文章

zigbee协议栈之按键处理流程

zigbee协议栈版本: z-stack home 1.2.1 1.按键的初始化:协议栈的按键初始化主要有两个地方,一个是初始化开始,一个是初始化结束. int main( void ) { .... InitBoard( OB_COLD ); //第一次初始化按键 .... InitBoard( OB_READY ); .... } 2.先看一下InitBoard函数的实现 void InitBoard( uint8 level ) { if ( level == OB_COLD ) { //

Netty源码分析第1章(Netty启动流程)-------->第1节: 服务端初始化

第一章:  Server启动流程 概述: 本章主要讲解server启动的关键步骤, 读者只需要了解server启动的大概逻辑, 知道关键的步骤在哪个类执行即可, 并不需要了解每一步的运作机制, 之后会对每个模块进行深度分析 第一节:服务端初始化 首先看下在我们用户代码中netty的使用最简单的一个demo: EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventL

[ZigBee] 16、Zigbee协议栈应用(二)——基于OSAL的无线控制LED闪烁分析(下)

说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c程序入口文件 这里chipcon_cstartup.s51是汇编的启动文件,ZMain.c相当于main文件,里面有main函数: 1 int main( void ) 2 { 3 osal_int_disable( INTS_ALL );// Turn off interrupts 关中断 4 HAL_

【RL-TCPnet网络教程】第30章 RL-TCPnet之SNTP网络时间获取

第30章      RL-TCPnet之SNTP网络时间获取 本章节为大家讲解RL-TCPnet的SNTP应用,学习本章节前,务必要优先学习第29章的NTP基础知识.有了这些基础知识之后,再搞本章节会有事半功倍的效果. 本章教程含STM32F407开发板和STM32F429开发板. 30.1  初学者重要提示 30.2  可用的NTP服务器 30.3  SNTP函数 30.4  SNTP配置说明(Net_Config.c) 30.5  SNTP调试说明(Net_Debug.c) 30.6  网络

第5章2节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 启动流程概览(原创)

天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文"寻求合作伙伴编写<深入理解 MonkeyRunner>书籍".但因为诸多原因,没有如愿.所以这里把草稿分享出来,所以错误在所难免.有需要的就参考下吧,转发的话还请保留每篇文章结尾的出处等信息. 每个应用都会有一个入口方法来供操作系统调用执行,Monkey这个应用的入口方法就是在Monkey.java这个类里面的,也就是说Monkey.java就是整个Monkey应用的入口类. Monkey作为一个命令行应用,

「ZigBee模块」zigbee协议栈网络管理

Zigbee协议栈网络管理 一.补充基础知识 每个cc2530芯片出厂时候都有一个全球唯一的32位MAC地址,当设备连入网络的时候,每个设备都能获得由协调器分配的16位短地址,协调器默认地址0x0000,很多时候网络就是通过短地址进行管理. 二.实验现象 路由器.设备终端发送自己定义的设备号给协调器,协调器通过接收到的设备号判断设备类型,并且获取设备的短地址,通过串口打印出来. 三.实验步骤 串口初始化 图1 先在SampleApp.c添加串口通信的头文件.(如图1) #include “MT_

「ZigBee模块」网络通讯实验-点播、组播、广播

预告下,明天还有最后一个实验<zigbee协议栈管理>......太棒了~马上就如期完成任务啦!哈哈哈 点播.组播.广播 一.基础知识补充 Zigbee的通信方式主要有三种:点播.组播.广播. 点播就是点对点通信,也就是两个设备之间的通信,不允许第三个设备收到信息. 组播就是把网络中的节点分组,每一个组员发出的信息只有相同组号的组员才能收到. 广播,最广泛的就是1个设备上发出的信息所以设备都能接收到. 二.点播实验步骤 因为要将收到的数据通过串口显示在屏幕上,所以在程序开始之前先把串口初始化吧

VxWorks5.5.1 移植RTL8139驱动和配置网络启动调试环境

运行平台 主机操作系统:Windows XP 开发环境: Tornado 2.2.1 目标机CPU:英特尔 ATOM D2550 相关知识介绍 VxWorks系统支持两种形式的网络驱动:一种是标准的BSD驱动,支持通用的BSD4.4网络API结构等和大多所BSD网络驱动类似,将网络驱动协议层与硬件驱动联系在一起:另外一种是END网络驱动,是VxWorks独有的,简称增强型网络模型(可裁剪的增强型网络堆栈,SENS-Scalable Enhanced Networks Stack). END型驱动

[ZigBee] 15、Zigbee协议栈应用(一)——Zigbee协议栈介绍及简单例子(长文,OSAL及Zigbee入门知识)

1.Zigbee协议栈简介 协议是一系列的通信标准,通信双方需要按照这一标准进行正常的数据发射和接收.协议栈是协议的具体实现形式,通俗讲协议栈就是协议和用户之间的一个接口,开发人员通过使用协议栈来使用这个协议,进而实现无线数据收发. 如图1所示:Zigbee协议分为两部分,IEEE 802.15.4定义了PHY(物理层)和MAC(介质访问层)技术规范:Zigbee联盟定义了NWK(网络层).APS(应用程序支持层).APL(应用层)技术规范.Zigbee协议栈就是将各个层定义的协议都集合在一起,