深入浅出OSAL多任务资源分配机制_第1页
深入浅出OSAL多任务资源分配机制_第2页
深入浅出OSAL多任务资源分配机制_第3页
深入浅出OSAL多任务资源分配机制_第4页
深入浅出OSAL多任务资源分配机制_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、、概述OSAL (Operating System Abstraction Layer),翻译为“操作系统抽象层”。如何理解 这个复杂的名词呢?表面上看它是作为操作系统存在的,可是为什么又加上“抽象层”呢? 它的本质是什么?在Z-Stack协议栈中,它又扮演了什么角色呢?要解答这些问题,我们必、 须先从宏观入手,渐渐深入探究,最后答案自然会浮出水面。应用程序框架匝月程序应用程序对象240对象1碑京0 时5挡:捐K I林多枷点下图是ZigBee协议的结构图:Ei*曲设备对象(ZDQ)go恣共接口2宅。七或拦一.二3隽.多:.卖悻略黄问点.牲咀先*问席应用程序支持子晨(APS)APS安全管理lC攻

2、寸厘洗W疽安全.服务携供者so管埋面板媒体访问控制层PHV物理层(PHY)2.4 GHz-068/915 MHz从这幅图中,我们可以很清楚地从宏观上了解ZigBee协议的结构。可是,经过粗略的 浏览,我们并没有发现任何OSAL的踪迹。当然,我们都知道,Z-Stack与ZigBee之间并不 能完全划等号。Z-Stack是ZigBee的具体实现,所以存在于Z-Stack中的OSAL并不一定出 现在ZigBee中。但是,我们可以在ZigBee中找到些许OSAL的踪影。在ZigBee协议中,协议本身已经定义了大部分内容。在基于ZigBee协议的应用开发中, 用户只需要实现应用程序框架即可。从上图可以看

3、出应用程序框架中包含了最多240个应用 程序对象。如果我们把一个应用程序对象看做为一个任务的话,那么应用程序框架将包含一 个支持多任务的资源分配机制。于是OSAL便有了存在的必要性,它正是Z-Stack为了实现 这样一个机制而存在的。OSAL就是以实现多任务为核心的系统资源管理机制。所以OSAL与标准的操作系统还是 有很大的区别的。简单而言,OSAL实现了类似操作系统的某些功能,但并不能称之为真正 意义上的操作系统。二、OSAL任务运行方式弄明白了 OSAL是何方神圣,接下来我们将深入Z-Stack,进一步研究OSAL。为了方便,我们使用Z-Stack所提供的GenericApp这个例程为例来

4、进行分析。此例程 的默认路径为C:Texas InstrumentsZStack-1.4.3-1.2.1ProjectszstackSamplesGenericApp。首先我们去繁就简,先来了解应用程序的运行方式。在右侧工作空间窗口打开App文件夹,我们可以看到三个文件,分别是“GenericApp.c”、 “ GenericApp.h ”、 OSAL_GenericApp.c ”。我们整个程序所实现的功能都在这三个文件当中。首先打开GenericApp.c这个文件。我们首先看到的是比较重要的两个函数: GenericApp_Init和GenericApp_ProcessEvent。从函数名称

5、上我们很容易得到的信息便是, GenericApp_Init是任务的初始化函数,而GenericApp_ProcessEvent则负责处理传递给此 任务的事件。大概浏览一下GenericApp_ProcessEvent这个函数,我们可以发现,此函数的主要功能 是判断由参数传递的事件类型,然后执行相应的事件处理函数。我们可以由此推断Z-Stack 应用程序的运行机制如下图所示:当有一个事件发生的时候,OSAL负责将此事件分配给能够处理此事件的任务,然后此 任务判断事件的类型,调用相应的事件处理程序进行处理。明白了这个问题,新的问题又摆在了我们的面前:OSAL是如何传递事件给任务的。三、OSAL的

6、事件传递机制在试图弄清楚这个问题之前,我们需要弄清楚另外一个十分基础而重要的问题。那就是 如何向我们的应用程序中添加一个任务。我们先来看看GenericApp是如何添加任务的。我们打开OSAL_GenericApp.c文件。这里我们可以找到一个很重要的数组tasksArr和一个同样很重要的函数osallnitTasks。TaskArr这个数组里存放了所有任务的事件处理函数的地址,在这里事件处理函数就代 表了任务本身,也就是说事件处理函数标识了与其对应的任务。osallnitTasks是OSAL的任务初始化函数,所有任务的初始化工作都在这里面完成, 并且自动给每个任务分配一个ID。要添加新任务,

