事件驱动型OSAL系统原理分析|学习笔记

简介: 快速学习事件驱动型OSAL系统原理分析

开发者学堂课程【嵌入式之RFID开发与应用2020版事件驱动型OSAL系统原理分析】学习笔记与课程紧密联系,让用户快速学习知识

课程地址https://developer.aliyun.com/learning/course/665/detail/11129


事件驱动型OSAL系统原理分析

 

1、0SAL, Operating , System A bstraction Layer ,即操作系统抽象层。

2、从 Z -Stack1.4.3及以后开始引入OSAL 。

3、0SAL是一种基于事件驱动的轮询式操作系统,所提供的管理功能有:

(1)任务登记、任务初始化、任务触发

(2)任务间消息传递

(3)任务同步

(4)中断处理

(5)计时器

(6)内存分配

抛开Cc2530芯片单独看OSAL系统。对协议栈如果没有操作系统去支撑,那么它的整个运行,也是可以的。但是很多的逻辑的处理需要自己去做,有了操作系统它的整个的处理就会变得更加的有序也不容易出错。OSAL就是操作系统抽象层的一个缩写。在TI从1.4.3的这个协议栈开始就已经引入了OSAL系统。

为了缩小的体积,变成一个低功耗轻量级的,之前就没有这个系统,或者说很多方案里面就没有这个系统。OSAL操作系统并不是linux windowsWIN七这种大型的操作系统。

这个操作系统更多是像管家一样来管理着各种通讯事件的执行,包括一些定时器内存分配这些工作,它的核心是基于事件驱动。当有事情的时候,创建了任务才会被执行,如果没有事情,这个任务是不执行的,这样节省了时间和空间。他不是一个时间片的,也不会去抢占。他其实就是一个纯事件驱动的,他提供的功能有任务的登记注册初始化,还有一个处罚的方式,任务就是所谓的操作系统,最核心的五大功能之一就是任务调度,所以就把他叫进程或者线程。

当系统里面要用到一些硬件资源,第二个功能就是对软硬件资源进行管理,所以说OSAL也提供了操作Cc2530的管理,包括它的中断定时器IO按键。他其实提供了一套完整的流程,包括串口的操作,还有定时器怎么使用,申请内存怎么去分配都由OSAL来提供服务。

4、osal run system()不断轮询遍历所有任务事件,事件被置位后就会被调度执行该任务:

(1)需要注意的是每次任务被调度时都只处理一个事件,并在处理完后清除该事件。

image.png

整个操作系统的核心是靠这个osal run system来进行不断轮询遍历所有事件。

1019:*/

1020: void osal _ start _ system ( void )

1021:{

1022:# if ! defined ( ZBIT )&& Idefined ( UBIT)

1023:  for (;;)// Forever Loop

1024:# endif

1025:  {

1026:    osal _ run _ system ();

1027:  }

1028:}

1029:1030:/**********************************************

1031: *@ fn     osal _ run _ system

1032:*

1033:*@ brief

1034:*

1035:*This function wil1 make one pass through the oSAL taskEvents table

1036:* and cal1 the task _ event _ processor () function for the first task that

Start system其实就调了这一个函数,而且他是一个死循环。

它会不断去轮询所有的这些事件有没有发生,总之他的所有的事情都是由这个函数在不断轮询去发生的。这个函数是在我们的mian函数里面调的。这个函数的上面其实就是mian函数,所以这个操作系统首先由mian函数完成有关操作系统一系列的初始化,最后会停在osal run system这个死循环里面。

整个的操作系统是由事件来驱动任务调度什么事件,比如这个主要是用在无线通信里面。假设收到了一个数据,这就发生了一件事情,有一个任务是专门处理接收事情接收消息的,当它接收到消息的时候它的底层就会去设置这个标志位告知某个任务需要去处理。所以当事件发生的时候它驱使这个系统去找到置位的事件,并调用这个任务完成对接受这个事件的处理。当他把这个事情处理完了之后这个任务又停止了,除非这个任务还没处理完。每次只处理一件事情。

如果有两件事情,处理完这件事情之后退出去,下次再轮询的时候,发现另一个事件再去处理,另一个事件可能又有另一个任务去处理,这都是有可能的。

5、任务数组taskArr[]中的任务定义:

(1)unsigned short (*pTaskEventHandLerFn)(unsigned char task_id, unsigned short event);

image.png

106:*/

107:void osalInitTasks ( void )

