OSAL操作系统最多可以支持16个任务,由任务功耗管理PwrMgr_task_state变量可知,而OSAL每个任务最多只能支持16个事件处理,理论上最大可以执行256个事件处理。对于一些运算能力不强,内存空间不大的处理器最适合不过了。OSAL实际上不是一个真正意义上的操作系统,在加上它最多只能处理16个任务,所以OSAL没有像其他操作系统一样有复杂的任务调度算法,每个任务都是有序轮流执行。OSAL的任务管理代码主要在OSAL.c中。
最常用的任务函数格式是:有几个参数以及返回值。OSAL中任务事件处理函数如下:
typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );
OSAL中定义任务函数带两个参数的,一个是任务的id,另一个是要传递的事件。
const pTaskEventHandlerFn tasksArr[] =
{
LL_ProcessEvent, /* task 0 */
Hal_ProcessEvent, /* task 1 */
HCI_ProcessEvent, /* task 2 */
OSAL_CBTIMER_PROCESS_EVENT(osal_CbTimerProcessEvent), /* task 3*/
L2CAP_ProcessEvent, /* task 4 */
GAP_ProcessEvent, /* task 5*/
GATT_ProcessEvent, /* task 6 */
SM_ProcessEvent,/* task 7 */
GAPRole_ProcessEvent,/* task 8 */
GAPBondMgr_ProcessEvent,/* task 9 */
GATTServApp_ProcessEvent,/* task 10 */
SimpleBLEPeripheral_ProcessEvent /* task 11 */
};
tasksArr[]数组的元素就是各个任务的任务函数,系统会永远顺序执行这些任务函数。OSAL要添加一个新的任务很简单,只要在tasksArr[]添加对应的处理函数就可以了,不过任务函数的命名最好也遵照官方的要求,以XXXX_ProcessEvent为函数名。
在OSAL.c文件中,有一个osal_init_system()函数用来初始化OSAL函数,如下:
uint8 osal_init_system( void )
{
osal_mem_init(); /*初始化内存空间*/
osal_qHead = NULL; /*初始化消息队列*/
osalTimerInit(); /*初始化定时器*/
osal_pwrmgr_init(); /*初始化功耗管理器*/
osalInitTasks(); /*初始化各个任务*/
osal_mem_kick(); /*调整内存空间*/
return ( SUCCESS );
}
这个函数中,将OSAL的各个模块(如内存空间、定时器、功耗管理器等)初始化了一遍,以保证OSAL的各个机制可以正常使用。其中,osalInitTasks()函数初始化定义的各个任务,最主要的是给各个任务分配任务id,以及各个任务对应的事件空间,如下:
void osalInitTasks( void )
{
uint8 taskID = 0;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
Hal_Init( taskID++ );/* Hal Task */
......
SimpleBLEPeripheral_Init( taskID );/* Application */
}
在mian函数的循环中,调用osal_start_system()来启动系统任务。这个函数在OSAL.c中定义,而它实际上调用的是同文件下的osal_run_system()函数。
osal_run_system()正式来执行系统任务。它可以分成下面几个步骤:
(1)处理处理器需要轮询的硬件接口代码
直接调用Hal_ProcessPoll()函数来处理处理器的接口,这些接口可以是:UART、I2C、SPI等。
(2)查找是否有事件(event)发生
通过轮询任务事件数组tasksEvents[ ]来查看是否有事件发生。
do {
if (tasksEvents[idx])
{
break;
}
} while (++idx < tasksCnt);
(3)、执行发生事件的任务
执行任务函数数组tasksArr[]中发生事件的任务函数,并传递对应的事件。最后在下面
activeTaskID = idx;//活跃任务id
events = (tasksArr[idx])( idx, events );//调用事件处理函数,并返回该任务未处理的事件
activeTaskID = TASK_NO_TASK;
(4)、如果没有发生事件,则进入睡眠
osal_pwrmgr_powerconserve();
5、获取当前正在执行任务的任务id
某些情况下,可能需要获取当前正在执行任务的任务id,OSAL.c提供了一个osal_self()函数获取这个任务id。获取当前任务id其实很简单,只要在执行任务的时候,将任务id赋给全局变量activeTaskID,当调用osal_self()就可以直接这个activeTaskID变量返回。
uint8 osal_self( void )
{
return ( activeTaskID );
}