APP下载

基于Z-Stack协议栈的ZigBee应用系统设计

2018-03-29韩新风高智中

长春师范大学学报 2018年8期
关键词:源文件源代码路由器

韩新风,高智中

(1.安徽科技学院电气与电子工程学院,安徽凤阳 233100;2.安徽科技学院信息与网络学院,安徽凤阳 233100)

Z-Stack协议栈软件是TI公司开发的Zigbee协议栈,适用于其公司的CC2430、CC2530和CC2538等射频芯片。Z-Stack协议栈是在IEEE 802.15.4标准基础上建立的,具有物理层、介质访问控制层、网络层、安全层、应用程序接口、应用层,其中物理层、介质访问控制层是根据IEEE 802.15.4标准定义的,而网络层、安全层和应用程序接口是由ZigBee联盟制定的。Z-Stack协议栈采用的是一个名为操作系统抽象层(Operating System Abstraction Layer,OSAL)的协议栈调度程序。对用户来说,除了能够看到这个调度程序外,其他任何协议栈操作的具体实现细节都封装在库代码中,用户在开发具体应用时,只能通过调用API(Application Programming Interface)接口,而无权知道ZigBee协议栈实现的具体细节[1],因此称Z-Stack协议栈为半开源的协议栈。用户主要利用应用层来完成具体的应用系统的设计。Z-Stack协议栈定义了三种ZigBee设备类型:协调器、路由器和终端设备[2]。本文以TI公司的CC2530用于设计无线温湿度测量系统来说明应用系统设计的一般步骤,其中终端设备负责测量温度和湿度,路由器负责转发数据,协调器负责接收数据、进行数据处理显示或者将数据上传至上位机。

1 项目的创建

基于Z-Stack协议栈的新项目的创建与一般软件不同,因为它是一个半开源的协议栈,有很多代码(如介质访问控制层、网络层的部分代码)对用户来讲是非开源的,即对用户不可见,但这些代码却是必备的,因此新项目的创建一般会采用在原有项目基础上进行修改的方法来完成。用户计算机上需要安装IAR Embeded Workbench IDE软件。一般需要四个步骤:项目文件的建立(重命名)、项目文件修改、修改APP目录及源文件、编译选项的设置。

1.1 项目文件的建立(重命名)

第一步,在Texas Instrument/ZStack-2.2.2-1.3.0/Projects/zstack/Samples文件夹下建立用户自己的文件夹,将其命名为HumandTemApp。在此文件夹下,创建两个子文件夹:CC2530和Source,其中CC2530文件负责项目平台的创建,Source文件负责源代码的实现。第二步,将TI官网提供的示例项目中用于创建项目平台的文件复制一份到用户文件夹,具体操作如下:选择Texas nstrument/ZStack-2.2.2-1.3.0/Projects/zstack/Samples/GenericApp/CC2530DB文件夹中的GenericApp.ewd、GenericApp.ewp、GenericApp.eww这三个文件复制一份粘贴在HumandTemAPP/CC2530文件夹下,并将这些文件的名称改为HumandTemApp.ewd、HumandTemApp.ewp、HumandTemApp.eww。需要注意的是,只修改文件名,文件类型(即文件后缀名)保持不变。

1.2 项目文件修改

使用记事本方式分别打开HumandTemApp.ewd、HumandTemApp.ewp、HumandTemApp.eww三个文件,采用查找替换的方法,将这三个文件中的“GenericApp”全部替换为“HumandTemApp”。

至此,将实例系统中用于创建项目平台的非开源代码,成功移植到了用户的项目中,用户项目平台创建完成。

1.3 修改APP目录及源文件

使用IAR软件打开HumandTemAPP/CC2530目录下HumandTemApp.eww文件,可以看到名为HumandTemApp的项目。第一步,将HumandTemApp项目下App目录下的所有源文件删除(实例项目的源文件),操作方法是:选中HumandTemApp项目下App目录下的任一源文件,鼠标左键点击选中该源文件,然后点击右键选中下拉列表中的Remove选项,即可将该文件删除。第二步,创建用户自己的源文件,并完成协调器、路由器或终端源程序。在TI官网提供的实例GenericApp中,协调器、路由器或终端源程序都写在了同一个文件中。程序运行时是借助于条件编译来实现不同功能的。为了使源代码读写更加清晰,用户可以选择将协调器、路由器或终端源程序分开编写[3]。具体操作如下:在HumandTemApp项目下,点击选中App目录,然后点击IAR软件的菜单栏Project/Add Group,在App目录添加文件夹,如协调器的源文件Coordinator、路由器的源文件Router或终端设备EndDevice。

