ZIGBEE协调器启动
- 格式:doc
- 大小:52.50 KB
- 文档页数:14
ZigBee技术概述1ZigBee技术简介 (1)2 ZigBee结构 (2)2.1物理层 (2)2.2 MAC层 (4)2.3 网络层 (6)2.4 应用层 (7)1ZigBee技术简介ZigBee技术是一种近距离、低功耗、低成本、低传输速率的具有统一技术标准的短距离无线通信技术,符合IEEE 802.5.4标准,主要适用于工业、家庭自动控制以及远程控制领域,目的是为了满足小型廉价设备的无线联网和控制。
ZigBee技术并不是完全独有、全新的标准。
它的物理层、MAC层采用了IEEE 802.15.4(无线个人区域网)协议标准,并在此基础上进行了完善和扩展。
其网络层、应用会聚层和高层应用规范由ZigBee联盟进行了制定。
根据IEEE 802.15.4协议标准,ZigBee的工作频段分为3个频段,这3个工作频段相距较大,而且在各频段上的信道数目不同,因而,在该项技术标准中,各频段上的调制方式和传输速率不同。
它们分别为868MHz、915MHz和2.4GHz,其中2.4GHz频段上,分为16个信道,该频段为全球通用的工业、科学、医学(ISM)频段,且该频段为免付款、免申请的无线电频段,在该频段上,数据传输速率为250kbPs,另外两个频段为868/915MHz,其相应的信道数分别为10个信道和1个信道,传输速率分别为40kbPs和20kbPs。
在网络性能上,ZigBee设备可构造星型网络或者点对点网络,在每一个ZigBee组成的无线网络内,连续地址码分为16bit短地址或者64bit长地址,可容纳的最大网络设备个数分别为216个和264个,具有较大的网络容量。
在无线通信技术上,采用免冲突多载波信道接入(CSMA/CA)方式,有效地避免了无线电载波之间的冲突,此外,为保证数据传输的可靠性,建立了完整的应答通信协议。
ZigBee设备为低功耗设备,其发射功率为,通信距离为30-70m,具有能量检测和链路质量指示能力,根据这些检测结果,设备可自动调整发射功率,在保证通信链路质量的条件下,最小地消耗设备能量。
ZigBeeLED设备启动流程ZigBee LED设备启动流程及按键机制一.先对LED引脚进行相关配置,主要在两个文件中修改(hal_board_cfg.h ,Hal_led.h )hal_board_cfg.h定义我们三个LED的引脚配置分别是 P1_0 P1_1 P0_4 , 低电平有效。
/* 1 - Green */#define LED1_BV BV(0)#define LED1_SBI T P1_0#define LED1_DDR P1DIR#define LED1_POLARITY ACTIVE_LOW/* 2 - Red */#define LED2_BV BV(1)#define LED2_SBIT P1_1#define LED2_DDR P1DIR#define LED2_POLARITY ACTI VE_LOW/* 3 - Yellow */#define LED3_BV BV(4)#define LED3_SBIT P0_4#define LED3_DDR P0DIR#define LED3_POLARITY ACTI VE_LOW在HAL_BOARD_INI T将三个LED引脚配置为输出#define HAL_BOARD_INIT(){……………..设置LED1 LED2 LED3 引脚为输出LED1_DDR |= LED1_BV;LED2_DDR |= LED2_BV;LED3_DDR |= LED3_BV;}/* ----------- LED's ---------- */#define HAL_TURN_OFF_LED1() st( LED1_SBI T = LED1_POLARITY (0); ) //关灯#define HAL_TURN_ON_LED1() st( LED1_SBI T = LED1_POLARITY (1); ) //开灯#define HAL_TOGGLE_LED1() st( if (LED1_SBIT) { LED1_SBIT = 0; } else { LED1_SBI T = 1;} ) //取反#define HAL_STATE_LED1() (LED1_POLARITY (LED1_SBI T)) //获取状态Hal_led.h定义了3个LED/* LEDS - The LED number is the same as the bit position */ #define HAL_LED_1 0x01#define HAL_LED_2 0x02#define HAL_LED_3 0x04#define HAL_LED_ALL (HAL_LED_1 | HAL_LED_2 | HAL_LED_3) /* Modes 定义了LED的一些模式*/#define HAL_LED_MODE_OFF 0x00#define HAL_LED_MODE_ON 0x01#define HAL_LED_MODE_BLINK 0x02#define HAL_LED_MODE_FLASH 0x04#define HAL_LED_MODE_TOGGLE 0x08/* Defaults 定义了一些LED的控制模式*/#define HAL_LED_DEFAULT_MAX_LEDS 4#define HAL_LED_DEFAULT_DUTY_CYCLE 5#define HAL_LED_DEFAULT_FLASH_COUNT 50#define HAL_LED_DEFAULT_FLASH_TIME 1000二、初始化LED灯可以看到main()函数进来,后HAL_BOARD_INIT()进行了系统时钟的初始化,还将LED灯配置为输出状态。
Zigbee工程启动流程解析1、Zigbee工程启动流程解析初始化流程:main() -> osal_init_system() -> osalInitTasks() -> GenericApp_Init()事件流程: main() -> osal_start_system() -> (tasksArr[idx])( idx, events ) -> GenericApp_ProcessEvent()2、GenericApp_ProcessEvent()中if ( events & SYS_EVENT_MSG ):SYS_EVENT_MSG是协议栈已经定义好的系统事件if ( events & GENERICAPP_SEND_MSG_EVT ):GENERICAPP_SEND_MSG_EVT就是用户自定义的事件事件号是一个16bit的常量,使用独热码(one-hot code)编码,方便进行event的提取,这样一个task中最多可以有16个event,SYS_EVENT_MSG已经占用了0x8000,故自定义的事件只能有16个。
事件提取events & GENERICAPP_SEND_MSG_EVT,事件清除events ^ GENERICAPP_SEND_MSG_EVT。
用户可以自定义系统事件的消息范围为0xE0~0xFF3、AF_INCOMING_MSG_CMD:当模块接收到属于自己的无线数据信息时就会触发消息ZDO_STATE_CHANGE:当网络状态改变时就会触发此消息4、osal_start_timerEx( GenericApp_TaskID,GENERICAPP_SEND_ MSG_EVT,GENERICAPP_SEND_MSG_TIMEOUT )osal_start_timerEx()的作用是启动一系统定时器,当其溢出(GENERICAPP_SEND_MSG_TIMEOUT)时,会触发task (GenericApp_TaskID)的事件(GENERICAPP_SEND_MSG_EVT)。
ZigBee协议架构ZigBee协议是一种低功耗、近距离无线通信协议,主要应用在无线传感器网络(WSN)中。
它是由ZigBee联盟(ZigBee Alliance)所定义和推广的,旨在为物联网设备之间的通信提供一个标准化的解决方案。
本文将介绍ZigBee协议的架构和其主要组件,以及在物联网应用中的应用场景。
一、ZigBee协议架构概述ZigBee协议采用了分层的架构,以便于各个组件的模块化和扩展性。
ZigBee协议架构一般可分为两个主要层次:应用层和网络层。
下面将详细介绍每个层次的主要组件和功能。
1. 应用层应用层是ZigBee协议栈的顶层,负责实现各种应用的功能。
它可以与不同类型的传感器和执行器进行通信,并执行各种任务,如数据采集、控制和管理等。
应用层使用ZigBee Cluster Library(ZCL)定义了一系列的应用框架和应用集群,以便开发人员可以方便地构建自己的应用。
2. 网络层网络层是ZigBee协议栈的中间层,负责实现节点之间的通信和路由功能。
它使用ZigBee网络堆栈协议(ZigBee Network Stack Protocol)来处理数据包的发送和接收,以及路由选择和网络管理等功能。
网络层的核心组件包括ZigBee协调器(ZigBee Coordinator)、路由器(Router)和终端设备(End Device)。
二、ZigBee协议架构组件1. ZigBee协调器ZigBee协调器是在ZigBee网络中的关键组件,它负责启动和管理整个网络,以及分配网络地址和加密密钥等。
协调器可以与多个路由器和终端设备建立连接,并通过网络层协议进行数据传输和路由选择。
此外,协调器还负责处理网络中的任何故障或冲突,并重新分配资源以保持网络的可靠性和稳定性。
2. 路由器路由器是ZigBee网络中的中间节点,它负责转发数据包并实现网络层的路由选择功能。
路由器可以与其他路由器和终端设备建立连接,并通过网络层协议将数据包从源节点传输到目标节点。
Zigbee入门指导(二)——运行Zigbee例程在Zigbee入门指导(一)中讲解了基于CC2430的Zigbee 开发环境的搭建,安装完Ti的协议栈后,里面有多个例程,帮助用户入门及作为自己工程的基本框架。
在Zigbee入门指导(二)中,我们将通过演示执行相关的例程,了解Zigbee应用的启动流程(不是Zigbee网络的启动流程),了解运行一个自定义Zigbee工程所要作的软件方面的改动和工程选项的配置。
所用的开发套件为无线龙的套件。
一、修改HALHAL及所谓的Hardware Abstration Layer,通俗的了解即为开发板的硬件驱动,由于所用的是无线龙的开发板,与Ti的原装开发板有差异,需要对协议栈自带的HAL进行修改。
HAL文件存放在目录<Components/hal>中,里面有<common>、<include>、<target>三个目录,<common>中定义的与外设无关的硬件操作,<include>存放的是头文件,而<target>存放的是目标文件,里面根据目标板的不同分为<CC2430BB>、<CC2430DB>、<CC2430EB>。
所用的无线龙的开发板和CC2430EB最为相似,故修改<CC2430EB>中的内容。
按键操作几乎在每个例程中都会用到,故此处以按键驱动的修改为例,演示HAL的修改。
先了解下Ti和无线龙扩展板的不同之处。
Ti的CC2430EB 原理图在Ti文档SWRU133.pdf(位于SWRU133.zip中)。
Page29是按键电路的原理图,如图1图1(左上角是元件图)CC2430EB的按键其实是摇杆,上下左右四个方向和电阻网络相连,通过放大电路送到CC2430的P0.6脚,经AD采样后判断摇杆摆向哪个方向,按键编号为SW1~SW4摇杆也可像普通按键一样按下,产生一个直流电平变化,接到P0.5脚,按键编号为SW5。
ZigBee模块设置1.ZigBee模块F8913D插入配置基板F8913-EVB(注:基板排针接口与模块插针序号正确对应,不可反插。
否则,模块可能烧坏。
)2.用USB连接线,连接配置基板与电脑。
配置基板通过USB口供电。
电脑端打开ZigBeeConfig.exe3.查看端口号,,,(如何查看端口号,详见备注2)4.参数设置,配置步骤如图。
串口波特率:9600校验:无校验停止位:1个停止位是否启用硬件控制流:不勾选调试等级:0AT命令是否回显:不勾选网络号:自行设置(同一网络内模块和网关的网络号必须相同)节点类型:路由 分节点网络地址:自行设置(同一网络内的设备不能有相同网络地址) 透传地址:0 重新自52A8加入网络:勾选 物理信道:26 应用模式: 透传模块设置关键参数说明:网络号:网络号是ZigBee 判断是否在同一个网络的标志,只有网络号相同的设备才会互相组网,互相通信。
节点类型:同一网络,有且仅有一个协调器。
路由具备转发其他模块数据功能,终端不具有该功能。
1 92 34 5 67 8分节点网络地址:即ZigBee 设备本机在网络内的地址标志,协调器不能修改,默认固定为0,路由或终端可设置为非0 的其它数值,一个ZigBee 设备设置完网络地址后这个地址在本网络内就是唯一的,不可再重复加入这个地址的设备。
透传地址:即本ZigBee 设备串口收到的数据要发送的目标ZigBee 设备的分节点网络地址,在透传模式下,只要指定了透传地址,那么本设备发出的数据都会发送给那个分节点网络地址的zibgee 设备。
例如:ZigBee1(分节点网络地址为10)---ZigBee2(分节点网络地址为13)ZigBee1 要把串口收到的数据发给ZigBee2,ZigBee1 的透传地址就要指定为13,ZigBee2 把串口收到的数据发给ZigBee1,那ZigBee2 的透传地址就要设置为10。
物理信道:要互相通信的设备必须设置为一样的信道,推荐使用15,20,25,26 信道,可减少WIFI的干扰。
zigbee技术介绍ZigBee作为用于个人网络的短距离无线通信协议,已变得越来越知名。
Zigbee是一种适用于短距离无线通信的低成本,低功耗,低速的新技术,可以嵌入各种电子设备中。
该技术主要设计用于低速通信网络。
它的最大特点是低功耗和联网功能,尤其是具有路由功能的联网功能。
从理论上讲,ZigBee覆盖的通信领域可以无限扩展。
ZigBe包含3种节点类型,即:协调器,路由节点和终端节点。
●协调器——启动网络和维护网络●路由节点——转发数据包●终端节点——发送和接收数据。
在实际的Zigbee网络中,仅支持两种无线设备:全功能设备和简化功能设备。
FFD可以提供所有IEEE802.15.4协议服务,不仅可以发送和接收数据,还可以具有路由功能;最终节点负责收集数据,然后将其发送到协调点或路由节点进行处理。
这三种类型的节点使ZigBee支持三种网络拓扑:星形结构,树形结构和网状结构Zigbee协议无线通信技术的特点:●低速率:数据传输速率在10Kb/s〜250Kb/s之间●低功耗:在低功耗待机模式下,两节普通5号电池可以使用6到24个月●成本低:Zigbee数据传输速率低,协议简单,大大降低了成本●网络容量大:网络可容纳65,000个设备●短延迟:典型的搜索设备延迟为30ms,睡眠激活延迟为15ms,活动设备通道访问延迟为15ms。
数据安全性:Zigbee提供数据完整性检查和声音功能,采用AES-128加密算法,并且每个应用程序都可以灵活确定其安全属性基于ZigBee技术的应用数字家庭ZigBee模块可以安装在电视,门禁系统,空调系统和其他家用电器中。
通过ZigBee终端设备,可以收集各种家庭信息并将其传输到中央控制设备,或者可以使用远程控制来实现远程控制的目的,从而提供家庭生活自动化,联网和智能化。
自动抄表读数通过ZigBee网络直接发送到提供天然气,水和电的公司。
利用ZigBee技术,天然气或水电公司可以直接向用户发送用水、用电、用气等信息,十分方便。
zigbee协调器和终端对话实验遇到的问题与解决办法1、组网后,怎样获取新加入的Endpoint的地址?答:现在有一个最常见的场景,我有一个100个节点的网络同时发送数据给协调器,我很想知道那个地址对应那个节点。
其实楼上的就想知道那个,以前老板也经常问我这个问题。
即使知道了某个节点的IEEE地址还是不知道是某个节点,除非你事先知道那个节点的地址。
你不可能一个一个节点上电在轮询获得地址吧?如果那样的话,我还不如直接加下NV_RESTORE之后断电一个一个标。
终端在给协调器发送的数据包中就包含自己的地址信息就可以了,这样协调器即不用浪费自己的RAM空间来保存所有节点的地址信息,也不用花时间来查询了。
因为MAC地址是唯一的,所以可以用MAC地址。
还记得毛子在太空用铅笔的典故么?这里有个笨办法,在批量烧写CC2530的时候,就把它的IEEE地址读出来,然后贴在标签上。
A:请问zigbee怎么通过mac地址获得网络中挂在路由下的节点的短地址,用APSME_LookupNwkAddr得到短地址时,只能查找协调器儿子节点,对孙子节点不可访问,afStatus_t ZDP_NwkAddrReq(byte*IEEEAddress,byte ReqType,byte StartIndex,byte SecurityEnable)根据已知网络地址查询远程设备物理地址,作为一个广播信息发送给网络中的所有设备:这个函数也是知道IEEE地址,对短地址进行寻找,这个不存在上面所说的限制,但是这个短地址放在那里呢,我怎么获得这个短地址呢?B:请使用函数:afStatus_t ZDP_NwkAddrReq(uint8*IEEEAddress,byte ReqType,byte StartIndex,byte SecurityEnable)2、问题:请问调用这个函数获得的地址放在那里呢?答:会有callback函数上来的,对应的处理事件是#define NWK_addr_rsp(NWK_addr_req|ZDO_RESPONSE_BIT)void ZDApp_ProcessMsgCBs(zdoIncomingMsg_t*inMsg)的switch case下面做添加就可以,然后去处理获得的地址3、问题:ZigBee网络中协调器分配网络地址在哪?如何查看设备的网络地址?答:协调器的短地址是0x0000,当设备加入成功后,会产生一个ZDO_STATE_CHANGE_EVT事件,这个事件就是设备加入网络成功后,并在网络中的身份确定后产生的一个事件,我们可以在这里处理,一些初始化,比如可以发送终端的短地址,IEEE地址等,这里协调器接收到以后,可以提取出终端的短地址,其实在终端给协调器发送的每个数据包中,都含有其自身的短地址,如结构体当中的afAddrType_t srcAddr;协调器在接收到短地址后,就可以知道自己下面管辖的终端节点,或者路由节点有哪些了?协调器提取到的短地址可以存放到一个非易失性的存储器中。
Zigbee简介:Zigbee网络通常由三种节点构成:z协调器(Coordinator):用来创建一个Zigbee网络,并为最初加入网络的节点分配地址,每个Zigbee网络需要且只需要一个Coordinator.z路由器(Router):也称为Zigbee全功能节点,可以转发数据,起到路由的作用,也可以收发数据,当成一个数据节点,还能保持网络,为后加入的节点分配地址.z终端节点(End Device):通常定义为电池供电的低功耗设备,通常只周期性发送数据。
或者通过休眠按键控制节点的休眠或工作。
注意:三种Zigbee节点的P ANID在相同的情况下,可以组网并且互相通讯(上电即组网,不需要人为干预)。
这样可以通过P ANID区分zigbee网络,在同一个区域内,可以同时并存多个zigbee网络,互相不会干扰。
Panid设置见下。
管脚定义:z P1.5:休眠键,输入脚,p1.5拉高时,休眠有效。
模块如果是Cornidator、Router 时此脚无效,只有模块是Enddevice时,此脚才有效,如果不需要休眠功能,则此脚与GND连接。
z p1.7:Set键,输入脚,p1.7拉高时候,设置功能有效,平时模块处于数据收发状态时,此引脚应为低电平,具体设置功能见下节z p2.0 网络连接状态灯,输出脚,模块如果是Router或Enddevice时,此按键表明当前模块是否入网,高电平表明入网,低电平表明没有入网。
z p0.2:Rx,与外置MCU的Tx连接z P0.3:Tx,与外置MCU的Rx连接z GND:电源地z VCC:电源3.3V用户在使用时候,可以根据自己需要选择引脚。
最简单的情况是只使用Rx、Tx.、GND、VCC四个脚,但需要将P1.5(休眠键)、P1.7(设置键)接地。
P2.0(网络连接状态)悬空。
当P1.7为高,通过串口对模块进行设置,数据格式如下(以下数据均为16进制):说明:模块处于设置状态时,波特率固定为38400.即P1.7为高时,模块波特率为38400;P1.7为低时,波特率为设置的波特率,波特率设置见下面命令。
Zigbee网络设备启动流程—协调器(自启动模式)(转)使用的协议栈版本信息: ZigBee2006\ZStack-1.4.3-1.2.1Zigbee网络设备启动流程—协调器(自启动模式)—以SampleApp的协调器为例.1、协调器预编译信息通过project->options->c/c++compiler->extraOptions可以看到协调器所带的配置文件为:-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wCoord.cfg-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wConfig.cfg即编译了ZDO_COORDINATOR和RTR_NWK.通过project->options->c/c++compiler->Preprocessor->Defined symbols可以看到协调器预编译包含了:CC2430EB; ZTOOL_P1; MT_TASK; LCD_SUPPORTED=DEBUG; MANAGED_SCAN没有编译HOLD_AUTO_START和SOFT_START.2、具体流程main()->osal_init_system()->osalInitT asks()->ZDApp_Init()进入ZDApp_Init()函数:**************************************void ZDApp_Init( byte task_id ){uint8 capabilities;// Save the task IDZDAppTaskID = task_id;// Initialize the ZDO global device short address storageZDAppNwkAddr.addrMode = Addr16Bit;ZDAppNwkAddr.addr.shortAddr =INVALID_NODE_ADDR; //0xFFFE(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.// 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(); //通过判断预编译来开启一些函数功能// 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?if ( devState != DEV_HOLD ){ZDOInitDevice( 0 );}else{// Blink LED to indicate HOLD_STARTHalLedBlink ( HAL_LED_4, 0, 50, 500 );}ZDApp_RegisterCBs();}**************************************协调器没有编译HOLD_AUTO_START,也没有手工设置SW_1,初始化devState = DEV_INIT(参见基本问题说明3).因此直接在ZDApp_Init()中进入ZDOInitDevice( 0 )开启设备.**************************************uint8 ZDOInitDevice( uint16 startDelay ){//初始化设备网络状态为ZDO_INITDEV_NEW_NETWORK_STATE:新的网络状态.//可能意味着ZCD_NV_STARTUP_OPTION不能恢复,或没有任何网络状态恢复uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;uint16 extendedDelay = 0;devState = DEV_INIT; // Remove the Hold state// Initialize leave control logic//函数读取NV项目ZCD_NV_LEAVE_CTRL的值,ZDApp_LeaveCtrl指向这个值ZDApp_LeaveCtrlInit();// Check leave control reset settingsZDApp_LeaveCtrlStartup( &devState, &startDelay );// Leave may make the hold state come back//以上两个函数设置了对设备离开时的控制,如果有延时则延时,没有则//把设备状态设为DEV_HOLDif ( devState == DEV_HOLD )//ZDO_INITDEV_LEAVE_NOT_STARTED:该设备没有在网络中,下次调用才启用.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 )//SW_BYPASS_NV按键处于按下状态时,则避开网络层的NV存储networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //设备网络状态为新的网络状态else{// Determine if NV should be restored//函数返回的设备网络状态要么是新的网络状态;要么是恢复的网络状态;以此//来确定要不要读取NV里相应条目来恢复网络先前状态networkStateNV = ZDApp_ReadNetworkRestoreState();}//如果设备的网络状态为恢复的网络状态if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE ){//恢复设备先前的网络状态参数并且//设置devStartMode = MODE_RESUMEnetworkStateNV = ZDApp_RestoreNetworkState();}else //如果设备的网络状态为新的网络状态,在下面进行处理{// Wipe out(清除) the network state in NVNLME_InitNV();NLME_SetDefaultNV(); //设置默认NV条目}#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 securityZDApp_SecInit( networkStateNV );// Trigger the network startZDApp_NetworkInit( extendedDelay );return ( networkStateNV );}**************************************分两种情况:(1)如果协调器预编译了NV_RESTORE,且函数ZDApp_ReadNetworkRestoreState()返回值为ZDO_INITDEV_RESTORED_NETWORK_STATE,则进入ZDApp_RestoreNetworkState()里设置ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR和devStartMode = MODE_RESUME.****************uint8 ZDApp_RestoreNetworkState( void ){…………// Are we a coordinator//设备的网络状态为恢复的网络状态.则进入这个函数进行恢复//先判断如果短地址为0则设置设备逻辑类型为协调器且devStartMode = MODE_RESUME//否则设置devStartMode = MODE_RESUMEZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();if ( ZDAppNwkAddr.addr.shortAddr == 0 ) //如果短地址是0,即协调器{ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR; //}devStartMode = MODE_RESUME; //MODE_RESUME…………}****************(2)如果协调器没有预编译NV_RESTORE,networkStateNV ==ZDO_INITDEV_NEW_NETWORK_STATE,但由于协调器编译了ZDO_COORDINATOR而没有编译SOFT_START,因此ZDAppDetermineDeviceType()不起作用.因此ZDO_Config_Node_Descriptor.LogicalType和devStartMode这两个关键参数保持初始化时的值:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR(见基本问题说明6)devStartMode = MODE_HARD(见基本问题说明4)对于协调器,这两种情况最终都是确定两个关键设备网络状态参数的值.对本例的SampleApp的协调器,没有编译NV_RESTORE,因此属于情况(2).然后调用ZDApp_NetworkInit()启动网络:****************void ZDApp_NetworkInit( uint16 delay ){if ( delay ){// Wait awhile before starting the deviceosal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );}else{osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );}}****************通过触发ZDAppTaskID的ZDO_NETWORK_INIT事件.来看下对ZDO_NETWORK_INIT 事件的处理:****************UINT16 ZDApp_event_loop( byte task_id, UINT16 events ){…………if ( events & ZDO_NETWORK_INIT ){// Initialize apps and start the networkdevState = DEV_INIT;ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.Logi calType, devStartMode,DEFAULT_BEACON_ORDER,DEFAULT_SUPERFRAME_ORDER );// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_INIT);}…………}****************可以看到调用了ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalTy pe, devStartMode,DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );这里设备网络状态参数:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATORdevStartMode = MODE_HARD且协调器编译了ZDO_COORDINATOR****************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 ) //MODE_HARD{devState = DEV_COORD_STARTING; //Started as Zigbee Coordinator//建网ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,zgDefaultStartingScanDuration, beaconOrder,superframeOrder, false );}else if ( startMode == MODE_RESUME ) //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" );ClearScreen();Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);#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; //Discovering PAN's to join#if defined( MANAGED_SCAN )ZDOManagedScan_Next();ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC );#elseret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );#endif}else if ( startMode == MODE_RESUME ) //MODE_RESUME 恢复{if ( logicalType == NODETYPE_ROUTER ){ZMacScanCnf_t scanCnf;devState = DEV_NWK_ORPHAN;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" );Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);#endif}}//#endif //!ZDO COORDINATOR || SOFT_STARTif ( ret != ZSuccess )osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );}****************通过参数可知协调器调用NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,zgDefaultStartingScanDuration, beaconOrder,superframeOrder, false )进行网络的组建.而对NLME_NetworkFormationRequest()的调用会产生一个回调函数ZDO_NetworkFormationConfirmCB()(见主要函数说明3),来看下:****************void ZDO_NetworkFormationConfirmCB( ZStatus_t Status ) {#if defined(ZDO_COORDINATOR)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 );#endif //ZDO_COORDINATOR}****************如果Status返回ZSUCCESS,建立网络成功,通过一些灯亮来来指示;不成功则通过闪烁灯来指示.最后触发任务ZDAppTaskID的ZDO_NETWORK_START事件,看下对ZDO_NETWORK_START的处理:****************#if defined (RTR_NWK)if ( events & ZDO_NETWORK_START ){ZDApp_NetworkStartEvt();// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_START);}****************调用了ZDApp_NetworkStartEvt()****************void ZDApp_NetworkStartEvt( void ){if ( nwkStatus == ZSuccess )//网络建立成功{// Successfully started a ZigBee networkif ( devState == DEV_COORD_STARTING ){devState = DEV_ZB_COORD;}osal_pwrmgr_device( PWRMGR_ALWAYS_ON );osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );}else //网络建立不成功,则增加能量阀值重新建网.{// Try again with a higher energy threshold !!if ( ( NLME_GetEnergyThreshold() +ENERGY_SCAN_INCREMENT ) < 0xff ){NLME_SetEnergyThreshold( (uint8)(NLME_GetEnergyThresh old() + ENERGY_SCAN_INCREMENT) );osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); //重新初始化建立网络}else{// Failed to start network. Enter a dormant state (until user intervenes)devState = DEV_INIT;osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );}}}****************如果协调器建立网络成功,则触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT事件.看下对 ZDO_STATE_CHANGE_EVT 的处理:****************if ( events & ZDO_STATE_CHANGE_EVT ){ZDO_UpdateNwkStatus( devState );// Return unprocessed eventsreturn (events ^ ZDO_STATE_CHANGE_EVT);}****************调用了ZDO_UpdateNwkStatus( devState ),网络状态改变,这个函数会更新和发送信息通知每个注册登记过的应用终端.****************void ZDO_UpdateNwkStatus( devStates_t state ){// Endpoint/Interface descriptor list.epList_t *epDesc = epList;byte bufLen = sizeof(osal_event_hdr_t);osal_event_hdr_t *msgPtr;ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.while ( epDesc ){if ( epDesc->epDesc->endPoint != ZDO_EP ){msgPtr = (osal_event_hdr_t *)osal_msg_allocate( bufLen );if ( msgPtr ){msgPtr->event = ZDO_STATE_CHANGE; // Command IDmsgPtr->status = (byte)state;osal_msg_send( *(epDesc->epDesc->task_id), (byte *)msgPtr ); //发往应用任务}}epDesc = epDesc->nextDesc;}}****************对SampleApp的协调器来说,这里触发应用任务SampleApp_TaskID的ZDO_STATE_CHANGE事件,看下对ZDO_STATE_CHANGE的处理:****************case ZDO_STATE_CHANGE:SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //获取设备当前状态if ( (SampleApp_NwkState == DEV_ZB_COORD)|| (SampleApp_NwkState == DEV_ROUTER)|| (SampleApp_NwkState == DEV_END_DEVICE) ){// Start sending the periodic message in a regular interval.osal_start_timerEx( SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );}else{// Device is no longer in the network}break;****************可以看到当协调器建立网络成功,通过回调函数触发应用任务的ZDO_STATE_CHANGE事件,最终开启定时器发送周期信息.3、协调器(自启动模式)—以SampleApp的协调器为例,并假设初始化成功,网络建立成功.程序大致流程:main()->osal_init_system()->osalInitT asks()->ZDApp_Init()-> ZDOInitDevice()->ZDApp_NetworkInit->触发ZDAppT askID的ZDO_NETWORK_INIT->ZDO_StartDevice()->NLME_NetworkFor mationRequest()->网络建立成功ZDO_NetworkFormationConfirmCB->触发ZDAppT askID的ZDO_NETWORK_START->ZDApp_NetworkStartEvt()->触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT->ZDO_UpdateNwkStatus()->触发SampleApp_TaskID的ZDO_STATE_CHANGE->开户周期信息发送的定时器.4、注:(1)自启动模式下SampleApp的终端和路由器总体流程基本一致.(2)以SampleApp为例,ZDO_StartDevice()函数的两个重要参数比较:终端:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICEdevStartMode = MODE_JOIN路由器:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTERdevStartMode = MODE_JOIN协调器:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATORdevStartMode = MODE_HARD***************************************。
记录几个问题:***********************************1、有关设备的启动模式选项:(有待完善):非自动启动模式HOLD_AUTO_START:HOLD_AUTO_START is a compile option that will surpres s ZDApp from starting the device and wait for the application to start the device.不通过ZDApp(具体讲是ZDOInitDevice())而是等待应用程序来开启设备并初始化建立/加入网络.软启动模式SOFT_START:SOFT_START is a compile option that allows the device to start as a c oordinator if one isn't found. Otherwise, the device will start as a router.如果没有协调器则作为协调器启动,有则作为路由器启动.自动启动模式:个人认为就是自动通过ZDApp(具体讲是ZDOInitDevice())来开启设备并初始化建立/加入网络,设备的逻辑类型由所携带的配置文件来决定.**********************************************************************2、三种逻辑类型节点的配置文件协调器:f8wCoord.cfg配置文件中同时编译了路由功能RTR_NWK和协调器功能ZDO_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路由器:f8wRouter.cfg配置文件中编译了路由功能RTR_NWK/* 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终端:f8wEdev.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协调器的配置文件只比路由器配置文件多编译了个-DZDO_COORDINATOR // Coordinator Functions 如果同时编译非自动启动模式HOLD_AUTO_START和软启动模式SOFT_START,设备可以通过应用程序来选择成为路由器或协调器.当然这个设备所带的配置文件应为f8wCoord.cfg.对于设备携带的是何种配置文件,可以打开project->options->c/c++compiler->extraOptions选项查看.比如SampleApp中的DemoEB,同时编译了SOFT_START和HOLD_AUTO_START,貌似下载进去后通过外部跳线来选择是当协调器还是路由器,不过这部分程序已经被注销了.当然的,DemoEB所带的配置文件应该是同时编译了路由功能和协调器功能的f8wCoord.cfg,即编译了RTR_NWK和ZDO_COORDINAT OR.再比如SimpleApp中两个实验中的灯与开关实验.开关设备SimpleSwitchEB无论按K1还是K2都是作为终端设备的,其预编译选项只有HOLD_AUTO_START而没有SOFT_START,配置文件为f8wEndev.cfg,没有协调器和路由功能;而灯设备SimpleControllerEB按键K1则作为协调器,按K2则作为路由器,其预编译选项同时编译了SOFT_START和HOLD_AUTO_START,配置文件为f8wCoord.cfg,即编译了RTR _NWK和ZDO_COORDINATOR. SimpleApp中传感器实验也一样,只能作为终端设备的SimpleSensorEB 预编译了HOLD_AUTO_START,配置文件为f8wEndev.cfg;而SimpleCollectorEB按K1作为协调器按K2作为路由器,预编译了SOFT_START和HOLD_AUTO_START,配置文件f8wCoord.cfg. 可以通过project ->options->c/c++compiler->extraOptions选项查看,也可由workspace看出,如下:作为终端的开关节点与作为协调器/路由器的灯节点:空白的文件表示没有包含在这个workspace中.作为终端的传感器节点与作为协调器、路由器的中心收集节点:空白的文件表示没有包含在这个workspace 中.**********************************************************************3、有两种方式来设置非自动启动模式:Hold Auto Start(1)、手工方式:在ZDApp_Init()函数中有个ZDAppCheckForHoldKey();(// Check for manual(手工的) "Hold Auto Star t").来看下这个函数:********************void ZDAppCheckForHoldKey( void ){#if (defined HAL_KEY) && (HAL_KEY == TRUE)//直接通过读取按键来判断是否需要采用HOLD_AUTO_START 模式,如果发现//SW_1处于按下(普通按键?)/向上(Joystick up)状态,则设置devState 为DEV_HOLD;// Get Keypad directly to see if a HOLD_START is needed.// Hold down the SW_BYPASS_START key (see OnBoard.h)// while booting to avoid starting up the device.if ( HalKeyRead () == SW_BYPASS_START) //HAL_KEY_SW_1{// Change the device state to HOLD on start updevState = DEV_HOLD;}#endif // HAL_KEY}*********************可以看到如果手工使HAL_KEY_SW_1置位状态,则会设置devState = DEV_HOLD.这里HAL_KEY的初始化见hal_board_cfg.h:#ifndef HAL_KEY#define HAL_KEY TRUE#endif而对SW_BYPASS_START的初始化见OnBoard.h:// These Key definitions are unique to this development system.// They are used to bypass functions when starting up the device.//这些键的定义仅适用于本应用例子,可以在设备启动时避开一些功能://避开网络层的NV存储和避开网络初始化#define SW_BYPASS_NV HAL_KEY_SW_5 // Bypass Network layer NV restore#define SW_BYPASS_START HAL_KEY_SW_1 // Bypass Network initialization因此避开网络层NV存储也可以通过手工方式来完成.(2)、预编译方式:project->options->c/c++compiler->preprocessor->defined symbols下编译选项:HOLD_AUTO_START SimpleApp例子里四种节点都预编译了HOLD_AUTO_START:非自动启动模式在ZDApp.c中:#if defined( HOLD_AUTO_START )devStates_t devState = DEV_HOLD;#elsedevStates_t devState = DEV_INIT;#endif把devState初始化为DEV_HOLD.以上两种方式最终都会设置devState = DEV_HOLD // Initialized - not started automatically********************************************************************************4、devStartMode和devState的初始化,ZDApp.c中:devStartMode:#if defined( ZDO_COORDINATOR ) && !defined( SOFT_START )// Set the default to coodinatordevStartModes_t devStartMode = MODE_HARD;#elsedevStartModes_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编译了ZDO_COORDINATOR并且没有编译SOFT_START,则初始化devStartMode = MODE_HARD;其他情况初始化devStartMode = MODE_RESUME;比如SampleApp三种逻辑类型节点.devState:#if defined( HOLD_AUTO_START )devStates_t devState = DEV_HOLD;// Initialized - not started automatically#elsedevStates_t devState = DEV_INIT;// Initialized - not connected to anything#endif预编译了HOLD_AUTO_START,则devState = DEV_HOLD;否则devState = DEV_INIT;********************************************************************************5、存储设备逻辑类型的NV条目ZCD_NV_LOGICAL_TYPE:(1)在ZGlobals.c下的NV条目表ZGlobal Item Table有这么一个条目:static CONST zgItem_t zgItemTable[ ] ={#if defined ( NV_INIT ){ZCD_NV_LOGICAL_TYPE, sizeof(zgDeviceLogicalType), &zgDeviceLogicalType},…………}zgItem_t结构体如下:typedef struct zgItem{uint16 id;uint16 len;void *buf;} zgItem_t;ZDO全局变量zgDeviceLogicalType被初始化为uint8 zgDeviceLogicalType = DEVICE_LOGICAL_TYP E;因此这里全局变量zgDeviceLogicalType的值为NV条目ZCD_NV_LOGICAL_TYPE的值,buf指向zgD eviceLogicalType.如果在应用程序中改变了设备逻辑类型并写入NV条目ZCD_NV_LOGICAL_TYPE中,这时即全局变量zgDeviceLogicalType的值改变了(卡在这步上近两天,因为找不着改变的逻辑状态与设备开启时选择的逻辑状态之间的关系).(2)NV条目ZCD_NV_LOGICAL_TYPE的值有哪些?// Device Logical Type//NV条目ZCD_NV_LOGICAL_TYPE的值包括:(即zgDeviceLogicalType的值)// 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(3)对于DEVICE_LOGICAL_TYPE的值各逻辑类型设备初始化如下:// Device Logical Type//zgDeviceLogicalType = DEVICE_LOGICAL_TYPE#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如果编译了SOFT_START,则初始化DEVICE_LOGICAL_TYPE=ZG_DEVICETYPE_SOFT,即zgDevice LogicalType = ZG_DEVICETYPE_SOFT;如果没有编译SOFT_START但编译了ZDO_COORDINATOR,则初始DEVICE_LOGICAL_TYPE = ZG_DEVICETYPE_COORDINATOR,即zgDeviceLogicalType=Z G_DEVICETYPE_COORDINATOR;路由器和终端类似.********************************************************************************6、启动设备都要通过ZDApp_event_loop()函数调用ZDO_StartDevice()对ZDO_NETWORK_INIT事件的处理:ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );这里对于设备逻辑类型的传递参数ZDO_Config_Node_Descriptor.LogicalType,ZDConfig.c中初始化是这样的:NodeDescriptorFormat_t ZDO_Config_Node_Descriptor ={#if defined( ZDO_COORDINATOR ) && !defined( SOFT_START )NODETYPE_COORDINATOR,//协调器#elif defined (RTR_NWK)NODETYPE_ROUTER, //路由器#elseNODETYPE_DEVICE, //终端设备// Logical Type#endif…………}如果编译了ZDO_COORDINATOR且没有编译SOFT_START,则ZDO_Config_Node_Descriptor.Logical Type的值为NODETYPE_COORDINATOR; 如果没有编译ZDO_COORDINATOR或者编译了SOFT_S TART,且编译了了RTR_NWK,则ZDO_Config_Node_Descriptor.LogicalType的值为NODETYPE_ROU TER(比如simpleApp中灯节点和中心收集节点就是这种情况,因此它俩的ZDO_Config_Node_Descriptor. LogicalType被初始化为NODETYPE_ROUTER,当然当通过外部按键选择设备逻辑类型为协调器时,会通过内部程序把这个值改为NODETYPE_COORDINATOR,这点后面再作记录);剩下情况为NODETYPE_D EVICE.********************************************************************************7、simpleApp中的按键完成两个功能:设置设备的逻辑类型(ZC/ZR/ED) 和设置设备的启动方式(ZCD_STARTOPT_AUTO_START),然后写入相应的NV条目ZCD_NV_LOGICAL_TYPE和ZCD_NV_STARTUP_OPTION.ZDApp_Init()是先于应用任务如SampleApp_Init()初始化的.ZCD_NV_STARTUP_OPTION值包括:// These are bit weighted - you can OR these together.// Setting one of these bits will set their associated NV items// to code initialized values.#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 //清除状态=默认网络状态ZCD_NV_LOGICAL_TYPE值参见4.******************************************************************************8、网络状态的类型://设备的网络状态为恢复的网络状态#define ZDO_INITDEV_RESTORED_NETWORK_STATE 0x00//网络状态初始化,即设备的网络状态为新的网络状态.可能意味着ZCD_NV_STARTUP_OPTION不能恢复,或没有任何网络状态恢复#define ZDO_INITDEV_NEW_NETWORK_STATE 0x01//复位前,网络重返选项为TRUE,因此该设备在网络中没有启动(仅一次),下次调用该函数将启动.#define ZDO_INITDEV_LEAVE_NOT_STARTED 0x02********************************************************************************9、NV条目ZCD_NV_STARTUP_OPTION初始化******************************************************************************** ******************************************************************************** ********************************************************************************分析一:(错误,见分析二;暂不删除)NV条目的初始化在zgInit()中.main()函数中:***************// Initialize basic NV items/*初始化NV条目*/zgInit();***************************************** @fn zgInit** @brief** Initialize the Z-Stack Globals. If an item doesn't exist in* NV memory, write the system default into NV memory. But if* it exists, set the item to the value stored in NV memory.** NOTE: The Startup Options (ZCD_NV_STARTUP_OPTION) indicate* that the Config state items (zgItemTable) need to be* set to defaults (ZCD_STARTOPT_DEFAULT_CONFIG_STATE). The*** @param none** @return ZSUCCESS if successful, NV_ITEM_UNINIT if item did not* exist in NV, NV_OPER_FAILED if failure.*/uint8 zgInit( void ){uint8 i = 0;uint8 setDefault = FALSE;// Do we want to default the Config state valuesif ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )// 0x01 {setDefault = TRUE;}#if 0 //正常情况下被禁止来节省NV空间// Enable this section if you need to track the number of resets// This section is normally disabled to minimize "wear" on NV memory…………#endif// Initialize the Extended PAN ID as my own extended address//扩展地址ZMacGetReq( ZMacExtAddr, zgExtendedPANID );#ifndef NONWK// Initialize the Pre-Configured Key to the default keyosal_memcpy( zgPreConfigKey, defaultKey, SEC_KEY_LEN ); // Do NOT Change!!!#endif // NONWK//----------------------------------初始化各NV配置状态条目值//初始化NV条目表zgItemTable[ ].如果setDefault=TRUE,则设置为默认//值;否则读取原先存储在里面的值.while ( zgItemTable[i].id != 0x00 ){// Initialize the itemzgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault );// Move on to the next itemi++;}//----------------------------------// Clear the Config State default//如果NV条目ZCD_NV_STARTUP_OPTION的ZCD_STARTOPT_DEFAULT_CONFIG_STATE标致位为1if ( setDefault ){//把ZCD_STARTOPT_DEFAULT_CONFIG_STATE标致位清0zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE ); }return ( ZSUCCESS );}****************************************NOTE: The Startup Options (ZCD_NV_STARTUP_OPTION) indicatethat the Config state items (zgItemTable) need to beset to defaults (ZCD_STARTOPT_DEFAULT_CONFIG_STATE).开启选项表明了各NV配置状态条目(zgItemTable表中的即为NV配置状态条目)需要被设置为默认值. setDefault的值取决于zgReadStartupOptions(),而这个函数记取的正是ZCD_NV_STARTUP_OPTION的值.****************************************// Reads the ZCD_NV_STARTUP_OPTION NV Item.uint8 zgReadStartupOptions( void ){// Default to Use Config State and Use Network Stateuint8 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//NV条目ZCD_NV_STARTUP_OPTION值读到startupOptionosal_nv_read( ZCD_NV_STARTUP_OPTION,0,sizeof( startupOption ),&startupOption);}return ( startupOption );}********************************************************************************* @fn zgItemInit()** Initialize a global item. If the item doesn't exist in NV memory,* write the system default (value passed in) into NV memory. But if* it exists, set the item to the value stored in NV memory.** Also, if setDefault is TRUE and the item exists, we will write* the default value to NV space.** @param id - item id* @param len - item len* @param buf - pointer to the item* @param setDefault - TRUE to set default, not read* TRUE则设置为默认值而不读取原先的值* @return ZSUCCESS if successful, NV_ITEM_UNINIT if item did not * exist in NV, NV_OPER_FAILED if failure.*/static uint8 zgItemInit( uint16 id, uint16 len, void *buf, uint8 setDefault ) {uint8 status;// If the item doesn't exist in NV memory, create and initialize// it with the value passed in.status = osal_nv_item_init( id, len, buf ); //NV条目读写前要进行条目的初始化if ( status == ZSUCCESS ){if ( setDefault ) //条目存在,setDefault=TRUE,设置为默认值{// Write the default value back to NVstatus = osal_nv_write( id, 0, len, buf );}else//条目存在,setDefault=FALSE,读取原先存储的值{// The item exists in NV memory, read it from NV memorystatus = osal_nv_read( id, 0, len, buf );}}return (status);}****************************************zgReadStartupOptions()中:Default to Use Config State and Use Network State说明采用默认的配置和网络状态,那设备初始启动时ZCD_NV_STARTUP_OPTION值应该是默认配置标志位和默认网络标志位都置1,两者相或0x03(见7),但还没能找到究竟哪里进行过初始化.回到zgInit():(1)setDefault = FALSE;(2)读取ZCD_NV_STARTUP_OPTION值如果ZCD_STARTOPT_D EFAULT_CONFIG_STATE标志位为1,设置setDefault = TRUE;(3)初始化NV配置状态条目表zgItemTa ble[ ]中各条目为默认值(4)清除ZCD_STARTOPT_DEFAULT_CONFIG_STATE标志位.至于清除ZCD_STARTOPT_DEFAULT_CONFIG_STATE标志位,我想如果用户不改变ZCD_NV_STAR TUP_OPTION条目的值,设备每次重启都会将NV条目表中各项初始化为默认值:比如SampleApp例子,每次设备重启配置状态都为默认值.而如果用户改变了ZCD_NV_STARTUP_OPTION的值,比如SimpleApp 中: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();每次按键后都会先把设备逻辑状态写入NV中(准备下次启动设备时以保存在这个NV条目里的逻辑类型来启动),然后把ZCD_NV_STARTUP_OPTION设为ZCD_STARTOPT_AUTO_START 0x04,则下面两个标志位都为0.ZCD_STARTOPT_DEFAULT_CONFIG_STATE 0x01 //默认配置状态:存储配置信息ZCD_STARTOPT_DEFAULT_NETWORK_STATE 0x02 //默认网络状态:存储网络信息这样系统重启进入zgInit()后:if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )// 0x01{setDefault = TRUE;}ZCD_STARTOPT_DEFAULT_CONFIG_STATE标志位不为1,setDefault保持FALSE,因而进入NV配置状态条目初始化zgItemInit()时,执行的是:else //条目存在,setDefault=FALSE,读取原先存储的值{// The item exists in NV memory, read it from NV memorystatus = osal_nv_read( id, 0, len, buf );}这样把上次存储在NV条目ZCD_NV_LOGICAL_TYPE中的设备逻辑类型值读出作为此次NV条目ZCD _NV_LOGICAL_TYPE的值.问题是,还未确定开启选项ZCD_NV_STARTUP_OPTION的值初始化的地方.纠结中,待解决……************************************************************************************************************************************************************************************************************************************************分析二:@@@ZCD_NV_STARTUP_OPTION最开始在osal_nv_item_init()中初始化,初始化为0***************************************** @fn zgInit** @brief** Initialize the Z-Stack Globals. If an item doesn't exist in* NV memory, write the system default into NV memory. But if* it exists, set the item to the value stored in NV memory.** NOTE: The Startup Options (ZCD_NV_STARTUP_OPTION) indicate* that the Config state items (zgItemTable) need to be* set to defaults (ZCD_STARTOPT_DEFAULT_CONFIG_STATE). The*** @param none** @return ZSUCCESS if successful, NV_ITEM_UNINIT if item did not* exist in NV, NV_OPER_FAILED if failure.*/uint8 zgInit( void ){uint8 i = 0;uint8 setDefault = FALSE;// Do we want to default the Config state valuesif ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE ) // 0x01{setDefault = TRUE;}#if 0 //正常情况下被禁止来节省NV空间// Enable this section if you need to track the number of resets// This section is normally disabled to minimize "wear" on NV memory…………#endif// Initialize the Extended PAN ID as my own extended address//扩展地址ZMacGetReq( ZMacExtAddr, zgExtendedPANID );#ifndef NONWK// Initialize the Pre-Configured Key to the default keyosal_memcpy( zgPreConfigKey, defaultKey, SEC_KEY_LEN ); // Do NOT Change!!!#endif// NONWK//----------------------------------初始化各NV配置状态条目值//初始化NV条目表zgItemTable[ ].如果setDefault=TRUE,则设置为系统默认//值;否则设置为原先存储在里面的值.while ( zgItemTable[i].id != 0x00 ){// Initialize the itemzgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault );// Move on to the next itemi++;}//----------------------------------// Clear the Config State default//如果NV条目ZCD_NV_STARTUP_OPTION的ZCD_STARTOPT_DEFAULT_CONFIG_STATE标致位为1if ( setDefault ){ //把ZCD_STARTOPT_DEFAULT_CONFIG_STATE标致位清0zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE ); }return ( ZSUCCESS );}****************************************首先来看下zgReadStartupOptions():****************************************// Reads the ZCD_NV_STARTUP_OPTION NV Item.uint8 zgReadStartupOptions( void ){// Default to Use Config State and Use Network Stateuint8 startupOption = 0;// This should have been done in ZMain.c, but just in case.//能返回ZSUCCESS,说明条目已经存在;当然,如果不存在,还是在osal_nv_item_init //中创建条目并设置为startupOption的值.if ( osal_nv_item_init( ZCD_NV_STARTUP_OPTION,sizeof(startupOption),&startupOption ) == ZSUCCESS ){// Read saved startup control//NV条目ZCD_NV_STARTUP_OPTION值读到startupOptionosal_nv_read( ZCD_NV_STARTUP_OPTION,0,sizeof( startupOption ),&startupOption);}return ( startupOption );}****************************************这里读取ZCD_NV_STARTUP_OPTION NV值,再来看下osal_nv_item_init(): ***************************************** @fn osal_nv_item_init** @brief If the NV item does not already exist, it is created and* initialized with the data passed to the function, if any.* This function must be called before calling osal_nv_read() or* osal_nv_write().如果条目不存在,则创建并初始化为传递过来的值.如果存在,直接返回ZSUCCESS.这个必须在read和write之前调用.** @param id - Valid NV item Id.* @param len - Item length.* @param *buf - Pointer to item initalization data. Set to NULL if none.* 条目初始化时的值.* @return NV_ITEM_UNINIT - Id did not exist and was created successfully. * ZSUCCESS - Id already existed, no action taken.* NV_OPER_FAILED - Failure to find or create Id.*/uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf )/* Global fail flag for fail due to low bus voltage has less impact on code* size than passing back a return value all the way from the lowest level.*/failF = FALSE;// ZCD_NV_EXTADDR is maintained without an osalNvHdr_t, so it is always alreadyinitialized.//条目已经存在,则直接返回ZSUCCESSif ( (id == ZCD_NV_EXTADDR) || (findItem( id ) != OSAL_NV_ITEM_NULL) ){return ZSUCCESS; //只有条目已经存在了,才会返回ZSUCCESS}//条目不存在,则通过initItem创建条目并初始化为buf传递过来的值else if ( initItem( TRUE, id, len, buf ) ){if ( failF ){(void)initNV(); // See comment at the declaration of failF.return NV_OPER_FAILED;}else{return NV_ITEM_UNINIT;}}else{return NV_OPER_FAILED;}}****************************************在zgReadStartupOptions()中调用了osal_nv_item_init( ZCD_NV_STARTUP_OPTION,sizeof(startupOpti on),&startupOption );其中startupOption = 0;一开始并不存在ZCD_NV_STARTUP_OPTION这个NV 条目,因而这里会创建NV条目ZCD_NV_STARTUP_OPTION并初始化为startupOption传递过来的值0.成功则返回NV_ITEM_UNINIT,因而不会调用zgReadStartupOptions()的osal_nv_read( ZCD_NV_STAR TUP_OPTION,0,sizeof( startupOption ),&startupOption),最后返回startupOption=0.回到zgInit(),setDefa ult = FALSE保持不变,然后进入NV配置状态条目初始化zgItemInit( zgItemTable[i].id, zgItemTable[i]. len, zgItemTable[i].buf, setDefault ),注意此时传递进去的值zgItemTable[i].buf已经定义为系统默认值(可以查看ZGlobals.c的NWK GLOBAL VARIABLES栏).看下zgItemInit():***************************************** @fn zgItemInit()** @brief* Initialize a global item. If the item doesn't exist in NV memory,* write the system default (value passed in) into NV memory. But if* it exists, set the item to the value stored in NV memory.* 条目不存在,创建并设置为传递过来的值;存在则设置为原存储的值.* Also, if setDefault is TRUE and the item exists, we will write* the default value to NV space.** @param id - item id* @param len - item len* @param buf - pointer to the item* @param setDefault - TRUE to set default, not read** @return ZSUCCESS if successful, NV_ITEM_UNINIT if item did not* exist in NV, NV_OPER_FAILED if failure.*/static uint8 zgItemInit( uint16 id, uint16 len, void *buf, uint8 setDefault ){uint8 status;// If the item doesn't exist in NV memory, create and initialize// it with the value passed in.status = osal_nv_item_init( id, len, buf );//NV条目读写前都要进行条目的初始化//这里是要status == ZSUCCESS才会执行里面的内容,说明//此NV条目是已经存在的,这样才会返回ZSUCCESSif ( status == ZSUCCESS ){if ( setDefault ) //条目存在,设置为默认值{// Write the default value back to NVstatus = osal_nv_write( id, 0, len, buf );}else //条目存在,读取原先存储的值{// The item exists in NV memory, read it from NV memorystatus = osal_nv_read( id, 0, len, buf );}}return (status);}****************************************可以看到同样调用了osal_nv_item_init( id, len, buf ),如果条目不存在则创建并设置为buf传递过来的值,如果存在则直接返回ZSUCCESS.一开始各NV配置状态条目不存在,因而这里创建各条目并设置为buf传递过来的值(系统定义的默认值).回到zgInit(),各NV配置状态条目初始化完成后,返回ZSUCCESS.因为此时setDefault保持FALSE不变,因而不会执行zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_ST ARTOPT_DEFAULT_CONFIG_STATE );以上为NV条目的初始化流程.初始化时ZCD_NV_STARTUP_OPTION=0,即把各NV条目初始化为系统默认的值.想到zgReadStartupOptions()开头那句话:// Default to Use Config State and Use Network Stateuint8 startupOption = 0;startupOption即为ZCD_NV_STARTUP_OPTION的初始化值.(###)如果,这样初始化完成后,又在应用程序中改变ZCD_NV_STARTUP_OPTION的值,改为ZCD_START OPT_DEFAULT_CONFIG_STATE.然后zb_SystemReset()重启系统.进入zgInit(),首先设置setDefault = FALSE,然后同样进入判断:if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_CONFIG_STATE )// 0x01{setDefault = TRUE;}调用:zgReadStartupOptions()->osal_nv_item_init(),因为此时NV条目ZCD_NV_STARTUP_OPTION已经存在,所以osal_nv_item_init()不会再创建条目并设置为传递过来的值startupOption = 0,而是直接返回ZS UCCESS,因而这时在zgReadStartupOptions()里会调用osal_nv_read( ZCD_NV_STARTUP_OPTION,0,s izeof( startupOption ),&startupOption)读取先前已经存储在条目ZCD_NV_STARTUP_OPTION里的值: ZCD_STARTOPT_DEFAULT_CONFIG_STATE!所以这里设置setDefault = TRUE.然后进入各NV配置状态条目初始化:zgItemInit( zgItemTable[i].id, zgItemTable[i].len, zgItemTable[i].buf, setDefault );进入zgItemInit(),同样先调用了osal_nv_item_init( id, len, buf ),因为各NV配置状态条目已经存在,所以不再创建而是直接返回ZSUCCESS,所以这次会调用:if ( status == ZSUCCESS ){if ( setDefault ) //条目存在,设置为默认值{// Write the default value back to NVstatus = osal_nv_write( id, 0, len, buf );}else//条目存在,设置为原先存储的值{// The item exists in NV memory, read it from NV memorystatus = osal_nv_read( id, 0, len, buf );}}因为setDefault = TRUE,所以重新设置各NV配置状态条目为系统默认值.然后回到zgInit(),最终调用if ( setDefault ){ //把ZCD_STARTOPT_DEFAULT_CONFIG_STATE这位清0zgWriteStartupOptions( ZG_STARTUP_CLEAR, ZCD_STARTOPT_DEFAULT_CONFIG_STATE ); }这里把ZCD_NV_STARTUP_OPTION条目值重新清0(我上面只假设ZCD_NV_STARTUP_OPTION的值为ZCD_STARTOPT_DEFAULT_CONFIG_STATE 0x01).(###)当然,如果像SampleApp例子没有在应用程序中修改过ZCD_NV_STARTUP_OPTION,最开始启动设备时会创建条目并初始化为0(startupOption = 0),然后创建各NV配置状态条目并初始化为系统默认值.以后的每次设备启动,ZCD_NV_STARTUP_OPTION值为0,setDefault = FALSE,各NV配置状态条目初始化执行的是:else//条目存在,设置为原先存储的值{// The item exists in NV memory, read it from NV memorystatus = osal_nv_read( id, 0, len, buf );}读取此前的配置状态.(###)再比如SimpleApp例子,应用程序通过按键改变NV条目ZCD_NV_STARTUP_OPTION以及NV配置状态条目ZCD_NV_LOGICAL_TYPE的值,通过zb_WriteConfiguration()写入NV中,然后zb_SystemRe set()重启系统.进入zgInit(),通过zgReadStartupOptions()读出的ZCD_NV_STARTUP_OPTION值不为ZC D_STARTOPT_DEFAULT_CONFIG_STATE,因而setDefault = FALSE.再进入zgItemInit(),因为条目存在且setDefault = FALSE,所以执行// The item exists in NV memory, read it from NV memorystatus = osal_nv_read( id, 0, len, buf );把条目的值设置为先前存储的值.即在SampleApp例子中,把上次存储在NV条目ZCD_NV_LOGICAL_TY PE中的设备逻辑类型值读出作为此次NV条目ZCD_NV_LOGICAL_TYPE的值.(1)初始ZCD_NV_STARTUP_OPTION=0.如果设备是首次启动,则调用status = osal_nv_item_init( id, len, buf )创建各NV配置状态条目并初始化为系统默认值;如果设备不是首次启动,则调用osal_nv_read( id, 0, len, buf )读取各NV配置状态条目先前存储的值作为本次的值.(2)设置ZCD_NV_STARTUP_OPTION=ZCD_STARTOPT_DEFAULT_CONFIG_STATE.NV条目ZCD_ NV_STARTUP_OPTION已经存在,调用osal_nv_write( id, 0, len, buf )设置各NV配置状态条目为系统默认值.最后把这位清0.(3)设置ZCD_NV_STARTUP_OPTION=ZCD_STARTOPT_AUTO_START.NV条目ZCD_NV_STARTUP _OPTION已经存在,调用osal_nv_read( id, 0, len, buf )读取各NV配置状态条目先前存储的值作为本次的值.********************************************************************************************************************************************************************************************************************************************************************************************************************************。
XBee和XBee - PRO OEM RF模块的设计,以ZigBee协议内运作,支持低成本的独特需求,低功耗无线传感器网络工程。
模块只需要最小的功率,就能提供远程设备之间的数据传输的可靠性。
这两个模块内运作的ISM 2.4 GHz频段,且引脚对引脚相互兼容。
1.1 主要特点先进的网络和安全重试和确认。
DSSS(直接序列扩频)每一个序列频道,可使用超过65000个唯一的网络地址点至点,点对点,点对多点和点对点的对等拓扑支撑自行安排,自我修复和故障容错网络易于使用没有配置必要的外箱射频通信AT和API命令模式配置模块参数小尺寸广泛的命令集免费的X - CTU软件(测试和配置软件)免费及无限技术支持1.1.1. 全球认证FCC认证(美国)参见附录A [p34要求]。
系统包含的XBee / XBee-PRO射频模块继承MaxStream的认证。
ISM(工业,科学和医疗)2.4吉赫频带的ISO 9001:2000认证机构认证下制造的注册标准的XBee / XBee-PRO射频模块列表被优化用于在美国,加拿大,澳大利亚,以色列和欧洲。
1.2.描述表1-01,XBee/XBee‐PRO OEM RF 模块(简述)当在欧洲运用时:XBee - PRO RF模块必须被配置为运行在一个最大发射功率为10 dBm的输出水平。
电源输出级别设置使用PL 命令。
PL参数必须等于“0”(10 dBm)。
此外,欧洲法规规定,EIRP最高功率为12.86 dBm的(19毫瓦),对于XBee – PRO的12.11 dBm和XBee时高增益天线天线选项:指定的范围内使用时是典型的集成块(1.5 dBi的)和偶极子(2.1 dBi的)天线。
该芯片天线选项提供要素优势,它的形式,但它通常会产生更短的选择范围比带和偶极子天线发射时,在户外。
1.3.机械尺寸图1 - 01 XBee / XBee - PRO OEM RF模块的机械尺寸(天线选项未显示)The XBee and XBee‐PRO RF Modules are pin‐for‐pin compatible.XBee和XBee - 专业射频模块的引脚- 为- 引脚兼容。
【转自小峰博客】协调器的启动【自动模式】使用的协议栈版本信息: ZigBee2019\ZStack-1.4.3-1.2.1Zigbee网络设备启动流程—协调器(自启动模式)—以SampleApp的协调器为例.1、协调器预编译信息通过project->options->c/c++compiler->extraOptions可以看到协调器所带的配置文件为:-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wCoord.cfg-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wConfig.cfg即编译了ZDO_COORDINATOR和RTR_NWK.通过project->options->c/c++compiler->Preprocessor->Defined symbols可以看到协调器预编译包含了:CC2430EB; ZTOOL_P1; MT_TASK; LCD_SUPPORTED=DEBUG; MANAGED_SCAN没有编译HOLD_AUTO_START和SOFT_START.2、具体流程main()->osal_init_system()->osalInitTasks()->ZDApp_Init()进入ZDApp_Init()函数:**************************************void ZDApp_Init( byte task_id ){uint8 capabilities;// Save the task IDZDAppTaskID = task_id;// Initialize the ZDO global device short address storageZDAppNwkAddr.addrMode = Addr16Bit;ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR; //0xFFFE(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.// 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(); //通过判断预编译来开启一些函数功能// 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 filteringNLME_GetRequest(nwkCapabilityInfo, 0, &capabilities);NLME_SetBroadcastFilter( capabilities );// Start the device?if ( devState != DEV_HOLD ){ZDOInitDevice( 0 );}/*如果devState=DEV_HOLD,则不会调用ZDOInitDevice()来初始化网络即不组网也不进网.LED4闪烁等待应用程序来开启设备并初始化网络*/else{// Blink LED to indicate HOLD_STARTHalLedBlink ( HAL_LED_4, 0, 50, 500 );}ZDApp_RegisterCBs();}**************************************协调器没有编译HOLD_AUTO_START,也没有手工设置SW_1,初始化devState = DEV_INIT(参见基本问题说明3).因此直接在ZDApp_Init()中进入ZDOInitDevice( 0 )开启设备.**************************************uint8 ZDOInitDevice( uint16 startDelay ){//初始化设备网络状态为ZDO_INITDEV_NEW_NETWORK_STATE:新的网络状态.//可能意味着ZCD_NV_STARTUP_OPTION不能恢复,或没有任何网络状态恢复uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;uint16 extendedDelay = 0;devState = DEV_INIT; // Remove the Hold state// Initialize leave control logic//函数读取NV项目ZCD_NV_LEAVE_CTRL的值,ZDApp_LeaveCtrl指向这个值ZDApp_LeaveCtrlInit();// Check leave control reset settingsZDApp_LeaveCtrlStartup( &devState, &startDelay );// Leave may make the hold state come back//以上两个函数设置了对设备离开时的控制,如果有延时则延时,没有则//把设备状态设为DEV_HOLDif ( devState == DEV_HOLD )//ZDO_INITDEV_LEAVE_NOT_STARTED:该设备没有在网络中,下次调用才启用.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 )//SW_BYPASS_NV按键处于按下状态时,则避开网络层的NV存储networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //设备网络状态为新的网络状态else{// Determine if NV should be restored//函数返回的设备网络状态要么是新的网络状态;要么是恢复的网络状态;以此//来确定要不要读取NV里相应条目来恢复网络先前状态networkStateNV = ZDApp_ReadNetworkRestoreState();}//如果设备的网络状态为恢复的网络状态if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE ){//恢复设备先前的网络状态参数并且//设置devStartMode = MODE_RESUME!!!!networkStateNV = ZDApp_RestoreNetworkState();}else //如果设备的网络状态为新的网络状态,在下面进行处理{// Wipe out(清除) the network state in NVNLME_InitNV();NLME_SetDefaultNV(); //设置默认NV条目}#endif//如果设备的网络状态为新的网络状态if ( 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 device securityZDApp_SecInit( networkStateNV );// Trigger the network startZDApp_NetworkInit( extendedDelay );return ( networkStateNV );}**************************************分两种情况:(1)如果协调器预编译了NV_RESTORE,且函数ZDApp_ReadNetworkRestoreState()返回值为ZDO_INITDEV_RESTORED_NETWORK_STATE,则进入ZDApp_RestoreNetworkState()里设置ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR和devStartMode = MODE_RESUME.****************uint8 ZDApp_RestoreNetworkState( void ){…………// Are we a coordinator//设备的网络状态为恢复的网络状态.则进入这个函数进行恢复//先判断如果短地址为0则设置设备逻辑类型为协调器且devStartMode = MODE_RESUME //否则设置devStartMode = MODE_RESUMEZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();if ( ZDAppNwkAddr.addr.shortAddr == 0 ) //如果短地址是0,即协调器{ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR; //!!!!!}devStartMode = MODE_RESUME; //MODE_RESUME!!!!!!!!…………}****************(2)如果协调器没有预编译NV_RESTORE,networkStateNV==ZDO_INITDEV_NEW_NETWORK_STATE,但由于协调器编译了ZDO_COORDINATOR而没有编译SOFT_START,因此ZDAppDetermineDeviceType()不起作用.因此ZDO_Config_Node_Descriptor.LogicalType和devStartMode这两个关键参数保持初始化时的值:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR(见基本问题说明6)devStartMode = MODE_HARD(见基本问题说明4)对于协调器,这两种情况最终都是确定两个关键设备网络状态参数的值.对本例的SampleApp的协调器,没有编译NV_RESTORE,因此属于情况(2).然后调用ZDApp_NetworkInit()启动网络:****************void ZDApp_NetworkInit( uint16 delay ){if ( delay ){// Wait awhile before starting the deviceosal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );}else{osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );}}****************通过触发ZDAppTaskID的ZDO_NETWORK_INIT事件.来看下对ZDO_NETWORK_INIT 事件的处理:****************UINT16 ZDApp_event_loop( byte task_id, UINT16 events ){…………if ( events & ZDO_NETWORK_INIT ){// Initialize apps and start the networkdevState = DEV_INIT;ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode, DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_INIT);}…………}****************tuzhuke2019-11-08 20:18:11可以看到调用了ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,DEF AULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );这里设备网络状态参数:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATORdevStartMode = MODE_HARD且协调器编译了ZDO_COORDINATOR****************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 ) //MODE_HARD{devState = DEV_COORD_STARTING; //Started as Zigbee Coordinator//建网ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,zgDefaultStartingScanDuration, beaconOrder,superframeOrder, false );}else if ( startMode == MODE_RESUME ) //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" );ClearScreen();Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);#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; //Discovering PAN's to join#if defined( MANAGED_SCAN )ZDOManagedScan_Next();ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC ); #elseret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration ); #endif}else if ( startMode == MODE_RESUME ) //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" );Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);#endif}}//#endif //!ZDO COORDINATOR || SOFT_STARTif ( ret != ZSuccess )osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );}****************通过参数可知协调器调用NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,zgDefaultStartingScanDuration, beaconOrder,superframeOrder, false )进行网络的组建.而对NLME_NetworkFormationRequest()的调用会产生一个回调函数ZDO_NetworkFormationConfirmCB()(见主要函数说明3),来看下:****************void ZDO_NetworkFormationConfirmCB( ZStatus_t Status ){#if defined(ZDO_COORDINATOR)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 );#endif //ZDO_COORDINATOR}****************如果Status返回ZSUCCESS,建立网络成功,通过一些灯亮来来指示;不成功则通过闪烁灯来指示.最后触发任务ZDAppTaskID的ZDO_NETWORK_START事件,看下对ZDO_NETWORK_START的处理:****************#if defined (RTR_NWK)if ( events & ZDO_NETWORK_START ){ZDApp_NetworkStartEvt();// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_START);}****************调用了ZDApp_NetworkStartEvt()****************void ZDApp_NetworkStartEvt( void ){if ( nwkStatus == ZSuccess )//网络建立成功{// Successfully started a ZigBee networkif ( devState == DEV_COORD_STARTING ){devState = DEV_ZB_COORD;}osal_pwrmgr_device( PWRMGR_ALWAYS_ON );osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );}else //网络建立不成功,则增加能量阀值重新建网.{// Try again with a higher energy threshold !!if ( ( NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT ) < 0xff ){NLME_SetEnergyThreshold( (uint8)(NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT) );osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); //重新初始化建立网络}else{// Failed to start network. Enter a dormant state (until user intervenes)devState = DEV_INIT;osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );}}}****************如果协调器建立网络成功,则触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT事件.看下对ZDO_STATE_CHANGE_EVT的处理:****************if ( events & ZDO_STATE_CHANGE_EVT ){ZDO_UpdateNwkStatus( devState );// Return unprocessed eventsreturn (events ^ ZDO_STATE_CHANGE_EVT);}****************调用了ZDO_UpdateNwkStatus( devState ),网络状态改变,这个函数会更新和发送信息通知每个注册登记过的应用终端.****************void ZDO_UpdateNwkStatus( devStates_t state ){// Endpoint/Interface descriptor list.epList_t *epDesc = epList;byte bufLen = sizeof(osal_event_hdr_t);osal_event_hdr_t *msgPtr;ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.while ( epDesc ){if ( epDesc->epDesc->endPoint != ZDO_EP ){msgPtr = (osal_event_hdr_t *)osal_msg_allocate( bufLen );if ( msgPtr ){msgPtr->event = ZDO_STATE_CHANGE; // Command IDmsgPtr->status = (byte)state;osal_msg_send( *(epDesc->epDesc->task_id), (byte *)msgPtr ); //发往应用任务}}epDesc = epDesc->nextDesc;}}****************对SampleApp的协调器来说,这里触发应用任务SampleApp_TaskID的ZDO_STATE_CHANGE事件,看下对ZDO_STATE_CHANGE的处理:****************case ZDO_STATE_CHANGE:SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //获取设备当前状态if ( (SampleApp_NwkState == DEV_ZB_COORD)|| (SampleApp_NwkState == DEV_ROUTER)|| (SampleApp_NwkState == DEV_END_DEVICE) ){// Start sending the periodic message in a regular interval.osal_start_timerEx( SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );}else{// Device is no longer in the network}break;****************可以看到当协调器建立网络成功,通过回调函数触发应用任务的ZDO_STATE_CHANGE事件,最终开启定时器发送周期信息.3、协调器(自启动模式)—以SampleApp的协调器为例,并假设初始化成功,网络建立成功.程序大致流程:main()->osal_init_system()->osalInitTasks()->ZDApp_Init()->ZDOInitDevice()->ZDApp_NetworkInit->触发ZDAppTaskID的ZDO_NETWORK_INIT->ZDO_StartDevice()->NLME_NetworkFormationRequest()->网络建立成功ZDO_NetworkFormationConfirmCB->触发ZDAppTaskID的ZDO_NETWORK_START->ZDApp_NetworkStartEvt()->触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT->ZDO_UpdateNwkStatus()->触发SampleApp_TaskID的ZDO_STATE_CHANGE->开户周期信息发送的定时器.4、注:(1)自启动模式下SampleApp的终端和路由器总体流程基本一致.(2)以SampleApp为例,ZDO_StartDevice()函数的两个重要参数比较:终端:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICEdevStartMode = MODE_JOIN路由器:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER devStartMode = MODE_JOIN协调器:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR devStartMode = MODE_HARD******************************************************************************说明:1、本文为个人学习笔记,纯属个人理解,错误不可避免,仅供参考.随时更新2、细节基本不管,遇到问题再作分析,程序注释为个人原始注释内容,记录有些仓促.3、欢迎交流,转载请注明出处,谢谢!。
基于zigbee的无线网络协调器节点的设计ZigBee是一种由英特尔开发的低功耗无线网络技术,由英特尔支持的短距离、低速率的无线网络技术。
它使用节点网络结构,可以在低成本的情况下构建完整的低级别网络覆盖,无线局域网(WLAN)可以实现整合和控制多种网络节点。
一个zigBee网络中有一个或多个节点叫做协调器,它们负责维护和管理整个网络的共同状态和紧密维护节点的唯一性,以及确保节点可以安全地无线传输数据。
一. ZigBee协调器节点协调器节点是ZigBee网络中最重要的节点,其主要职责是管理网络中的所有节点,包括初始化、组织、维护和保护网络。
在协调器节点中,我们可以定义一些参数如网络ID,设置网络安全性等,这些参数必须经过协调器审批,才能让其他节点进入到ZigBee网络中。
此外,协调器节点也具有网络发现功能,可以支持ZigBee网络的数据传输,有效地改善ZigBee网络的安全性和稳定性。
二.协调器节点的设计1.络通信模块网络通信模块是协调器节点的核心组件,它的主要功能就是实现ZigBee网络中节点之间的网络通信和数据传输。
它可以根据需要采用多种通信技术,如UART、SPI、I2C和RS485等。
此外,它还具备一定的错误纠正功能,可以有效减少网络传输数据的错误率。
2.存模块内存模块主要负责存储协调器节点的网络参数和网络上传输的数据,它可以采用各种内存技术,如SRAM、SDRAM、Flash等。
它可以实现网络数据的长期存储,也可以帮助和支持协调器节点的网络参数的更新。
3.制器模块控制器模块是协调器节点的核心组件,它主要用于管理和控制其他模块的运行,实现网络参数设置、网络维护和网络加密等功能。
此外,它还可以用于完成协调器节点的配置管理。
4.源模块电源模块的目的是为协调器模块提供电源,它可以采用多种电源技术,如直流电源供电、可充电电池、太阳能电池等。
此外,它还可以用来检测电源的状态,以保证协调器模块的正常运行。
设备启动准备一、设备类型选择:通过Workspace下拉框选择设备的类型:图1:协调器图2:路由器图3:终端节点协议栈设备类型:#define ZG_DEVICETYPE_COORDINATOR 0x00#define ZG_DEVICETYPE_ROUTER 0x01#define ZG_DEVICETYPE_ENDDEVICE 0x02#define ZG_DEVICETYPE_SOFT 0x03ZG_DEVICETYPE_SOFT说明:可选设备类型。
可以成为路由器、也可以成为协调器,由后面的程序决定。
初始化:对于DEVICE_LOGICAL_TYPE的值各逻辑类型设备初始化如下:// Device Logical Type//zgDeviceLogicalType = DEVICE_LOGICAL_TYPE在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说明:如果编译了SOFT_START,则初始化设备逻辑类型(DEVICE_LOGICAL_TYPE)为可选择类型(ZG_DEVICETYPE_SOFT)即设备可以作为协调器启动创建一个网络或者作为路由器加入一个已经存在的网络。
【转自小峰博客】协调器的启动【自动模式】使用的协议栈版本信息: ZigBee2006\ZStack-1.4.3-1.2.1Zigbee网络设备启动流程—协调器(自启动模式)—以SampleApp的协调器为例.1、协调器预编译信息通过project->options->c/c++compiler->extraOptions可以看到协调器所带的配置文件为:-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wCoord.cfg-f $PROJ_DIR$\..\..\..\Tools\CC2430DB\f8wConfig.cfg即编译了ZDO_COORDINATOR和RTR_NWK.通过project->options->c/c++compiler->Preprocessor->Defined symbols可以看到协调器预编译包含了:CC2430EB; ZTOOL_P1; MT_TASK; LCD_SUPPORTED=DEBUG; MANAGED_SCAN没有编译HOLD_AUTO_START和SOFT_START.2、具体流程main()->osal_init_system()->osalInitTasks()->ZDApp_Init()进入ZDApp_Init()函数:**************************************void ZDApp_Init( byte task_id ){uint8 capabilities;// Save the task IDZDAppTaskID = task_id;// Initialize the ZDO global device short address storageZDAppNwkAddr.addrMode = Addr16Bit;ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR; //0xFFFE(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.// 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(); //通过判断预编译来开启一些函数功能// 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 filteringNLME_GetRequest(nwkCapabilityInfo, 0, &capabilities);NLME_SetBroadcastFilter( capabilities );// Start the device?if ( devState != DEV_HOLD ){ZDOInitDevice( 0 );}/*如果devState=DEV_HOLD,则不会调用ZDOInitDevice()来初始化网络即不组网也不进网.LED4闪烁等待应用程序来开启设备并初始化网络*/else{// Blink LED to indicate HOLD_STARTHalLedBlink ( HAL_LED_4, 0, 50, 500 );}ZDApp_RegisterCBs();}**************************************协调器没有编译HOLD_AUTO_START,也没有手工设置SW_1,初始化devState = DEV_INIT(参见基本问题说明3).因此直接在ZDApp_Init()中进入ZDOInitDevice( 0 )开启设备.**************************************uint8 ZDOInitDevice( uint16 startDelay ){//初始化设备网络状态为ZDO_INITDEV_NEW_NETWORK_STATE:新的网络状态.//可能意味着ZCD_NV_STARTUP_OPTION不能恢复,或没有任何网络状态恢复uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;uint16 extendedDelay = 0;devState = DEV_INIT; // Remove the Hold state// Initialize leave control logic//函数读取NV项目ZCD_NV_LEAVE_CTRL的值,ZDApp_LeaveCtrl指向这个值ZDApp_LeaveCtrlInit();// Check leave control reset settingsZDApp_LeaveCtrlStartup( &devState, &startDelay );// Leave may make the hold state come back//以上两个函数设置了对设备离开时的控制,如果有延时则延时,没有则//把设备状态设为DEV_HOLDif ( devState == DEV_HOLD )//ZDO_INITDEV_LEAVE_NOT_STARTED:该设备没有在网络中,下次调用才启用.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 )//SW_BYPASS_NV按键处于按下状态时,则避开网络层的NV存储networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //设备网络状态为新的网络状态else{// Determine if NV should be restored//函数返回的设备网络状态要么是新的网络状态;要么是恢复的网络状态;以此//来确定要不要读取NV里相应条目来恢复网络先前状态networkStateNV = ZDApp_ReadNetworkRestoreState();}//如果设备的网络状态为恢复的网络状态if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE ){//恢复设备先前的网络状态参数并且//设置devStartMode = MODE_RESUME!!!!networkStateNV = ZDApp_RestoreNetworkState();}else //如果设备的网络状态为新的网络状态,在下面进行处理{// Wipe out(清除) the network state in NVNLME_InitNV();NLME_SetDefaultNV(); //设置默认NV条目}#endif//如果设备的网络状态为新的网络状态if ( 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 device securityZDApp_SecInit( networkStateNV );// Trigger the network startZDApp_NetworkInit( extendedDelay );return ( networkStateNV );}**************************************分两种情况:(1)如果协调器预编译了NV_RESTORE,且函数ZDApp_ReadNetworkRestoreState()返回值为ZDO_INITDEV_RESTORED_NETWORK_STATE,则进入ZDApp_RestoreNetworkState()里设置ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR和devStartMode = MODE_RESUME.****************uint8 ZDApp_RestoreNetworkState( void ){…………// Are we a coordinator//设备的网络状态为恢复的网络状态.则进入这个函数进行恢复//先判断如果短地址为0则设置设备逻辑类型为协调器且devStartMode = MODE_RESUME //否则设置devStartMode = MODE_RESUMEZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();if ( ZDAppNwkAddr.addr.shortAddr == 0 ) //如果短地址是0,即协调器{ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR; //!!!!!}devStartMode = MODE_RESUME; //MODE_RESUME!!!!!!!!…………}****************(2)如果协调器没有预编译NV_RESTORE,networkStateNV==ZDO_INITDEV_NEW_NETWORK_STATE,但由于协调器编译了ZDO_COORDINATOR而没有编译SOFT_START,因此ZDAppDetermineDeviceType()不起作用.因此ZDO_Config_Node_Descriptor.LogicalType和devStartMode这两个关键参数保持初始化时的值:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR(见基本问题说明6)devStartMode = MODE_HARD(见基本问题说明4)对于协调器,这两种情况最终都是确定两个关键设备网络状态参数的值.对本例的SampleApp的协调器,没有编译NV_RESTORE,因此属于情况(2).然后调用ZDApp_NetworkInit()启动网络:****************void ZDApp_NetworkInit( uint16 delay ){if ( delay ){// Wait awhile before starting the deviceosal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );}else{osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );}}****************通过触发ZDAppTaskID的ZDO_NETWORK_INIT事件.来看下对ZDO_NETWORK_INIT 事件的处理:****************UINT16 ZDApp_event_loop( byte task_id, UINT16 events ){…………if ( events & ZDO_NETWORK_INIT ){// Initialize apps and start the networkdevState = DEV_INIT;ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode, DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_INIT);}…………}****************tuzhuke2010-11-08 20:18:11可以看到调用了ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,DEF AULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );这里设备网络状态参数:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATORdevStartMode = MODE_HARD且协调器编译了ZDO_COORDINATOR****************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 ) //MODE_HARD{devState = DEV_COORD_STARTING; //Started as Zigbee Coordinator//建网ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,zgDefaultStartingScanDuration, beaconOrder,superframeOrder, false );}else if ( startMode == MODE_RESUME ) //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" );ClearScreen();Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);#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; //Discovering PAN's to join#if defined( MANAGED_SCAN )ZDOManagedScan_Next();ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC ); #elseret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration ); #endif}else if ( startMode == MODE_RESUME ) //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" );Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);#endif}}//#endif //!ZDO COORDINATOR || SOFT_STARTif ( ret != ZSuccess )osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );}****************通过参数可知协调器调用NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList,zgDefaultStartingScanDuration, beaconOrder,superframeOrder, false )进行网络的组建.而对NLME_NetworkFormationRequest()的调用会产生一个回调函数ZDO_NetworkFormationConfirmCB()(见主要函数说明3),来看下:****************void ZDO_NetworkFormationConfirmCB( ZStatus_t Status ){#if defined(ZDO_COORDINATOR)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 );#endif //ZDO_COORDINATOR}****************如果Status返回ZSUCCESS,建立网络成功,通过一些灯亮来来指示;不成功则通过闪烁灯来指示.最后触发任务ZDAppTaskID的ZDO_NETWORK_START事件,看下对ZDO_NETWORK_START的处理:****************#if defined (RTR_NWK)if ( events & ZDO_NETWORK_START ){ZDApp_NetworkStartEvt();// Return unprocessed eventsreturn (events ^ ZDO_NETWORK_START);}****************调用了ZDApp_NetworkStartEvt()****************void ZDApp_NetworkStartEvt( void ){if ( nwkStatus == ZSuccess )//网络建立成功{// Successfully started a ZigBee networkif ( devState == DEV_COORD_STARTING ){devState = DEV_ZB_COORD;}osal_pwrmgr_device( PWRMGR_ALWAYS_ON );osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );}else //网络建立不成功,则增加能量阀值重新建网.{// Try again with a higher energy threshold !!if ( ( NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT ) < 0xff ){NLME_SetEnergyThreshold( (uint8)(NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT) );osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); //重新初始化建立网络}else{// Failed to start network. Enter a dormant state (until user intervenes)devState = DEV_INIT;osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );}}}****************如果协调器建立网络成功,则触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT事件.看下对ZDO_STATE_CHANGE_EVT的处理:****************if ( events & ZDO_STATE_CHANGE_EVT ){ZDO_UpdateNwkStatus( devState );// Return unprocessed eventsreturn (events ^ ZDO_STATE_CHANGE_EVT);}****************调用了ZDO_UpdateNwkStatus( devState ),网络状态改变,这个函数会更新和发送信息通知每个注册登记过的应用终端.****************void ZDO_UpdateNwkStatus( devStates_t state ){// Endpoint/Interface descriptor list.epList_t *epDesc = epList;byte bufLen = sizeof(osal_event_hdr_t);osal_event_hdr_t *msgPtr;ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.while ( epDesc ){if ( epDesc->epDesc->endPoint != ZDO_EP ){msgPtr = (osal_event_hdr_t *)osal_msg_allocate( bufLen );if ( msgPtr ){msgPtr->event = ZDO_STATE_CHANGE; // Command IDmsgPtr->status = (byte)state;osal_msg_send( *(epDesc->epDesc->task_id), (byte *)msgPtr ); //发往应用任务}}epDesc = epDesc->nextDesc;}}****************对SampleApp的协调器来说,这里触发应用任务SampleApp_TaskID的ZDO_STATE_CHANGE事件,看下对ZDO_STATE_CHANGE的处理:****************case ZDO_STATE_CHANGE:SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //获取设备当前状态if ( (SampleApp_NwkState == DEV_ZB_COORD)|| (SampleApp_NwkState == DEV_ROUTER)|| (SampleApp_NwkState == DEV_END_DEVICE) ){// Start sending the periodic message in a regular interval.osal_start_timerEx( SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );}else{// Device is no longer in the network}break;****************可以看到当协调器建立网络成功,通过回调函数触发应用任务的ZDO_STATE_CHANGE事件,最终开启定时器发送周期信息.3、协调器(自启动模式)—以SampleApp的协调器为例,并假设初始化成功,网络建立成功.程序大致流程:main()->osal_init_system()->osalInitTasks()->ZDApp_Init()->ZDOInitDevice()->ZDApp_NetworkInit->触发ZDAppTaskID的ZDO_NETWORK_INIT->ZDO_StartDevice()->NLME_NetworkFormationRequest()->网络建立成功ZDO_NetworkFormationConfirmCB->触发ZDAppTaskID的ZDO_NETWORK_START->ZDApp_NetworkStartEvt()->触发ZDAppTaskID的ZDO_STATE_CHANGE_EVT->ZDO_UpdateNwkStatus()->触发SampleApp_TaskID的ZDO_STATE_CHANGE->开户周期信息发送的定时器.4、注:(1)自启动模式下SampleApp的终端和路由器总体流程基本一致.(2)以SampleApp为例,ZDO_StartDevice()函数的两个重要参数比较:终端:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICEdevStartMode = MODE_JOIN路由器:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER devStartMode = MODE_JOIN协调器:ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR devStartMode = MODE_HARD******************************************************************************说明:1、本文为个人学习笔记,纯属个人理解,错误不可避免,仅供参考.随时更新2、细节基本不管,遇到问题再作分析,程序注释为个人原始注释内容,记录有些仓促.3、欢迎交流,转载请注明出处,谢谢!。