108:{

109:uint8 taskID =θ

110:

111: tasksEvents =(uint16*) osal _ mem _ alloc ( sizeof (uint16)* tasksCnt );

112: osal _ memset ( tasksEvents ,θ,( sizeof (uint16)* tasksCnt ));

113:

114: macTaskInit ( taskID ++);

115: nwk _ init ( taskID ++)

116: Hal _ Init ( taskID ++)

117:# if defined ( MT _ TASK )

118: MT _ TaskInit ( taskID ++);

119:# endif

120:APS _ Init ( taskID ++);

121:# if defined ( zIGBEE _ FRAGMENTATION )

122: APSF _ Init ( taskID ++);

123:# endif

任务其实就是一个函数,创建一个线程必须指定一个函数,Java也是一样的,这个函数专门服务于这个进程,这个线程。

那进程的意义,可能还不太一样,但对于内核来说都叫任务,这个函数专门负责处理这个任务的事情。简单的理解,一个任务其实就是一个函数,系统里面有很多的任务可以创建很多的线程。每一个任务,每一个线程都需要一个函数,从而形成函数列表。这个函数列表是以函数指针数组的形式出现的。这个函数有一个返回值还有一个函数指针名。

第一个就是这个任务的ID,第二个是事件。当任务处理函数被调用的时候会给传一个ID进去,ID是区分不同任务的唯一标识,每增加一个任务ID就会增加一个。从零开始依次增加。每一个任务都有一个事件,都有一组事件标志位,而这一组事件标志位总共可以支持16位,也就是完整形的16位也就是每一个任务最多可以同时标记16个事件。

在这个任务函数指针数组里面存放着所有的任务,事件指实际上指向一系列。完整型的一个变量,这个变量里面有16位每一位代表一个事件,当这个标志位为1就表示这个事件处罚了,如果为0就表示这个时间没有处罚。前面的taskID是任务编号,每增加一个任务,他就加一,递增的,对这个任务进行调度执行之前的第一步是对每一个任务进行初始化,osinitTask其实就是在对我们的任务进行一个初始化。

这个ID的初始值是零,每初始化一个任务他就加一。

image.png

每一个任务都对应一个16位的短整型。有一个变量指针叫做task event。他指向了所有的任务的第一个任务的那个起始地址。在提取任务的事件的时候,会给他传一个任务号。这个Index就任务号,然后他这个任务号传进去后把这个短整型提取出来来判断这个是不是非零的。这里面任何一个都不可能是非零的。如果是非零的,就表示要处理这个事件。对这个事件进行处理的时候,这个事件本身是一位标志,比如说1左移N位,N是0~145这么一个取值。判断事件的时候也是用1左移N位,如果是非零就表示要处理这个事件,处理完这个事件之后还要用1左移N位抑或这个变量,目的就是将这个1拉新程里,表示这个事件处理完了,完了之后要把这个结果返回taskArr,其实就是去调用这个函数把任务号传进去,把当前的事件传进去。返回的这个事件就是他本次任务调度没有处理完的,剩下的事件它就会再次还给task event等待下次任务调度去处理。这就是事件驱动型的osal系统。

6、每个任务最多可以同时设置16个事件,但有些位己经被系统定义事件占用,所以自定义事件时最好不要与其冲突,如:

(1)任务间消息收发事件 SYS _ EVENT _ MSG =0x8000

虽然最多可以同时设置16个事件。但是实际上里面有些事件已经被占用了。任务间通信,比如一号任务给二号任务发了一个消息,那这个算不算是有事件发生?是有事件发生的,所以二号任务要去处理这个消息。所以任务间通信其中有一个标志位已经被占用其实就最后那一位。

7、taskEvents 事件要和后面 zigbee 协议栈中的 afIncomingMSGPacket _ t -> hdr . event 这个8bit的消息事件加以区别

8、指定任务添加事件:

(1)osal _ set _ event (uint8 task _ id ,

uint16 event _ flag )

tasksEvents [ task _ id ]= event _ flag ;

9、指定任务清除事件:

(1)osal _ clear _ event (uint8 task _ id ,

uint 16 event _ flag )

tasksEvents [ task _ id ]&=~( event _ flag);

如果启动某一个任务去执行就必须得设置事件,通过这个osal set event去设置事件。创建了那么多任务要让他处理哪一个任务处理哪一个事件, event Flag是1左移N位,也就是将16位里面的某一位置1了。

操作系统在轮询的过程当中,就会发现这个里面有不为零的这种事件,If idx是从零开始,最大值是不能超过他最后任务的总个数taskArr,任务总个数是任务数组的总大小除成员的大小。如果发现tasksEvents是短整型,它里面任何一个值非零,Break表示有置位了。有置位后面就回去处理这个事情,所以只要设置了这个事件轮询的时候就会发现这个时间,一旦发现这个事件就会去调用某个任务,而这个任务在处理完了之后他会怎么样的时间清除这个事件。这个是整个操作系统通过事件。一步步去驱动。

10、任务事件被置位,即任务调度,主要通过以下两种途径实现:

(1)直接通过调用 osal _ set _ event()给任务事件置位。

(2)任务调度结束后返回,通过返回未处理完的事件位重新置位。

11、还有间接通过 osal _ set _ event ()置位的情况,例如:

(1)一个任务给另一个任务发消息

(2)定时触发事件设置 osal _ start _ timerEx()

(3)zigbee 协议栈底层触发调用

不管是直接还是间接他都是通过什么osal set event去完成事件的设置,并且通过轮询去发现这个事件去调用任务处理函数,这里提到事件的设置有很多种情况,比如一个任务给另一个任务发了消息,他会去设置。定时器时间到了,或者是设置到某一个定时也会调用这个去设置。还有协议栈的底层收到的数据,比如接收到数据也是。所以只要有事情发生都通过它来完成事件的设置,并且通过Run system去轮询出哪个事件,然后通过task Arr将没有处理完的事情附给event,然后再把它放回去,这次循环就结束了。结束之后这个函数就退出,下次再进来的时候再去判断这个事件有没有被置位,有置位继续去重复执行下面这个过程,如果 do Well退出的时候发现idX等于最大值,就表示没有任何任务被置位也不需要去调动任何的任务。这就是任务事件驱动的osal系统。

相关文章
|
7月前
|
安全 数据处理 C++
【Qt 底层之事件驱动系统】深入理解 Qt 事件机制:主事件循环与工作线程的交互探究,包括 QML 的视角
【Qt 底层之事件驱动系统】深入理解 Qt 事件机制:主事件循环与工作线程的交互探究,包括 QML 的视角
1488 3
|
7月前
|
开发工具 C语言 git
【嵌入式开源库】MultiButton的使用,简单易用的事件驱动型按键驱动模块
【嵌入式开源库】MultiButton的使用,简单易用的事件驱动型按键驱动模块
177 0
|
安全 Linux
【Linux高性能服务器编程】信号处理方法之统一事件源
【Linux高性能服务器编程】信号处理方法之统一事件源
134 0
|
JSON 算法 物联网
第1期 | MultiButton,一个小巧简单易用的事件驱动型按键驱动模块
第1期 | MultiButton,一个小巧简单易用的事件驱动型按键驱动模块
305 0
|
消息中间件 缓存 供应链
“消息驱动、事件驱动、流 ”基础概念解析
本文旨在帮助大家对近期消息领域的高频词“消息驱动(Message-Driven),事件驱动(Event-Driven)和流(Streaming)”有更清晰的了解和认知,其中事件驱动 EDA 作为 Gartner 预测的十大技术趋势之一, EventBridge 作为下一代消息中间件,也是目前的重点方向之一。
327 0
“消息驱动、事件驱动、流 ”基础概念解析
|
消息中间件 Linux
事件驱动的I/O模型是什么意思?底层原理是什么?
事件驱动的I/O模型是什么意思?底层原理是什么?
201 0
|
前端开发 JavaScript
十四、深入核心,详解事件循环机制【下】
JavaScript的学习零散而庞杂,很多时候我们学到了一些东西,但是却没办法感受到进步!甚至过了不久,就把学到的东西给忘了。为了解决自己的这个困扰,在学习的过程中,我一直在试图寻找一条核心的线索,只要顺着这条线索,我就能够一点一点的进步。 前端基础进阶正是围绕这条线索慢慢展开,而事件循环机制(Event Loop),则是这条线索的最关键的知识点
158 0
十四、深入核心,详解事件循环机制【下】
|
Web App开发 移动开发 前端开发
十四、深入核心,详解事件循环机制【上】
JavaScript的学习零散而庞杂,很多时候我们学到了一些东西,但是却没办法感受到进步!甚至过了不久,就把学到的东西给忘了。为了解决自己的这个困扰,在学习的过程中,我一直在试图寻找一条核心的线索,只要顺着这条线索,我就能够一点一点的进步。 前端基础进阶正是围绕这条线索慢慢展开,而事件循环机制(Event Loop),则是这条线索的最关键的知识点。
211 0
十四、深入核心,详解事件循环机制【上】
|
Linux 调度
内核开发基础-如何使用内核延时
从事Linux内核开发特别是驱动开发的小伙伴,肯定需要经常使用到定时器,比如,按键的去抖、LED屏幕显存buffer的刷新等。同时,在控制硬件时,可能会用到十分精确地短延时,这时,定时器的精度就不能满足这种需求了,这时就会使用到高精度定时器和忙等延时。今天就来简要说一下如何正确的使用内核提供的delay和sleep函数。
377 0
|
存储 调度
带你读《C/OS-III内核实现与应用开发实战指南:基于STM32》之三:任务的定义与任务切换
本书分为两部分,第一部分先教你如何从0到1把uC/OS-III内核写出来,从底层的汇编开始讲解任务如何定义、如何切换,还讲解了阻塞延时如何实现、如何支持多优先级、如何实现任务延时列表以及时间片等uC/OS的核心知识点;第二部分讲解uC/OS-III内核组件的应用以及使用uC/OS-III进行多任务编程。