1.4 选择编译选项设置

用户需要根据自己项目的结构,选择协议栈默认网状拓扑结构。项目内含有协调器节点CoordinatorEB、路由节点Router和终端节点EndDevice。用户打开IAR软件的Project/Edit Configuration进行Workspace选项的设置。首先用户可通过删除功能(Remove)将原有GenericApp例程中Workspace各选项删除,然后通过新建功能(New)建立用户自己的Workspace各选项CoordinatorEB、Router和EndDevice。

当用户选择编译协调器选项时,将路由器和终端节点的编译选项屏蔽掉。具体操作方法如下:第一步,在Workspace中选择CoordinatorEB;第二步,在HumandTemApp项目下,点击选中App目录下用户创建的Router;第三步,点击鼠标右键,选择下拉列表选项中的Options中的Options for node“HumandTemApp”,打开对话框后,选中Exclude from build,采用相同方法对EndDevice进行编译设置。这样就保证在编译Coordinator时,不会对Router和EndDevice进行编译。

当然,用户在Workspace中选择EndDevice时,也可以用相同方法屏蔽协调器和路由器。

2 网络参数的设置

在文件nwk_globals.h中的三种宏定义对应ZigBee网络的三种网络拓扑结构。每一种协议规范都有自己缺省的网络拓扑结构及相关网络设置。例如,在ZIGBEEPRO_PROFILE协议规范下,将网络默认设置为网状拓扑。

在Z-Stack-CC2530-2.5.0中,存在三种逻辑设备的类型:Coordinator(协调器)、Router(路由器)和End-Device(终端设备)。在编译时也可以通过编译选项确定逻辑设备具体属于哪种类型。

3 协调器源代码编写

Z-Stack协议栈的核心是事件的产生与事件的处理。协调器源代码主要分为两部分:一是任务的初始化;二是用户事件的处理。

3.1 任务初始化

任务的初始化借助于任务初始化函数完成。该函数的编写可以参考TI官网提供的GenericApp中的OSAL_GenericApp.c文件。

需要修改的主要有两部分:

(1)将任务初始化函数osalInitTasks()的最后一个任务修改为用户自定义的任务初始化,如HumandTemApp_Init(TaskID),并参照官网实例GenericApp_Init(TaskID)修改用户的HumandTemApp_Init(TaskID)函数。

ZigBee协议栈采用的OSAL是一种支持多任务运行的系统资源分配机制,它是一种基于事件驱动的轮询式实时操作系统[4]。OSAL专门分配了存放所有任务事件的tasksEvents[]数组,每一个单元对应存放着每一个任务的所有事件。当某一个任务有事件发生时,程序会通过osal_set_event()或者osal_msg_event()函数触发事件[5],将tasksEvents[]数组中对应单元设置为1。因此当tasksEvents[]数组某个单元不为零时,说明相应的任务有事件发生。也有可能同时发生多个事件,即tasksEvents[]数组有多个元素为1。

(2)把用户自定义的事件处理函数如HumandTemApp_ProcessEvent()添加到事件处理函数数组tasksArr[],作为该数组的最后一个元素。

OSAL轮询系统查询到某一层有事件发生时,将通过do-while循环来遍历tasksEvents[],找到一个具有待处理事件的优先级最高的任务,序号低的任务优先级高,然后跳出循环,此时就得到了最高优先级任务的序号idx,然后通过events=tasksEvents[idx]语句将当前具有最高优先级的任务事件取出,接着调用(tasksArr[idx])(idx,events)函数来执行具体的处理[6],即调用对应层的事件处理函数来完成对该事件的处理。处理完该事件后,该事件会被清除。如果所有事件全都被处理完成,该层的事件处理函数将返回零。

用户只需要编写用户自定义的事件处理函数,如HumandTemApp_ProcessEvent(),其余层的事件处理函数ZigBee协议栈已经写好,用户一般无需编写或修改。

3.2 用户事件的处理

用户事件的处理,可以参考TI官网提供的GenericApp中的GenericApp.c。

(1)首先对所使用的端点、簇等进行定义,并参考GenericApp.c中的GenericApp_Init()函数编写用户的任务初始化函数,如HumandTemApp_Init()。

