TI蓝牙BLE 协议栈代码学习——OSAL(下)

接下来我们再看main()函数中另一个跟OSAL相关的函数——osal_start_system(),也位于OSAL.c中。

void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop
#endif
  {
    osal_run_system();
  }
}

一看这是个死循环,相当于单片机程序最后一行 while(1); 。这个函数最主要的部分还是 osal_run_system() ,找到它,也在 OSAL.c 中。

void osal_run_system( void )
{
  uint8 idx = 0;
 
#ifndef HAL_BOARD_CC2538
  osalTimeUpdate();
#endif
 
  Hal_ProcessPoll();
 
  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);
 
  if (idx < tasksCnt)
  {
    uint16 events;
    halIntState_t intState;
 
    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState);
 
    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );
    activeTaskID = TASK_NO_TASK;
 
    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
#if defined( POWER_SAVING )
  else  // Complete pass through all task events with no activity?
  {
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif
 
  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  {
    osal_task_yield();
  }
#endif
}

去掉条件编译部分,最核心的是一个 do-while 循环,一个 if 判断。

do-while循环:

do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);

这个循环就是完成判断当前的事件表中有没有事件发生,如果有就跳出来,执行下面的代码。

if (idx < tasksCnt)
  {
    uint16 events;
    halIntState_t intState;
 
    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState);
 
    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );
    activeTaskID = TASK_NO_TASK;
 
    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }

这部分代码应该是OSAL最核心最精髓的部分了。前面的循环中已经确定有事件发生了。HAL_ENTER_CRITICAL_SECTION(intState);HAL_EXIT_CRITICAL_SECTION(intState);分别是关中断和使能中断,以防止在执行代码时被中断打断。将事件表tasksEvents[]中的事件赋给events,然后该事件清零。接下来events = (tasksArr[idx])( idx, events );就是去处理事件了,这里的tasksArr[]数组非常重要。下面的tasksEvents[idx] |= events;就是把没有响应的事件再放回到tasksEvents[]中。

我们来看看这个非常重要的数组taskArr[],它被定义在OSAL_KeyFobDemo.c中。

// The order in this table must be identical to the task initialization calls below in osalInitTask.
const pTaskEventHandlerFn tasksArr[] =
{
  LL_ProcessEvent,                                          // task 0
  Hal_ProcessEvent,                                       // task 1
  HCI_ProcessEvent,                                        // task 2
#if defined ( OSAL_CBTIMER_NUM_TASKS )
  OSAL_CBTIMER_PROCESS_EVENT( osal_CbTimerProcessEvent ),     // task 3
#endif
  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
  KeyFobApp_ProcessEvent                                      // task 11
};

数组内的成员看起来很面熟。最上面一行的注释也写得很清楚,表中的顺序要和osalInitTask()中定义的一致。再来看这个数组的类型,是pTaskEventHandlerFn,这是个什么东西?pTaskEventHandlerFn不是东西,是

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

这个定义是一个函数指针,看起着很头疼,很蛋疼。如果换一下:

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

这样或许理解起来要好一些。拿KeyFobApp_ProcessEvent的声明来看,uint16 KeyFobApp_ProcessEvent( uint8 task_id, uint16 events ),这是符合pTaskEventHandlerFn的格式的,函数名就是指针,函数的地址。

tasksArr[]是一个函数指针数组,里面保存了所有事件处理函数的地址。当有事件发生时,就执行events = (tasksArr[idx])( idx, events );一句,就是对应的tasksArr[]里相应的那个事件的处理函数。

再看另一个数组,tasksEvents[]tasksEvents[]声明为全局变量,是在osalInitTasks()中定义和初始化的:

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);

osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

这个数组的大小跟事件的数量是一致的,而且被osal_memset()初始化为0.

这样OSAL的运行机理基本清晰了,就是在do-while()循环中判断tasksEvents[]中哪个事件非0,即事件被触发了;然后在if中把该事件清0,执行tasksArr[]中定义好的事件处理函数,然后把没有执行的事件再放回到tasksEvents[]中。这也是为什么在osalInitTask()中进行初始化的时候,初始化的顺序要和tasksArr[]一致。

以上是我对 OSAL 的理解,因为 C 语言的基本不够瓷实,说得也很大白话。之所以敢这么大胆贴出来,也是请大家多批评指正,让我能得到提高。
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值