TI蓝牙BLE 协议栈代码学习——OSAL(下)
2015-09-06 15:58
441 查看
接下来我们再看main()函数中另一个跟OSAL相关的函数——osal_start_system(),也位于OSAL.c中。
一看这是个死循环,相当于单片机程序最后一行while(1);。这个函数最主要的部分还是osal_run_system(),找到它,也在OSAL.c中。
去掉条件编译部分,最核心的是一个do-while循环,一个if判断。
do-while循环:
这个循环就是完成判断当前的事件表中有没有事件发生,如果有就跳出来,执行下面的代码。
这部分代码应该是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中。
数组内的成员看起来很面熟。最上面一行的注释也写得很清楚,表中的顺序要和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语言的基本不够瓷实,说得也很大白话。之所以敢这么大胆贴出来,也是请大家多批评指正,让我能得到提高。
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语言的基本不够瓷实,说得也很大白话。之所以敢这么大胆贴出来,也是请大家多批评指正,让我能得到提高。
相关文章推荐
- java鼠标与键盘事件监听
- wxpython基本控件
- 感知机学习算法Java实现
- java事件演示
- PHP面向对象继承(二)
- Caused by: javax.el.PropertyNotFoundException: Property 'title' not found on type java.lang.String
- Caused by: javax.el.PropertyNotFoundException: Property 'title' not found on type java.lang.String
- TI蓝牙BLE 协议栈代码学习——OSAL(上)
- Python Thread related
- Java实现Stack类
- Java实现Bag类
- qt操作数据库
- C# 委托应用总结
- PHP 每天用一点
- Spring AOP Example Tutorial – Aspect, Advice, Pointcut, JoinPoint, Annotations, XML Configuration
- java常用代码
- 纯代码适配iphone屏幕尺寸
- 详解C语言中的ttyname()函数和isatty()函数的用法
- 关联规则Java实现
- python SyntaxError: Non-ASCII character '\xd5' in file