一般情况下,一个设备如果同时存在多个应用(例如,一个终端设备既要连接一个湿度传感器,又要连接温度传感器),可以为每个应用建立一个端点(端点号可以由用户从1~240中任意选定),并且要为每个端点关联一个taskID。需要注意的是,一个taskID是可以同时关联多个端点的,但是某个特定端点只能关联一个taskID。例如,在HumandTemApp_Init()函数中,可以用如下代码,将端点和应用层任务HumandTemApp_TaskID挂钩。

//Fill out the endpoint description

HumandTemApp_epDesc.endPoint=10;//HumandTemApp_ENDPOINT;此端点编号为10

HumandTemApp_epDesc.task_id=&HumandTemApp_TaskID;和应用层任务挂钩

//Register the endpoint description with the AF

afRegister(&HumandTemApp_epDesc);//注册端点,调用该函数才能完成整个挂钩操作

(2)所有用户事件的处理都是经过用户事件处理函数来完成的。用户可以参考GenericApp.c中的GenericApp_ProcessEvent()编写协调器的事件处理函数HumandTemApp_ProcessEvent()。

ZigBee事件分为两类:一类为系统事件(协议栈已经定义好);另一类为用户事件(用户可以自己定义)。不同事件按照事件类号进行区分。事件类号采用one-hot code(独热码)进行编码,即只有一个bit为1,其余全为0。协议栈已经通过宏定义系统事件SYS_EVENT_MSG为0x8000,自定义的用户事件可以从0x4000~0x0001(共15个)中由用户任选1个(只要不与现有的事件冲突即可),例如,用户发送事件可以定义为#define SENT_MSG 0x0004。

事件处理函数GenericApp_ProcessEvent(byte task_id,UNINT events)(调用此函数需要传递的task_id为任务号,events为事件类号),该函数内部可以调用若干个不同函数对不同类型的事件进行处理。第一步,根据事件类号events来判定何种事件发生。提取系统事件的方法是判定(events&SYS_EVENT_MSG)是否为真,如果是,那么该事件即为系统事件。通过任务号task_id接收消息,获取消息指针MSGpkt,然后根据消息中的事件号MSGpkt->event来处理具体事件。处理完系统事件后,将用return(events^SYS_EVENT_MSG)将该事件清除。第二步,若要提取某个用户事件,例如判断SENT_MSG是否发生,则可以通过判定(events&SENT_MSG)是否为真,如果是,则调用用户的相应函数进行处理。处理完成该事件后,采用return(events^SYS_EVENT_MSG)将该事件清除。

4 路由器或节点源代码的编写

路由器或终端设备源代码的编写步骤与协调器源代码结构编写步骤类似。由于路由器与协调器在网络中的功能不同,发生的事件和处理方式可能不同,主要区别在于用户事件的处理函数HumandTemApp_ProcessEvent()可能不同。

需要注意的是,在编写源代码时,协调器与路由器或终端节点之间数据的发送或接收,前后要清晰一致。如在无线温湿度测量系统中,测量的终端节点可以通过osal_start_timerEx()函数定期触发事件,在事件处理函数中可以通过AF_DataRequest()函数完成数据的发送。协调器接收到数据后会触发AF_INCOMING_MSG_CMD事件,当OSAL检测到该事件发生会调用用户编写的HumandTemApp_ProcessMSGCmd()进行处理,以便接收数据进行显示或者将数据传送至上位机。

5 结语

Z-Stack协议栈学习的关键是理解基于轮询及优先级控制的任务管理方式。由于Z-Stack是一个半开源的协议栈,有很大一部分源代码对用户并不开放,使初学者在理解上可能存在障碍。针对Z-Stack半开源的协议栈的特点,新的项目并不需要用户独立创建,通过移植的方法将用户不可见的那些源代码融入用户自己的项目中。这对用户来讲既省时又省力,用户只需要将精力集中在如何写应用层的源代码即可。

猜你喜欢

源文件源代码路由器
买千兆路由器看接口参数
维持生命
路由器每天都要关
路由器每天都要关
基于TXL的源代码插桩技术研究
网络社区划分在软件质量问题分析中的应用
基于源文件可疑度的软件缺陷定位方法研究
软件源代码非公知性司法鉴定方法探析
基于语法和语义结合的源代码精确搜索方法
LKJ基础数据源文件自动编制系统的研究