OSAL运行原理

蓝牙协议栈PROFILE、所有的应用程序、驱动等都是围绕着OSAL组织运行的。OSAL(Operating System Abstraction Layer)操作系统抽象层,它不是一个真正的操作系统(它没有 Context Switch 上下文切换功能),但它巧妙地组织各任务,支持任务优先级,任务之间可以通过事件和消息来通信,为任务提供软定时器和动态内存分配。要避免的陷阱是,应用任务的单个函数运行时间不能太长 (如操作大批量数据的 Flash 写),否则它无法及时调度高优先级的 LL(Link Layer)任务而导致蓝牙通信中断。

OSAL 为每一个任务函数分配了一个 16 位的EVENT 事件,每一位代表一个事件,其中最高位代表的事件为 SYS_EVENT_MSG,这个事件被 OSAL 系统保留,其他的 15 位可以由用户定义,OSAL 在主循环里运行每次都会检查每个任务函数的是否有事件发生(事件置位),如果有事件发生,将通过 taskid 来调用发生事件的任务函数,并将发生的事件传递到该函数中去,由任务函数处理对应的事件。

为什么要将返回值设置到tasksEvents中,就是因为其本质是一个单任务循环,如果某个子任务时间执行过长,会影响更高优先级的任务的响应变慢,影响整体性能。因此如果一个任务执行比较长,宜进行分割,在返回值那里设置继续处理事件,然后返回大循环,看看有没有更高优先级的任务需要执行。

事件和任务对应关系

事件和任务的事件处理函数是如何关联起来的呢?
建立一个事件表,保存各个任务对应的事件。【uint16 *tasksEvents;】。tasksEvents为指向一个内存分配的事件数组的指针。比如:tasksEvents[0]为第0个任务的事件变量(short int)。

建立另一个函数表,保存各个任务事件处理函数的地址。【const pTaskEventHandlerFn tasksArr[] =】将会根据tasksArr[x]去执行对应的回调函数。

然后将这两张表建立某种对应关系,【void osalInitTasks( void ),初始化task_id和tasksArr[]的函数指针对应关系】【uint8 osal_set_event( uint8 task_id, uint16 event_flag ),设置事件发生】,蓝牙协议栈也会调用并设置任务,具体的实现已经被封装起来了。

当某一事件发生时则查找函数表找到对应的事件处理函数即可。【events = (tasksArr[idx])( idx, events );,调用idx变好的函数指针回调函数】

//定义了一个函数指针
/** Event handler function prototype*/
typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );//这是一个数组,该数组的每一项都是一个函数指针,指向了事件处理函数
// The order in this table must be identical to the task initialization calls below in osalInitTask.
const pTaskEventHandlerFn tasksArr[] =
{LL_ProcessEvent,                                                  // task 0Hal_ProcessEvent,                                                 // task 1HCI_ProcessEvent,                                                 // task 2
#if defined ( OSAL_CBTIMER_NUM_TASKS )OSAL_CBTIMER_PROCESS_EVENT( osal_CbTimerProcessEvent ),           // task 3
#endifL2CAP_ProcessEvent,                                               // task 4GAP_ProcessEvent,                                                 // task 5GATT_ProcessEvent,                                                // task 6SM_ProcessEvent,                                                  // task 7GAPRole_ProcessEvent,                                             // task 8GAPBondMgr_ProcessEvent,                                          // task 9GATTServApp_ProcessEvent,                                         // task 10SimpleBLEPeripheral_ProcessEvent                                  // task 11
};//该变量保存了任务的总个数
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );//这是一个指针,指向了事件表的首地址,事件表实际上是一个内存分配的数组
uint16 *tasksEvents;

OSAL是一种事件驱动的轮询式操作系统。事件驱动是指发生事件后采取相应的事件处理方法,轮询指的是不断地查询是否有事件发生。

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

在系统初始化时,将所有任务的事件初始化为0。通过taskEvents[idx]是否为0来判断是否有事件发生【if (tasksEvents[idx])】。如果有事件发生,则查找函数对应的事件处理函数对事件进行处理【events = (tasksArr[idx])( idx, events );】。

事件表使用数组来实现,数组的每一项对应任务的事件,每一位表示一个事件;函数表使用函数指针数据来实现,数组的每一项是一个函数指针,指向了事件处理函数。

OSAL提供的API

