文档章节

OSAL小记

idaren
 idaren
发布于 2016/06/09 21:06
字数 1784
阅读 204
收藏 7
点赞 0
评论 5

0 预备

  • 端口 :在OSAL中,为每个子程序分配了一个端口号task_id。
  • 事件 :OSAL的运行是依赖事件进行的。每个事件都有对应的task_id,一个task_id可以对应多个事件。这些事件相当于一个个小的子线程。这些事件什么时候运行是由用户编程实现的。一般的,每个事件会有特定的标志位,这个标志位由特定的操作触发,比如在时间性事件中,当到达特定时间时,其标志位便会被置为1。通过查询这些标志位,我们可以决定是否运行某些事件。
HAL_ENTER_CRITICAL_SECTION(x)
HAL_EXIT_CRITICAL_SECTION(x)
  1. 是将定时器4的计数器EA的值保存起来,并置EA的值为0,相当于禁止了定时器4的中断
  2. 是设置EA的值为给定值,这两个函数经常配合使用。

1 Main函数

安装好的zigbee协议栈中有示例程序,路径在Texas Instruments\ZStack-CC2530-2.5.1a\Projects\zstack\Samples\SampleApp\CC2530DB中,打开路径下面的工程就可以在IAR中查看这个示例程序了。

我们将会一眼看到ZMain并顺手打开ZMain.c文件

看到主函数int main( void ),它在执行了一系列的初始化函数后,便会执行osal_start_system(),双击这个函数然后右键跳转到定义,于是我们看到了熟悉的永无止尽的循环

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

当程序开始执行,它就会通过循环osal_run_system()不断的运行这个系统,而这个系统就是被称为OSAL的操作系统。于是我们的重点自然就落到了函数osal_run_system()上,不过在此之前,我们先来看osal初始化时做了些什么。

2 初始化OSAL

回到之前的主函数,在很多初始化函数中会看到osal_init_system(),这个就是osal系统的初始化函数。从osalInitTasks()进入,在这个函数的最后一行,就是SampleApp_Init(),这是示例程序在应用层的初始化函数,我们也可以将自己想要做的初始化操作函数放到这里来。从SampleApp_Init进入,就来到了SampleApp.c文件,这个文件位于

这里是应用层,而大部分的应用功能都写在了这里。

重新回到osalInitTasks()可以看到函数下的每个初始化的操作函数都分配了一个taskID,这个taskID相当于应用程序的端口号。因为其是8位的,因此最多能有255个端口号,其中包含了一些特殊的端口号。此处还申请了一个tasksEvents数组,每个taskID将对应其中的一个tasksEvents[x]

tasksEvents[x]是一个16位的标志位集合,一个事件使用一个标志位,一个tasksEvents[x]下可以有16个事件,当到达事件的发生时间时,会将这个标志位置为1。在示例程序中,在SampleApp.c中自定义了一个名为SAMPLEAPP_SEND_PERIODIC_MSG_EVT的事件,它使用了第一位的标志位,因此其值是0x0001。另外与osalInitTasks()在同一个文件中,有一个函数指针数组tasksArr[],这个数组与端口号一一对应,其作用在下文可以看到。

3 OSAL的Timer链表

osal维护了一个链表,其节点的数据结构如下

typedef struct
{
  void   *next;
  uint16 timeout;
  uint16 event_flag;
  uint8  task_id;
  uint16 reloadTimeout;
} osalTimerRec_t;

我们暂且叫它计划表。计划表中的每个节点包含5个数据,第一个是指针,指向下一个节点,第二个是执行时间,第三个是事件标志位,第四个是端口,第六个是重载时间。通过以下函数

uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint16 timeout_value )

都可以将一个新的事件注册到计划表里面,不同的是后者为reloadTimeout赋了值,其值等于传进去的参数timeout_value,这个区别将在下文说到。

每次进入osal_run_system(),先执行更新时间的操作osalTimeUpdate(),这个函数先读取定时器2的计数(定时器2是专为mac层提供定时服务的),经过计算后将经过的时间(从上一次更新时间到当前的值)的毫秒数赋值给elapsedMSec,单位是毫秒。并判断elapsedMSec是否有值,即超过1ms的话就执行两个更新操作,分别是

 osalClockUpdate( elapsedMSec );
 osalTimerUpdate( elapsedMSec );

第一个函数更新了系统的时间值,确切说是系统的秒数以及系统的毫秒数。第二个函数遍历了链表即计划表。一个个节点遍历,首先会判断当前节点的timeout是否小于elapsedMSec,大于执行

