Z-STACK协议栈应用开发分析
扫描二维码
随时随地手机看文章
引言
Z-STACK是TI公司推出的符合Zigbee2006规范且可支持多种平台(包括CC2430/1)的协议栈。因其采用分布式寻址方案及简化的AODV路由,故能适应无线传感器网络特点,并能在有移动节点、链路失效和丢包的环境下工作。为了方便任务管理,Z-STACK协议栈定义了完全构建在应用层上的OS-AL层(OperationSystemAbstractionLayer,操作系统抽象层),该层可以隔离Z-STACK协议栈和特定硬件系统,并采用轮询及优先级控制方式实现任务调度,也支持IAR交互式及命令行编译配置。其强大的协议栈功能使Z-STACK在竞争激烈的ZigBee领域占有很重要的地位,但Z-STACK协议栈相对复杂、开发周期较长。本文主要介绍Z-STACK协议栈的层次结构、任务调度流程,同时结合具体案例分析了基于Z-STACK协议栈的应用开发流程。
1 Z-STACK协议栈的层次结构
Z-STACK协议栈总体上由硬件抽象层(HAL),操作系统抽象层(OSAL)和ZigBee协议各层组成"。HAL层提供Timer,I/O.UART等资源的API;OSAL层负责任务管理,它采用轮询机制,并且引入了优先级控制,可以隔离协议栈和特定硬件系统,因而用户无须过多了解具体平台的底层,就可以利用OSAL提供的丰富工具实现各种功能,包括任务注册、初始化和启动,同步任务,多任务间的消息传递,中断处理,定时器控制,内存定位等:2:;ZigBee协议各层集成有任务事件。从程序执行角度看,一般主要接触的是HAL层和OSAL层。
2 Z-STACK协议栈的任务调度流程
Z-STACK的任务管理主要由OSAL层完成。在OSAL中判断事件发生是通过tasksEvents[idx]任务事件数组来进行的在OSAL初始化时,tasksEvents[]数组被初始化为零,一旦系统中有事件发生,就用osal_set_event()函数把tasksEvents[taskID]赋值为对应的事件。不同的任务有不同的taskID,这样,任务事件数组tasksEvents中就会表示系统中哪些任务存在没有处理的事件,然后调用各任务处理对应的事件。
3 基于Z-STACK协议栈的应用开发流程
3.1 初始化应用服务变量及分配任务ID
以Z-STACK自带的OSAL_GenericApp.c文件为例,tasksArr[]和osallnit Tasks()主要完成应用服务变量的初始化及任务ID的分配。
tasksArr[]数组里存放了所有任务事件处理函数的指针(默认有6个任务),可标识与其对应的任务。tasksArr[]定义如下:
constpTaskEventHandlerFntasksArr[]={
...
ZDApp_event_loop,};
osallnitTasks()是OSAL的任务初始化函数,所有任务的初始化工作都在这里面完成,并且自动给每个任务分配一个ID。osallnitTasks()的定义如下:
void osallnitTasks(void){uint8taskID=0;
tasksEvents=(uintl6*)osal mem alloc(sizeof(uintl6)*tasksCnt);
osal_memset(tasksEvents,0,(sizeof(uintl6)*task-sCnt));
...
ZDApp_Init(taskID++);}
添加新任务GenericApp时,首先需将事件处理函数GenericApp ProcessEvent的指针加入task-sArr[],然后在osallnitTasks()中调用此任务的初始化函数GenericApp Init(tasked);。 应当注意的是,TaskArr[]里各任务函数的排列顺序要与osalln-itTasks()函数中调用各任务初始化的函数相一致,以保证各任务能通过初始化函数接收到正确的任务ID。
在系统运行时,OSAL如何将事件分配给任务osallnitTasks()中使用的全局变量tasksCnt保存有当前的任务个数,tasksEvents是一个指向数组的指针,此数组保存了当前任务的状态。由此可以看出,osallnitTasks()中将所有任务的状态都被初始化为0,这代表了当前任务没有需要响应的事件。之后,在main。函数中调用死循环函数osal_start_sys-tem(),再通过代码do(if(tasksEvents[idx])break;}while(十十idxVtasksCnt);完成所有的事件分配。若tasksEvents[]这个数组中的某个元素不为0,即代表此任务有事件需要响应,事件类型取决于这个元素的值。这个do-while循环会选出当前优先级最高的需要响应的任务,events=(tasksArr[idx])(idx,events);语句将调用tasksArr[]数组里面相应的事件处理函数来响应事件。如果新添加的任务有了需要响应的事件,那么此任务的事件处理程序就会被调用。这样,OSAL就会将需要响应的事件传递给了对应的任务处理函数进行处理。
3.2 在AF层中注册应用服务
要将ZigBee节点加入ZigBee网络,通常需要在任务中做以下两件事情
其一是定义此任务为ZigBee应用服务对象所需要的信息。其二是将这些信息注册到应用程序框架之中。通过在AF层注册应用对象的信息,可以告知系统afAddr_Type_t地址类型数据包的路由端点。通过填入endPointDesc_t数据格式的EndPoint变量,便可调用afRegister()在AF层注册EndPoint应用对象(afRegister(&-GenericApp MANAGE epDesc);)。
3.3 注册相应的OSAL或HAL系统服务
由于任何Z-STACK任务均不自行注册系统服务,因此,包括串口活动响应在内的任何任务都需要由应用程序注册官。例如,应用程序中需要使任务能够接收到按键消息,因而必须在应用程序框架中进行注册,告诉应用程序框架,如有按键消息即请传递过来。可通过代码RegisterForKeys(GenericApp MANAGE_TaskID)在GenericApp_MANAGE_Init函数中注册系统服务。
3.4 处理任务事件
Z-STACK通过创建ApplicationName Pro-cessEvent()函数来处理任务事件。一个OSAL任务除了强制事件(MandatoryEvents)之外,还可以定义包括ZDO_STATE_CHANGE在内的15个事件。当一个ZigBee节点成功加入网络以后,ZDO就会给所有已经在应用程序框架中注册过的任务发送一个ZDO_STATE_CHANGE消息,消息的状态指示了当前网络的状态登。可以通过处理此消息完成应用功能。以TIDEMO提供的键控LED灯为例,当一个消息被发送给任务时,SYS_EVENT_MSG事件会被传递给任务,通知任务有一个消息等待处理。所以,必须添加对于SYS_EVENT_MSG这个事件的响应,然后从消息队列中取出消息,并判断此消息是否为ZDO STATE_CHANGE,同时在处理ZDO_STATE_CHANGE消息时点亮LED灯。
4 结语
Z-STACK协议栈提供有强大的功能,这使得大部分应用设计都能基于现有的开放式协议进行应用开发。对于初学者而言,学习Z-STACK的关键是理清Z-STACK的协议栈结构以及及基于轮询及优先级控制的任务管理方式。文中在简要介绍了Z-STACK协议栈层次结构的基础上,详细分析了任务调度流程以及基于协议栈的应用开发流程。