总体而言,大致可以分为10个方面:
1.消息管理
2.任务同步
3.时间管理
4.中断管理
5.任务管理
6.内存管理
7.电源管理
8.非易失性闪存管理
9.时钟管理

10.其他常用

事件

OSAL为每个任务函数分配了一个16位的事件变量,每一位代表一个事件。最高位0x8000保留为系统事件SYS_ENENT_MSG。其余的15位留给用户自定义需要的事件。通常事件由定时器启动,比如2s后我要点亮LED1,这就需要发送一个点亮LED1的事件,然后等待,当2s后接收到点亮LED1事件的时候调用HAL层开关LED1的函数开启LED1。

消息

MAG是比EVENT事件更具体并且可以携带数据的一种通信方式。而且MSG的标记是按数值,而不是按位。比如0x02和0x03是两个不同的消息,但是对于事件0x03则是0x01和0x02事件的组合。MSG收发使用osal_mag_send()和osal_msg_receive();当调用osal_msg_send()发送一个MSG的同时会在EVENT列表中触发一个message ready event。为了降低消息传递的开支,通常传递指向消息的指针。

消息与事件的区别

讲解消息队列之前需要讲解一下消息与事件的区别。

事件是驱动任务去执行某些操作的条件,当系统中产生了一个事件,OSAL 将这个事件传递给相应的任务后,任务才能执行一个相应的操作(调用事件处理函数去处理)。

通常某些事件发生时,又伴随着一些附加信息的产生,例如:主机 GATT 接收到数据后,会产生 GATT_MSG_EVENT 消息,但是任务的事件处理函数在处理这个事件的时候,还需要得到所收到的数据。
因此,这就需要将事件和数据封装成一个消息,将消息发送到消息队列osal_msg_send,然后在事件处理函数中就可以使用 osal_msg_receive 从消息队列中得到该消息。这里需要说明一点,消息一般用于不同任务函数之间的数据传递,因为不同的任务具有各自的堆栈空间。在同一任务中使用全局函数或者用户事件完全能够胜任。当然消息也可以在同一个任务中传递数据。
EVENT用于同一任务函数传递命令,而MSG则用于不同的任务函数传递命令数据。

这里需要说明一点,消息一般用于不同任务函数之间的数据传递,因为不同的任务具有各自的堆栈空间。在同一任务中使用全局函数或者用户事件完全能够胜任。当然消息也可以在同一个任务中传递数据。

事件处理

消息处理

OSAL 维护了一个消息队列,每一个消息都会被放到这个消息队列中去,当任务接收到事件后,可以从消息队列中获取属于自己的消息,然后调用消息处理函数进行相应的处理即可。

Osal_msg_allocate()为消息分配缓存空间,分配之后,可以填充消息,然后通过osal_msg_send( ) 将消息发送出去,然后任务函数中通过 osal_msg_reveive()函数接收属于 自己的消息,并处理,最后调用osal_msg_deallocate() 函数销毁由Osal_msg_allocate()分配的内存空间。

下面是按键的消息处理过程,按键的消息最终将会发送到第一次注册的任务中去。

这里需要说明一点,消息一般用于不同任务函数之间的数据传递,因为不同的任务具有各自的堆栈空间。在同一任务中使用全局函数或者用户事件完全能够胜任。当然消息也可以在同一个任务中传递数据。

事实上,它只是发了一个KEY_CHANGE事件,而键值是以MSG消息的形式发到系统的消息队列,而该消息也会带上目标taskId的标识。

如下代码可以从消息队列中得到一个消息:pMsg = osal_msg_receive( registeredKeysTaskID))

时间管理

时间管理API用于开启和关闭定时器,定时时间一般为毫秒级定时。

osal_start_reload_timer()和osal_start_timerEx()功能一样,但是本接口还多了一个功能:就是定时时间到后相应事件被执行,并重新加载定时器,也就是又重新设置了定时器,继续进行定时工作,除非调“osal_stop_timerEx()”接口,否则一直循环定时操作。