timeout = timeout - elapsedMSec

小于,则说明当前节点代表的事件到了执行时间了,根据节点的task_id和event_flag可以找到在tasksEvents数组下的该节点的事件标志位,并将其置为1。接下来判断reloadTimeout是否大于0,大于0便将这个值赋值给timeout。这样事件标志就可以在下次到期时被触发,reloadTimeout决定了这个事件是周期事件还是仅仅只发生一次。

回到osal_run_system(),在osalTimeUpdate()之后,是Hal_ProcessPoll(),这个函数主要是去查询硬件上是否触发了其他事件。

4 对事件进行处理

通过上文已经可以知道,当我们将一个事件注册到链表计划表里面时,便可以在特定时间将这个事件对应的事件标志置为1,于是通过查询这个标志就可以知道事件是否应该发生了。而所有的事件的标志位其实都在tasksEvents数组中,这么多的事件,系统每次却只处理一个事件,所以都得排着队来处理。系统检索tasksEvents的每个元素是否有值,有则说明这个端口对应的事件至少有一个被触发,然后从tasksArr数组中选择端口对应的函数指针进行调用。比如示例程序中应用层的回调函数指针是SampleApp_ProcessEvent,而函数的主体则是位于应用层SamleApp.c文件中

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )

回调时的传参分别是task_id端口号和events该端口号下的事件触发标志。示例程序在SampleApp_ProcessEvent中,第一步先检查定义的系统事件是否被触发,假如没有,就判断SAMPLEAPP_SEND_PERIODIC_MSG_EVT,一个示例程序定义的事件是否被触发,触发了就执行发送信号的操作。无论是哪种事件,最后都需要手动清零标志位,这就是为什么我们会看到类似这种写法,之所以return是因为一次只处理一个事件

return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);

总结一下,在应用层,可以自定义事件,并把它注册到链表中去,然后可以在回调函数中判断事件是否发生并提供关于事件的处理方法。

© 著作权归作者所有

共有 人打赏支持
idaren
粉丝 1
博文 16
码字总数 14680
作品 0
广州
程序员
加载中

评论(5)

Ho1den
Ho1den
@|-|
idaren
idaren

引用来自“临峰不畏”的评论

点赞,你是第一个写zigbee程序博文的。
谢谢不过应该不是第一个吧
临峰不畏
临峰不畏
点赞,你是第一个写zigbee程序博文的。
踏雪寻阳
踏雪寻阳
6666
daniel098
daniel098
yyuyy
eclipse 控制台输出了三行红字怎么回事?

