12 OSLA
预备知识
OSAL(Operating System Abstraction Layer,系统抽象层),可以通俗地理解为一个简化版的操作系统,为Z-Stack的正确运行提供了内存管理、中断管理和任务调度等基本功能。
-
任务ID:应用层是一个任务,它有一个系统分配给他的数值唯一的编号
-
任务事件处理函数:任务可以处理事件,处理事件的这些代码都在一个函数里
-
任务事件变量:应用层任务还有一个 2个字节的变量
-
应用层任务事件变量和应用层定义的事件【之前通过宏定义,定义的代表这个事件的2个字节变量】的关系
- 如果事件变量和某个事件的宏值与操作为1,那么表示应用层任务将要处理这个事件。
-
系统在运行的时候会不断的去读应用层任务事件变量,当它发现这个变量为0时,就认为应用层任务当前没有事件需要去处理;如果发现这个变量不为0,它就认为应用层任务有事件将要去处理,它就会去调用应用层任务事件处理函数
TestApp_ProcessEvent( byte task_id, UINT16 events )
,并且把任务事件变量的值传给events
。 -
在事件处理函数里,
events
会分别和应用层定义的所有事件宏值进行与操作,如果发现那个为0,那么就去执行这个事件处理的相应代码 -
osal_set_event()
调用设置任务事件函数,TestApp_TaskID
就会去执行TestApp_SEND_MSG_EVT
事件相应的处理代码。- 本质:把
TestApp_TaskID
(应用层任务)的任务事件变量中对应于TestApp_SEND_MSG_EVT
宏值为1的那个为变成1,这样话首先这个任务事件变量就变成了非0,系统在检测到任务事件变量为非0,就会去调用任务事件处理函数TestApp_ProcessEvent
,在这个函数里,任务事件变量肯定和TestApp_SEND_MSG_EVT
宏值与操作为1,所以必定会执行这个事件相关的代码。
- 本质:把
-
每一个层都是一个任务,因此每一个层都有1个任务ID。 任务事件处理函数 任务事件变量
- FUN函数数组={任务事件处理A,任务事件处理B,任务事件处理C…}
- Arr变量数组={任务事件变量a,任务事件变量b,任务事件变量c…}
-
任务ID,系统不是随便分配,可以通过这个值立即找到这个任务自己的任务事件处理函数和事件变量
- 例如:应用层任务的任务ID是8
- 那么FUN[8]里面是对应的任务处理函数的函数名
- Arr[8]里面就是该任务的事件变量
其他资料上的专业性定义:
任务(Task):可以理解为需要处理器处理的具体任务,例如“在1秒后开灯”或者“关灯”等等。
任务池:是一个可以存储多个任务的缓冲区,例如一个任务池中可以存放“1秒后开灯”、“2秒后关灯”、“3秒后开灯”及“1分钟后关灯”这几个任务。系统会在指定的时间去执行任务池中的各个任务。
优先级:由于可能存在在同一个时刻需要执行多个任务的情况,所以需要区分在这个时刻优先处理哪些任务、延后处理哪些任务,而优先级是用来标记每一个任务的优先等级。在相同条件下,系统会优先处理高优先级的任务,同时低优先级的任务需要等待处理。另外,系统也可能会中断优先级较底的任务,转而去处理优先级较高的任务。
轮询:系统会每隔一段时间在任务池中检查有没有现在需要处理的任务,这个过程称为轮询。
操作系统调度周期:调度周期是指轮询概念中“每隔一段时间”的具体时间长度。系统调度周期也是任务的最小时间周期,例如系统调度周期是1秒钟,但是存在一个任务是“0.1秒后关灯”,该任务虽然要求0.1秒后关灯,但由于0.1秒小于系统调度周期,所以这个任务在1秒后才会被执行。
动手实现系统调度
osal_init_system
函数osal_init_system
中有一个osalInitTasks();
函数,在这个函数里系统给所有任务分配任务ID.
1 | void osalInitTasks( void ) // 定义函数 osalInitTasks,该函数不接受任何参数并且没有返回值 |
osal_start_system
do-while循环的作用:
轮询整个任务池,也就是看一下有没有要处理的任务。循环中只有一个条件判断,如果条件成立,那么就结束循环。
其中的tasksEvents是一个uint16类型的数组,其中的每一个元素都表示一种类型的任务,也就是说,tasksEvents就是一个任务池,tasksCnt是这个任务池的大小。
这个循环的运行逻辑是:
- 首先,idx的初始值为0;
- 当tasksEvents[idx]的值为0时,表示该任务中没有事情要处理,这时候条件判断不成立,进入下一次循环;
- 每执行1次循环前,idx加1,然后判断是否小于tasksCnt;
- 当tasksEvents[idx]的值不等于0时,表示该任务中有事情要处理,这时候条件判断成立,于是通过break结束循环;
- 当循环结束后,如果整个任务池中都没有任务要处理,那么idx必定会>=tasksCnt。因此,如果idx < tasksCnt,表示现在任务池中有任务需要处理,并且tasksEvents[idx]就是当前需要处理的任务。因此在循环结束后,Z-Stack先用if (idx < tasksCnt)语句来判断有没有任务需要处理。
1 | /* |