CC254x--OSAL相关推荐

  1. CC2540/CC2541/CC254x之OSAL操作系统抽象层

    测试环境 协议栈版本:BLE-CC254x-1.4.0 开发环境IAR版本:IAR 8.20 硬件设备:CC2540/CC2541开发板 示例测试Demo工程:simpleBLEPeripheral工 ...

  2. CC254x到CC2640

    介绍 TI-RTOS是CC26xx设备上蓝牙低功耗项目的新操作环境.该软件是一个多线程环境,其中,协议栈.应用程序及其配置文件存在于不同的线程上.TI-RTOS具有与OSAL相似的功能,但实现它们的机 ...

  3. TI CC254x BLE教程 4

    TI的CC254x芯片 1. SoC 2. RF收发器+8051MCU 128/256KB Code空间. 3. Master或者Slave 4. 可编程flash 5. 8KB SRAM 6. 全软 ...

  4. CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)

    参考学习大神博客: http://blog.csdn.net/feilusia/article/details/51083953 : http://blog.csdn.net/xiaoleiacmer ...

  5. 5、CC2541芯片中级教程-OSAL操作系统(PWM+看门狗)

    本文根据一周CC2541笔记汇总得来-- 适合概览和知识快速索引-- 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...

  6. Zigbee协议栈中OSAL的运行机理

    OSAL的运行机理 事件表 函数表 使用查表法来取得事件所对应函数 taskCnt  任务总数 taskEvents 指向事件表首地址的指针 taskArr 事件处理函数数组,每一项都是一个函数指针 ...

  7. 蓝牙BLE(协议栈、OSAL、蓝牙APP工具)

    目录 蓝牙配对和绑定 蓝牙4.0 BLE 信道(RF Channel) BLE协议栈分层 PHY层(Physical layer 物理层) LL层(Link Layer 链路层) HCI层(Host ...

  8. IAR平台移植TI OSAL到STC8A8K64S4A12单片机中

    玩过TI 的ZigBee或者BLE的人,都会接触到OSAL.OSAL是什么?OSAL英文全称:operating system abstraction layer(操作系统抽象层).基于OSAL的调度 ...

  9. 蓝牙协议栈中的 OSAL

    蓝牙协议栈里的操作系统叫做 OSAL(操作系统抽象层).它并非一个真正意义上的操作系统,它只是实现了操作系统的一些功能,如任务切换.内存管理. OSAL 产生的根源:基于蓝牙协议栈开发的产品,实际上是 ...

  10. BLE协议栈学习2——OSAL

    OSAL简介 BLE 协议栈包含了 BLE 协议所规定的基本功能,这些功能是以函数的形式实现的,为了便于管理 这些函数集,BLE 协议栈内加入了实时操作系统(并非真正意义上的操作系统),称为 OSAL ...

最新文章

  1. VTK:参数化超环形用法实战
  2. FFmpeg 硬件加速方案概览 (上)
  3. Java 8中最快的垃圾收集器是什么?
  4. CAReplicatorLayer复制Layer和动画, 实现神奇的效果
  5. html怎么实现单个li效果,基于DIV+ul+li实现的表格(多示例)
  6. 站点简介(欢迎大家踊跃参与本站站点的建设,谢谢)
  7. pyecharts折线图坐标轴范围设置_多层折线图,一对一展现数据趋势,图表就应如此美丽...
  8. Java知多少(51)finally
  9. VTK点云数据如何导入MeshLab
  10. 电信天翼网关路由器的超级密码
  11. 二元二次方程例题_二元二次方程组 解法 例题精编版
  12. phython学习笔记1
  13. 产品经理干久了,有哪些后遗症?
  14. shell 判断字符串长度
  15. 拍照基础方法及构图技巧
  16. Jmeter基础系列4-创建一个HTTP请求实例
  17. 客户贷后还款提醒优化项目
  18. 愿编程不再乱码(含Qt)-根因深究
  19. 充电池中热敏电阻作用
  20. 研究型论文_用于优化入侵检测类不平衡数据集中SMOTE比率的机器学习方法(英文论文)

热门文章

  1. Fix an “Unapproved Caller” SecurityAgent Message in Mac OS X
  2. Android处理ListView中的Item中的Button按钮不能点击的问题
  3. 2、Eternal框架-svn_有更新!
  4. 医疗大数据处理流程_我们需要数据来大规模改善医疗流程
  5. flink 检查点_Flink检查点和恢复
  6. 城市轨道交通运营票务管理论文_城市轨道交通运营管理专业就业前景怎么样?中职优选告诉你...
  7. 敏捷数据科学pdf_敏捷数据科学数据科学可以并且应该是敏捷的
  8. 渐进式web应用程序_渐进式Web应用程序与加速的移动页面:有什么区别,哪种最适合您?
  9. QueryList 配置curl参数 的文档位置 QueryList抓取https 终于找到了
  10. 基于相关性分析系统性能瓶颈