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

2015-9-21 16:09 6613 18 23 分类: MCU/ 嵌入式 文集: CC254x蓝牙BLE4.0协议栈学习笔记

接下来我们再看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语言的基本不够瓷实,说得也很大白话。之所以敢这么大胆贴出来,也是请大家多批评指正,让我能得到提高。

PARTNER CONTENT

文章评论5条评论)

登录后参与讨论

用户377235 2014-9-15 10:41

讲的不错

用户377235 2014-7-16 09:20

讲的很不错呀

用户377235 2014-4-23 21:08

可以借鉴下,最经正好看这个。

飞言走笔 2014-3-24 14:02

主要是理解得太肤浅了,只能是理解多少记录多少了,也请大侠多批评指正啊:)

用户377235 2014-3-24 11:21

讲地太肤浅
相关推荐阅读
飞言走笔 2017-01-06 21:56
2017,新的博客旅程
EDNChina 改版终于成功了!祝贺! 2017年,开始新的旅程~ ...
飞言走笔 2016-06-01 10:17
【博客大赛】《白鹿原》读后
《白鹿原》这本书已经买了很久,多次以来,都是只翻看几页,顶多几章就放下了,觉得这是一个大部头,得有足够的时间才行。前几天陈忠实先生去世的消息传来,让我很震惊和惭愧。 一口气读完这本书,畅快淋漓,又意...
飞言走笔 2016-03-26 16:42
【博客大赛】《毛斯朝》读后
这本书最早是在凤凰卫视曾子墨主持的一期关于沈志华先生的《世纪大讲堂》节目中知晓的。但是一直拖到今天才读完。 说实话,书的主要内容与当前官方的宣传口径有很多不一致的地方,而沈先生作为中国掌握苏联档...
飞言走笔 2016-03-08 13:46
【博客大赛】蓝牙4.0低功耗技术及其认证要求
详见附件 ...
飞言走笔 2016-02-02 14:20
【转】蓝牙4.0协议官方手册(一)——通用属性配置文件
转自:http://blog.csdn.net/jinzhichaoshuiping/article/details/43370009 通用属性配置文件 (GATT)——该说明书定义了通用属性配置...
飞言走笔 2016-01-31 23:24
【博客大赛】脑洞大开、三观重塑——《人类简史》读后
终于读完了《人类简史》,没有把这本书拖到二月份,这也是2016年读完的第一本书。之前也有所耳闻,但是没有太在意,倒是罗胖子的跨年演讲上偶然提到,不知怎么就勾起了阅读此书的欲望。 本文的标题用了“脑洞...
EE直播间
更多
我要评论
5
18
关闭 站长推荐上一条 /3 下一条