7、我们需要编写新任务的事件处理函数和初始化函数,然后将事件处理函 数的地址加入此数组。然后在osallnitTasks中调用此任务的初始化函数。在此例中,我们 此前提到过的GenericApp_ProcessEvent这个函数被添加到了数组的末尾, GenericApp_Init 这个函数在 osalInitTasks 中被调用。值得注意的是,TaskArr数组里各任务函数的排列顺序要与osalInitTasks函数中调用 各任务初始化函数的顺序必须一直,只有这样才能够保证每个任务能够通过初始化函数接收 到正确的任务ID。另外,为了保存任务初始化函数所接收的任务ID,我们需要给每一个任务定义一个

8、全 局变量来保存这个ID。在GenericApp中GenericApp.c中定义了 一个全局变量 GenericApp_TaskID ;并且在 GenericApp_Init 函数中进行了赋值GenericApp_TaskID = task_id;这条语句将分配给GenericApp的任务ID保存了下来。到此,我们就给应用程序中完整的添加了一个任务。我们回到OSAL如何将事件分配给任务这个问题上来在OSAL_GenericApp.c这个文件中,在定义TaskArr这个数组之后,又定义了两个全局 变量。tasksCnt这个变量保存了当前的任务个数。tasksEvents是一个指向数组的指针,此数