eclipse控制台输出了下面这三行红字怎么回事? [WARN ][osal ] Could not enumerate processes (1) error=-1073738819 [WARN ][osal ] Could not add counter (null) for query [WARN ][osa......

QGP-ROC
2015/01/03
1K
1
[ZigBee] 16、Zigbee协议栈应用(二)——基于OSAL的无线控制LED闪烁分析(下)

说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c...

史迪奇2号
01/10
0
0
Zigbee网络设备启动—基本问题说明

记录几个问题: *** 1、 有关设备的启动模式选项:(有待完善): 非自动启动模式 HOLDAUTOSTART:HOLDAUTOSTART is a compile option that will surpress ZDApp from starting the device and...

DB_Terrill
2014/07/23
0
0
[ZigBee] 15、Zigbee协议栈应用(一)——Zigbee协议栈介绍及简单例子(长文,OSAL及Zigbee入门知识)

1、Zigbee协议栈简介   协议是一系列的通信标准,通信双方需要按照这一标准进行正常的数据发射和接收。协议栈是协议的具体实现形式,通俗讲协议栈就是协议和用户之间的一个接口,开发人员通...

史迪奇2号
01/01
0
0
Z-Stack中SimpleApp开关结点加入网络流程

(1)开关结点初始化 这时选择的节点类型是终端节点,所以使用f8wEndev.cfg文件,所以在Zglobals.h文件中,我们可以得到下面的定义 #define ZGDEVICETYPEENDDEVICE 0x02 #define DEVICELOGIC...

DB_Terrill
2014/07/24
0
0
Zigbee网络设备启动—主要函数说明

Zigbee网络设备启动—基本问题说明 Zigbee网络设备启动流程—终端(自启动模式) Zigbee网络设备启动—主要函数说明 2010-07-09 20:32:17| 分类: Zigbee | 标签: |举报 |字号大中小 订阅 使用...

DB_Terrill
2014/07/23
0
0
Zigbee通讯之开发篇(基于TI 的Z-Stack)

1.Zigbee协议和Z-Stack Zigbee协议和Z-Stack是什么关系?这可能是初学Zigbee同学想知道的问题。给大家举个例子吧,我们生活中使用的插排是要符合一定的标准的,现在国家标准是GB2099.3-2008...

zhanglianpin
2015/07/14
0
0
基于Android平台的无线传感器网络(ZigBee)监控系统

过去包括将来,从别人开源项目上和博客学到太多,实在是很欣赏开源的精神。这段时间,review了下做过的东西,毕业后不再做这个方向的东西了。陆续也有不少网上或者低届的同学问我讨要论文相关...

Change_Ty
2013/05/30
0
44
介绍TTC CC2541 SDK 蓝牙4.0开发套件

简介 TTC CC2541 SDK 是由我司针对TI的CC2541芯片开发提供的快速开发工具。旨在让开发人员不再需要将大量精力放在蓝牙调试方面,只需将精力放在对CC2541芯片功能的应用开发上。 TTC CC2541 S...

昇润科技
05/21
0
0
蓝牙nrf52832的架构和开发

相比TI的CC254X、DIALOG的DA1458X,nordic推出的nrf51822和nrf52832在架构和开发商都有自己独特的地方。这几颗产品都是蓝牙低功耗芯片。DA1458X使用OTP硬件架构,功耗低,成本也低,但软件开...

yueqian_scut
2017/03/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Cloud Gateway 接口文档聚合实现

在微服务架构下,通常每个微服务都会使用Swagger来管理我们的接口文档,当微服务越来越多,接口查找管理无形中要浪费我们不少时间,毕竟懒是程序员的美德。 由于swagger2暂时不支持webflux 走...

冷冷gg
31分钟前
13
0
流利阅读笔记30-20180719待学习

1.今日导读 2.带着问题听讲解 3.新闻正文(中英文对照) 4.重点词汇 5.拓展内容

aibinxiao
34分钟前
1
0
OSChina 周五乱弹 —— 我们是食物链的最底层

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @温家成 :分享谢安琪的单曲《姿色份子》 《姿色份子》- 谢安琪 手机党少年们想听歌,请使劲儿戳(这里) @贪吃飒:最近p2p怎么了、半个月爆了...

小小编辑
47分钟前
6
1
Android Studio 3.0 之后打包apk出现应用未安装问题

1、废话 出现这个问题的原因,并不是只有一个,而是有多个原因,不懂的估计会被搞得一头雾水,下面我列举的是我遇到的几种问题和网友遇到的几种问题,但不一定是全部,也有可能有些莫名其妙的...

她叫我小渝
今天
0
0
前端基础

1. get请求传参长度的误区 误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。 实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是...

wenxingjun
今天
0
0
拦截SQLSERVER的SSL加密通道替换传输过程中的用户名密码实现运维审计(一)

工作准备 •一台SQLSERVER 2005/SQLSERVER 2008服务 •SQLSERVER jdbc驱动程序 •Java开发环境eclipse + jdk1.8 •java反编译工具JD-Core 反编译JDBC分析SQLSERVER客户端与服务器通信原理 SQ...

紅顏為君笑
今天
9
0
jQuery零基础入门——(六)修改DOM结构

《jQuery零基础入门》系列博文是在廖雪峰老师的博文基础上,可能补充了个人的理解和日常遇到的点,用我的理解表述出来,主干出处来自廖雪峰老师的技术分享。 在《零基础入门JavaScript》的时...

JandenMa
今天
0
0
linux mint 1.9 qq 安装

转: https://www.jianshu.com/p/cdc3d03c144d 1. 下载 qq 轻聊版,可在百度搜索后下载 QQ7.9Light.exe 2. 去wine的官网(https://wiki.winehq.org/Ubuntu) 安装 wine . 提醒网页可以切换成中...

Canaan_
今天
0
0
PHP后台运行命令并管理运行程序

php后台运行命令并管理后台运行程序 class ProcessModel{ private $pid; private $command; private $resultToFile = ''; public function __construct($cl=false){......

colin_86
今天
1
0
数据结构与算法4

在此程序中,HighArray类中的find()方法用数据项的值作为参数传递,它的返回值决定是否找到此数据项。 insert()方法向数组下一个空位置放置一个新的数据项。一个名为nElems的字段跟踪记录着...

沉迷于编程的小菜菜
今天
1
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部