CC254x--OSAL

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()”接口,否则一直循环定时操作。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CLR 与 C++的常用类型转换笔记

1. System::String 转换到 const wchar_t* const wchar_t* ToUnmanagedUnicode( System::String^ str ){ pin_ptr<const WCHAR> nativeString1 PtrToStringChars( str ); return (const wchar_t*)nativeString1;} 2. const wchar_t* / const char* 转换到 System::Strin…

mysql跨节点join——federated引擎

一、 什么是federated引擎 mysql中的federated类似于oracle中的dblink。 federated是一个专门针对远程数据库的实现&#xff0c;一般情况下在本地数据库中建表会在数据库目录中生成相对应的表定义文件&#xff0c;并同时生成相对应的数据文件。 [图] 但是通过federated引擎创建…

【阅读SpringMVC源码】手把手带你debug验证SpringMVC执行流程

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 ✿ 阅读源码思路&#xff1a; 先跳过非重点&#xff0c;深入每个方法&#xff0c;进入的时候可以把整个可以理一下方法的执…

Zabbix监控(十六):分布式监控-Zabbix Proxy

说明&#xff1a;Zabbix支持分布式监控&#xff0c;利用Proxy代理功能&#xff0c;在其他网络环境中部署代理服务器&#xff0c;将监控数据汇总到Zabbix主服务器&#xff0c;实现多网络的分布式监控&#xff0c;集中监控。1、分布式监控原理Zabbix proxy和Zabbix server一样&am…

CC254x--BLE

BLE协议栈 BLE体系结构&#xff0c;着重了解GAP和GATT。 PHY物理层在2.4GHz的ISM频段中跳频识别。LL连接层&#xff1a;控制设备的状态。设备可能有5中状态&#xff1a;就绪standby&#xff0c;广播advertising&#xff0c;搜索scanning&#xff0c;初始化initiating和连接con…

DW 在onload运行recordset find.html时 发生了以下javascript错误

这两天打开Dreamweaver CS5&#xff0c;总是弹出一个错误&#xff0c;写着&#xff1a; 在onLoad运行RecordsetFind.htm时&#xff0c;发生了以下JavaScript错误&#xff1a; 在文件“RecordsetFind”中&#xff1a; findRsisnotdefined 在关闭Dreamweaver的时候也会弹出一个类…

Azure Container App(一)应用介绍

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 一&#xff0c;引言 容器技术正日益成为打包、部署应用程序的第一选择。Azure 提供了许多使用容器的选项。例如&#xff0…

CC254x--API

CC2541常用API 连接 定义广播数据 GAPRole_SetParameter(GAPROLE_ADVERT_DATA,…); 自定义扫描响应数据 GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA,…); 密码管理回调 ProcessPasscodeCB(); 状态管理回调 peripheralStateNotificationCB(); 通信控制 添加GATT服务 GATTServ…

mysql 分区信息查看

select partition_name part,partition_expression expr,partition_description descr,table_rows from INFORMATION_SCHEMA.PARTITIONS where TABLE_SCHEMASCHEMA() AND TABLE_NAMEmx_domain//查看分区信息 CREATE TABLE mx_domain (id int(10) NOT NULL AUTO_INCREMENT,name…

怎样配置键盘最方便,以及一些设计的思考

使用Emacs的人&#xff0c;如果肯折腾&#xff0c;肯定有重新映射键盘的经历。我原来经常看到的是把Ctrl和Capslock交换&#xff0c;但是我感觉没什么道理&#xff0c;因为Ctrl已经用的很熟练了&#xff0c;换了反而不方便&#xff0c;而且对其他程序影响太大。那么我们就要使用…

profile、服务、特征、属性之间的关系

一个profile有很多的服务&#xff0c;一个服务又有很多的特性&#xff0c;一个特性中又有几种属性条目组成。 profile&#xff08;数据配置文件&#xff09; 一个profile文件可以包含一个或者多个服务&#xff0c;一个profile文件包含需要的服务的信息或者为对等设备如何交互的…

面试突击32:为什么创建线程池一定要用ThreadPoolExecutor?

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 在 Java 语言中&#xff0c;并发编程都是依靠线程池完成的&#xff0c;而线程池的创建方式又有很多&#xff0c;但从大的分类…

Bootstrap datepicker 在弹出窗体modal中不工作

解决办法 在 show 方法后面 添加 下面一段代码 $(#modalCard).modal(show);—例子 打开 弹出窗体 //$(#modalCard).modal(hide); $(#modalCard).on(shown.bs.modal, function () { //$(.input-group.date).datetimepicker({ $(#dpReceiveDate).datetimepicker({ format: "…

学习Samba基础命令详解之大话西游01

服务名:smb配置目录:/etc/sabma/主配置文件:/etc/sabma/smb.conf# Global Settings 17行workgroup语法 workgtoup <工作组群>; 预设 workgroup MYGROUP 说明 设定 Samba Server 的工作组 例 workgroup workgroup 和WIN2000S设为一个组&#xff0c;可在网上邻居可中看到…

实例讲解getopt()函数的使用

[cpp] view plaincopy #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { extern char *optarg;//保存选项的参数 extern int optind, opterr, optopt; int ch; printf("\n\n"); pri…

机器学习实战 | SKLearn最全应用指南

Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/course/detail/35475 作者&#xff1a;韩信子ShowMeAI 教程地址&#xff1a;http://www.showmeai.tech/tutorials/41 本文地址&#xff1a;http…

windows 64位 安装mvn提示 不是内部或外部命令

在安装mvn的过程中当在mvn的目录下去执行mvn命令的时候是可以正常执行的&#xff0c;当设置好环境变量后执行后发现提示mvn不是内部命令。 原因是设置的MAVEN_HOME变量未被Path解析&#xff0c;解决办法是 直接把path中的%MAVEN_HOME%\bin 换成MAVEN_HOME的绝对路径&#xff0c…

Scheme语言入门

2019独角兽企业重金招聘Python工程师标准>>> Scheme语言入门 最早听说 LISP&#xff0c;是 Stallman 的 GNU Emacs 中将 LISP 作为嵌入语言&#xff0c;定制和增强 Emacs。GNU Emacs 是一个文本编辑器&#xff0c;文本就是一种符号&#xff0c;而 Lisp 正好就是针对…

题目四 艺术品

Dr.Kong设计了一件艺术品&#xff0c;该艺术品由N个构件堆叠而成&#xff0c;N个构件从高到低按层编号依次为1&#xff0c;2&#xff0c;……,N。艺术品展出后&#xff0c;引起了强烈的反映。Dr.Kong观察到&#xff0c;人们尤其对作品的高端部分评价甚多。 狂热的Dr.Kong一激动…