9、组保存了当前任务的状态。在任务初始化函 数中做了如下操作tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);osal_memset(tasksEvents, 0, (sizeof( uint16 ) * tasksCnt);我们可以看出所有任务的状态都被初始化为0。代表了当前任务没有需要响应的事件。紧接着,我们来到了 main()函数。此函数在ZMain文件夹的ZMain.c文件中。略过许 多对当前来说并非重要的语句,我们先来看osal_init_system()这个函数。在此函数中, osalInitTas

10、ks。被调用,从而tasksEvents中的所有内容被初始化为0。之后,在main()函数中,我们进入了 osal_start_system()函数,此函数为一个死循 环,在这个循环中,完成了所有的事件分配。首先我们来看这样一段代码:doif (tasksEventsidx)break; while (+idxtasksCnt);当tasksEvents这个数组中的某个元素不为0,即代表此任务有事件需要相应,事件类 型取决于这个元素的值。这个do-while循环会选出当前优先级最高的需要响应的任务,events = (tasksArridx)( idx, events );此语句调用tasks

11、Arr数组里面相应的事件处理函数来响应事件。如果我们新添加的任 务有了需要响应的事件,那么此任务的事件处理程序将会被调用。就这样,OSAL就将需要响应的事件传递给了对应的任务处理函数进行处理。四、事件的捕获不过接下来就有了更加深入的问题了,事件是如何被捕获的?直观一些来说就是, tasksEvents这个数组里的元素是什么时候被设定为非零数,来表示有事件需要处理的?为 了详细的说明这个过程,我将以GenericApp这个例程中响应按键的过程来进行说明。其他 的事件虽然稍有差别,却是大同小异。按键在我们的应用里面应该属于硬件资源,所以OSAL理应为我们提供使用和管理这些 硬件的服务。稍微留意一下

12、我们之前说过的tasksArr这样一个数组,它保存了所有任务的 事件处理函数。我们从中发现了一个很重要的信息:Hal_ProcessEvent。HAL(Hardware Abstraction Layer)翻译为“硬件抽象层”。许多人在这里经常把将Z-Stack的硬件抽象层 与ZigBee的物理层混为一谈。在这里,我们应该将Z-Stack的硬件抽象层与ZigBee的物理 层区分开来。硬件抽象层所包含的范围是我们当前硬件电路上面所有对于系统可用的设备资 源。而ZigBee中的物理层则是针对无线通信而言,它所包含的仅限于支持无线通讯的硬件 设备。通过这个重要的信息,我们可以得出这样一个结论:OSA

13、L将硬件的管理也作为一个任 务来处理。那么我们很自然的去寻找Hal_ProcessEvent这个事件处理函数,看看它究竟是 如何管理硬件资源的。在“HALCommenhal_drivers.c”这个文件中,我们找到了这个函数。我们直接分析与 按键有关的一部分。if (events & HAL_KEY_EVENT)#if (defined HAL_KEY) & (HAL_KEY = TRUE)/* Check for keys */HalKeyPoll();/* if interrupt disabled, do next polling */if (!Hal_KeyIntEnable)osal

14、_start_timerEx(Hal_TaskID, HAL_KEY_EVENT, 100);#endif / HAL_KEYreturn events HAL_KEY_EVENT;在事件处理函数接收到HAL_KEY_EVENT这样一个事件后,首先执行HalKeyPoll()函数。 由于这个例程的按键采用查询的方法获取,所以是禁止中断的,于是表达式 (!Hal_KeyIntEnable)的值为真。那么 osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100)得以执行。osal_start_timerEx这是一个很常用的函数,它在这里的功能是经过10

15、0 毫秒后,向Hal_TaskID这个ID所标示的任务(也就是其本身)发送一个HAL_KEY_EVENT 事件。这样以来,每经过100毫秒,Hal_ProcessEvent这个事件处理函数都会至少执行一 次来处理HAL_KEY_EVENT事件。也就是说每隔100毫秒都会执行HalKeyPoll()函数。那么我们来看看HalKeyPoll函数到底在搞什么鬼!代码中给的注释为:/* Check for keys */HalKeyPoll();于是我们推断这个函数的作用是检查当前的按键情况。进入函数一看,果不其然。虽然 这个函数很长很复杂,不过凭借着非凡的聪明才智,我们还是十分清楚的明白了,经过一系

16、 列的if语句和赋值语句,在接近函数末尾的地方,keys变量(在函数起始位置定义的) 获得了当前按键的状态。最后,有一个十分重要的函数调用。(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);pHalKeyProcessFunction这个函数指针指向了哪个函数我们现在依然不清楚,但是为 了我们有个清晰而不间断的思路,我在这里先告诉大家。在这里调用的是voidOnBoard_KeyCallback ( uint8 keys, uint8 state )这个函数。此函数在“ZMainOnBoard .c”文件中可以找到。在这个函数中,又调用

17、了 voidOnBoard_KeyCallback ( uint8 keys, uint8 state )在这个函数中,按键的状态信息被封装到了一个消息结构体中(对于消息,我们稍后再 说)。最后有一个极其重要的函数被调用了。osal_msg_send(registeredKeysTaskID, (uint8 *)msgPtr );与前面的 pHalKeyProcessFunction 相同,我先直接告诉大家 registeredKeysTaskID 所指示的任务正式我们需要响应按键的GenericApp这个任务。那么也就是说,在这里我们向GenericApp发送了一个附带按键信息的 消息。在

18、osal_msg_send 函数中osal_set_event(destination_task, SYS_EVENT_MSG );被调用,它在这里的作用是设置destination_task这个任务的事件为SYS_EVENT_MSG。 而这个destination_task正式由osal_msg_send这个函数通过参数传递而来的,它也指示 的是GenericApp这个任务。在osal_set_event这个函数中,有这样一个语句:tasksEventstask_id |= event_flag;至此,刚才所提到的问题得到了解决。我们再将这个过程整理一遍。首先,OSAL专门建立了一个任务来对

19、硬件资源进行管理,这个任务的事件处理函数是 Hal_ProcessEvent。在这个函数中通过调用 osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);这个函数使得每隔100毫秒就会执行一次 HalKeyPoll()函数。 HalKeyPoll()获取当前按键的状态,并且通过调用OnBoard_KeyCallback函数向GenericApp 任务发送一个按键消息,并且设置tasksEvents中GenericApp所对应的值为非零。如此, 当main函数里这样一段代码doif (tasksEventsidx)break; while (+i

20、dxtasksCnt);执行了以后,GenericApp这个任务就会被挑选出来。然后通过events = (tasksArridx)( idx, events );这个函数调用其事件处理函数,完成事件的响应。现在,我们回过头来处理我们之前遗留下来的问题。第一、pHalKeyProcessFunction 这个函数指针为何指向了 OnBoard_KeyCallback 函数。在HALCommenhal_drivers.c这个文件中,我们找到了 HalDriverInit这个函数,在 这个函数中,按键的初始化函数HalKeyInit被调用。在HalKeyInit中有这样的语句:pHalKeyPro

21、cessFunction = NULL;这说明在初始化以后pHalKeyProcessFunction并没有指向任何一个函数。那 pHalKeyProcessFunction是什么时候被赋值的呢?就在HalKeyInit的下方有一个这样的函数HalKeyConfig。其中有这样一条语句:pHalKeyProcessFunction = cback;cback是HalKeyConfig所传进来的参数,所以,想要知道它所指向的函数,必须找到 其调用的地方。经过简单的搜索我们不难找出答案。在main函数中有这样一个函数调用: InitBoard( OB_READY );此函数中做了如下调用:HalKeyConfig(OnboardKeyIntEnable, OnBoard_KeyCallback);第二、registeredKeysTaskID 为什么标识了 GenericApp 这个任务?由于OSAL是一个支持多任务的调度机制,所以在同一时间内将会有多个任务同时运行。 但是从逻辑上来讲,一个事件只能由一个任务来处理。按键事件也不例外。那么如何向OSAL声明处理按键事件的任务是GenericApp呢?在Generic

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论