OSAL之任务管理

转载请注明出处,尊重原创

总论

OSAL操作系统最多可以支持16个任务,由任务功耗管理PwrMgr_task_state变量可知,而OSAL每个任务最多只能支持16个事件处理,理论上最大可以执行256个事件处理。对于一些运算能力不强,内存空间不大的处理器最适合不过了。OSAL实际上不是一个真正意义上的操作系统,在加上它最多只能处理16个任务,所以OSAL没有像其他操作系统一样有复杂的任务调度算法,每个任务都是有序轮流执行。OSAL的任务管理代码主要在OSAL.c中。

1、定义任务事件处理函数的格式

最常用的任务函数格式是:有几个参数以及返回值。OSAL中任务事件处理函数如下:

typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );

OSAL中定义任务函数带两个参数的,一个是任务的id,另一个是要传递的事件。

2、定义任务函数数组tasksArr[],以蓝牙工程为例。

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为函数名。

3、初始化OSAL系统

在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 */
}

4、启动系统

在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 );
}

你可能感兴趣的:(OSAL)