OSAL工作机制分析
协议栈代码main()函数分析
ZMain文件->ZMain.c->main() 在这里我们重点了解osal_start_system()函数
int main( void )
{
//关闭所有终端
osal_int_disable( INTS_ALL );
//硬件板子的初始化,比如led的初始化
HAL_BOARD_INIT();
//监测电压,确保电压能使CC2530运行
zmain_vdd_check();
// 初始化板子的I/O
InitBoard( OB_COLD );
// 初始化硬件驱动
HalDriverInit();
// 初始化NV系统
osal_nv_init( NULL );
// MAC的初始化
ZMacInit();
// 扩展地址的初始化
zmain_ext_addr();
// 初始化NV条目
zgInit();
#ifndef NONWK
//AF层的初始化,在禁止NONWK的时候需要初始化AF层
afInit();
#endif
//初始化操作系统
//维护事件表的函数在这个函数里边-》osalInitTasks();
osal_init_system();
// 开中断
osal_int_enable( INTS_ALL );
// 板级终初始化
InitBoard( OB_READY );
// 设备信息显示
zmain_dev_info();
//如果定义了LCD,那么执行LCD初始化
#ifdef LCD_SUPPORTED
zmain_lcd_init();
#endif
#ifdef WDT_IN_PM1
//如果定义了看门狗,那么执行使能看门狗函数
WatchDogEnable( WDTIMX );
#endif
//系统执行的入口,注意正常情况是不会运行到此函数的下一句,
//也就是return语句的,因为进入此函数以后会一直在里面循环执行任务,并不会跳出次循环。
osal_start_system();
return 0;
} // main()
分析osal_start_system()函数,通过go to的方式,跳转到函数中去
void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
for(;;) // Forever Loop //进入for死循环,相当于while(1);
#endif
{
osal_run_system(); //到这里进入我们osal系统,
}
}
OSAL的运行机制
ZigBee 协议栈仅仅是 ZigBee 协议的具体实现。OSAL 就是一种支持多任务运行的系统资源分配机制。在 ZigBee 协议栈中,OSAL 负责调度各个任务的运行,如果有事件发生了,则会调用相应的事件处理函数进行处理。
那么,事件和任务的事件处理函数是如何联系起来的呢?
ZigBee 中采用的方法是:建立一个事件表,保存各个任务的对应的事件,建立另一个函数表,保存各个任务的事件处理函数的地址,然后将这两张表建立某种对应关系,当某一事件发生时则查找函数表找到对应的事件处理函数即可。
分析osal_run_system()函数,通过go to的方式,跳转到函数中去,分析我们OSAL的运行机制。
void osal_run_system( void )
{
uint8 idx = 0;
osalTimeUpdate();
Hal_ProcessPoll();
//查询任务事件表是否有事件发生,从高优先级的任务中开始查询
// const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] ); 初始化任务数,并且进行初始化
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); /* 进入临界区---保存EA状态然后置EA = 0 */
//将发生任务的事件取出来放到events变量中,并将tasksEvents[idx]清零
// uint16 *tasksEvents; 指向事件表的首地址,
//协议栈中的事件采用独热码的方式,
// ZigBee 协议栈使用一个 unsigned short 型的变量,因为 unsigned short 类型占两个字节,
// 即 16 个二进制位,因此,可以使用每个二进制位表示一个事件,我们来看下协议栈定义
// 的系统事件SYS_EVENT_MS G,十六进制:0x8000,二进制0b100000000000000 0。
//它用的就是高位来表示该事件:在系统初始化时,所有任务的事件初始化为 0,
events = tasksEvents[idx];
tasksEvents[idx] = 0; // Clear the Events for this task.
HAL_EXIT_CRITICAL_SECTION(intState); /* 退出临界区---恢复EA状态 */
activeTaskID = idx;
// 声明函数指针
// typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );
// 函数指针数组,指向任务事件处理函数
// const pTaskEventHandlerFn tasksArr[] = {}
// 在任务事件处理函数中通过eturn (events ^ SYS_EVENT_MSG);返回任务中未处理的事件
events = (tasksArr[idx])( idx, events );
activeTaskID = TASK_NO_TASK;
HAL_ENTER_CRITICAL_SECTION(intState); /* 进入临界区---保存EA状态然后置EA = 0 */
// 将未处理的任务中的事件重新写回到事件表中
tasksEvents[idx] |= events; // Add back unprocessed events to the current task.
HAL_EXIT_CRITICAL_SECTION(intState); /* 退出临界区---恢复EA状态 */
}
#if defined( POWER_SAVING ) //进入低功耗模式
else // Complete pass through all task events with no activity?
{
osal_pwrmgr_powerconserve(); // Put the processor/system into sleep
}
#endif
}
事件表的分配空间:
查看main()函数中的系统初始化函数osal_init_system();——> 任务初始化函数osalInitTasks();
void osalInitTasks( void )
{
uint8 taskID = 0;
//给事件表分配空间通过osal_mem_alloc函数,
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
//使用osal_memset函数给事件表全部初始化为0
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
macTaskInit( taskID++ );
nwk_init( taskID++ );
Hal_Init( taskID++ );
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_Init( taskID++ );
#endif
ZDApp_Init( taskID++ );
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_Init( taskID++ );
#endif
SampleApp_Init( taskID ); //用户自己添加的任务初始化函数
}
任务事件处理函数分配空间:
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_ProcessEvent,
#endif
ZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_event_loop,
#endif
SampleApp_ProcessEvent //用户自己的任务中的事件处理函数
};
注意:任务初始化函数中每个任务的初始化函数必须与任务事件处理数组中的任务事件处理函数一一对应。
在 ZigBee 协议栈中,有三个变量至关重要:
tasksCnt—该变量保存了任务的总个数。
该变量的声明为:uint8 tasksCnt,其中 uint8 的定义为:typedef unsigned char uint8
tasksEvents—这是一个指针,指向了事件表的首地址。
该变量的声明为:uint16 *tasksEvents,其中 uint16 的定义为:typedef unsigned short
uint16
tasksArr—这是一个数组, 数组的每一项都是一个函数指针, 指向了事件处理函数
该数组的声明为:const pTaskEventHandlerFn tasksArr[],其中 pTaskEventHandlerFn 的
定义为:typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short
event ),这是定义了一个函数指针。tasksArr 数组的每一项都是一个函数指针,指向了事件
处理函数。
事件表 任务中的事件处理函数表
OSAL消息队列
提到事件,我们就不得不提到消息。事件是驱动任务去执行某些操作的条件,当系统中产生了一个事件,OSAL 将这个事件传递给相应的任务后,任务才能执行一个相应的操作(调用事件处理函数去处理) 。
通常某些事件发生时,又伴随着一些附加信息的产生,例如:从天线接收到数据后,会产生 AF_INCOMING _MSG_CMD 消息,但是任务的事件处理函数在处理这个事件的时候,还需要得到收到的数据。
因此,这就需要将事件和数据封装成一个消息,将消息发送到消息队列,然后在事件处理函数中就可以使用 osal_msg_receive 从消息队列中得到该消息。afIncomingMSGPacket_t *MSGpkt; //根据消息类型声明对应的接收消息的变量
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); //强制转化成对应的消息类型
OSAL维护了一个消息队列,每一个消息都会被放到这个消息队列中去,当任务接收到时间后,可以从消息队列中获取属于自己的消息,然后调用消息处理函数进行相应的处理即可。
OSAL中消息队列如下图所示:
每个消息都包含一个消息头osal_mag_hdr_t和用户自定义的消息,osal_msg_hdr_t结构体的定义为:
typedef struct
{
void *next;
uint16 len;
uint8 dest_id;
} osal_msg_hdr_t;
OSAL工作机制分析的更多相关文章
- Java IO工作机制分析
Java的IO类都在java.io包下,这些类大致可分为以下4种: 基于字节操作的 I/O 接口:InputStream 和 OutputStream 基于字符操作的 I/O 接口:Writer 和 ...
- Map/Reduce 工作机制分析 --- 错误处理机制
前言 对于Hadoop集群来说,节点损坏是非常常见的现象. 而Hadoop一个很大的特点就是某个节点的损坏,不会影响到整个分布式任务的运行. 下面就来分析Hadoop平台是如何做到的. 硬件故障 硬件 ...
- Map/Reduce 工作机制分析 --- 数据的流向分析
前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议. 接下来,数据被会被送往一个个Map节点中去,这也无异议. 下面问题来了:数据在被Map节点处理完后,再何去何从呢? ...
- Map/Reduce 工作机制分析 --- 作业的执行流程
前言 从运行我们的 Map/Reduce 程序,到结果的提交,Hadoop 平台其实做了很多事情. 那么 Hadoop 平台到底做了什么事情,让 Map/Reduce 程序可以如此 "轻易& ...
- 第十一篇:Map/Reduce 工作机制分析 - 错误处理机制
前言 对于Hadoop集群来说,节点损坏是非常常见的现象. 而Hadoop一个很大的特点就是某个节点的损坏,不会影响到整个分布式任务的运行. 下面就来分析Hadoop平台是如何做到的. 硬件故障 硬件 ...
- 第十篇:Map/Reduce 工作机制分析 - 数据的流向分析
前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议. 接下来,数据被会被送往一个个Map节点中去,这也无异议. 下面问题来了:数据在被Map节点处理完后,再何去何从呢? ...
- 第九篇:Map/Reduce 工作机制分析 - 作业的执行流程
前言 从运行我们的 Map/Reduce 程序,到结果的提交,Hadoop 平台其实做了很多事情. 那么 Hadoop 平台到底做了什么事情,让 Map/Reduce 程序可以如此 "轻易& ...
- hostapd源代码分析(二):hostapd的工作机制
[转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...
- Linux内核分析第四周学习总结——系统调用的工作机制
Linux内核分析第四周学习总结--系统调用的工作机制 内核态 执行级别高,可以执行特权指令,访问任意物理地址,在intel X86 CPU的权限分级为0级. 用户态 执行级别低,只能访问0x0000 ...
随机推荐
- 大纲2.3 Internet
Internet:域名系统基础知识和配置,上网查询访问的方法,常用电子邮件的种类和收发电子邮件的方法,网络信息搜索,网络信息下载.上传的基本方法,网络信息共享方法. DNS域名系统 域名 不区分大小写 ...
- CentOS7下安装MySQL5.7安装与配置(YUM)
http://blog.csdn.net/xyang81/article/details/51759200 安装环境:CentOS7 64位 MINI版,安装MySQL5.7 1.配置YUM源 在My ...
- bzoj4289 Tax
Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...
- 喵哈哈村的魔法考试 Round #1 (Div.2) 题解
喵哈哈村的魔法考试 Round #1 (Div.2) 题解 特别感谢出题人,qscqesze. 也特别感谢测题人Xiper和CS_LYJ1997. 没有他们的付出,就不会有这场比赛. A 喵哈哈村的魔 ...
- 使用MFC做一个简单的‘能自动生成小学生四则运算的软件’
这是软件工程的第一次作业!但由于我们python还没入门,所以这次的要求是‘语言不限’. 小学期做过一个关于MFC的‘资金管理系统’,也正好可以有界面,所以就选择了自己很熟悉的MFC来做这个作业! 1 ...
- 使用 IntraWeb (17) - 基本控件之 TIWRadioButton、TIWRadioGroup、TIWCheckBox
TIWRadioButton //单选 TIWRadioGroup //单选组 TIWCheckBox //复选 TIWRadioButton 所在单元及继承链: IWCompRadioButton. ...
- 一种高效的序列化方式——MessagePack
最近在弄一些数据分析方面的内容,发现很多时候数据瓶颈在模块之间的数据序列化和反序列化上了,原来项目中用的是Json,找了一圈发现Json.net在Json序列化库中已经是性能的佼佼者了,便准备从序列化 ...
- USB2.0 速度识别--区分低速-高速-全速
USB2.0是向下兼容USB1.X的,即USB2.0支持高速,全速,低速的USB设备 (HIGH-SPEED,FULL-SPEED,LOW-SPEED),而USB1.X不支持高速设备. 因此如果高速设 ...
- CAS服务器配置
参考文献: http://sucre.blog.51cto.com/1084905/683624 1.安装部署CAS Server 从官网下载CAS Server,今天发现CAS Server的官网居 ...
- 液晶电视插有线电视信号线的是哪个接口 HDMI是什么接口
1.液晶电视插有线电视信号线的接口(模拟信号)是射频接口(也叫RF接口,同轴电缆接口,闭路线接口),数字信号就得通过机顶盒转换成模拟信号视频输出至电视,才能正常收看电视节目. 2.电视机或高清机顶盒上 ...