协议栈代码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工作机制分析的更多相关文章

  1. Java IO工作机制分析

    Java的IO类都在java.io包下,这些类大致可分为以下4种: 基于字节操作的 I/O 接口:InputStream 和 OutputStream 基于字符操作的 I/O 接口:Writer 和 ...

  2. Map/Reduce 工作机制分析 --- 错误处理机制

    前言 对于Hadoop集群来说,节点损坏是非常常见的现象. 而Hadoop一个很大的特点就是某个节点的损坏,不会影响到整个分布式任务的运行. 下面就来分析Hadoop平台是如何做到的. 硬件故障 硬件 ...

  3. Map/Reduce 工作机制分析 --- 数据的流向分析

    前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议. 接下来,数据被会被送往一个个Map节点中去,这也无异议. 下面问题来了:数据在被Map节点处理完后,再何去何从呢? ...

  4. Map/Reduce 工作机制分析 --- 作业的执行流程

    前言 从运行我们的 Map/Reduce 程序,到结果的提交,Hadoop 平台其实做了很多事情. 那么 Hadoop 平台到底做了什么事情,让 Map/Reduce 程序可以如此 "轻易& ...

  5. 第十一篇:Map/Reduce 工作机制分析 - 错误处理机制

    前言 对于Hadoop集群来说,节点损坏是非常常见的现象. 而Hadoop一个很大的特点就是某个节点的损坏,不会影响到整个分布式任务的运行. 下面就来分析Hadoop平台是如何做到的. 硬件故障 硬件 ...

  6. 第十篇:Map/Reduce 工作机制分析 - 数据的流向分析

    前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议. 接下来,数据被会被送往一个个Map节点中去,这也无异议. 下面问题来了:数据在被Map节点处理完后,再何去何从呢? ...

  7. 第九篇:Map/Reduce 工作机制分析 - 作业的执行流程

    前言 从运行我们的 Map/Reduce 程序,到结果的提交,Hadoop 平台其实做了很多事情. 那么 Hadoop 平台到底做了什么事情,让 Map/Reduce 程序可以如此 "轻易& ...

  8. hostapd源代码分析(二):hostapd的工作机制

    [转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...

  9. Linux内核分析第四周学习总结——系统调用的工作机制

    Linux内核分析第四周学习总结--系统调用的工作机制 内核态 执行级别高,可以执行特权指令,访问任意物理地址,在intel X86 CPU的权限分级为0级. 用户态 执行级别低,只能访问0x0000 ...

随机推荐

  1. MySQL数据库之索引

    1 引言 在没有索引的情况下,如果要寻找特定行,数据库可能要遍历整个数据库,使用索引后,数据库可以根据索引找出这一行,极大提高查询效率.本文是对MySQL数据库中索引使用的总结. 2 索引简介 索引是 ...

  2. 分类器评估方法:ROC曲线

    注:本文是人工智能研究网的学习笔记 ROC是什么 二元分类器(binary classifier)的分类结果 ROC空间 最好的预测模型在左上角,代表100%的灵敏度和0%的虚警率,被称为完美分类器. ...

  3. 一个线上程序bug,由通用补数程序引起

    下游发现接口可用率非100%,马上线上查看,发现数据在有些情况下通用补数的数据是空, 有20%的用户是没有相应偏好等的数据的,需要通用补数来补数,结果通用补数没有数据. 通用补数数据的检查报警时必须要 ...

  4. BZOJ.1024.[SCOI2009]生日快乐(记忆化搜索)

    题目链接 搜索,枚举切的n-1刀. 对于长n宽m要切x刀,可以划分为若干个 长n'宽m'要切x'刀 的子问题,对所有子问题的答案取max 对所有子问题的方案取min 就是当前状态答案. 这显然是会有很 ...

  5. 独家专访|浙江执御:为何接受富安娜入股而不选VC?_深圳市跨境电子商务协会_新浪博客

    独家专访|浙江执御:为何接受富安娜入股而不选VC?_深圳市跨境电子商务协会_新浪博客   http://blog.sina.com.cn/s/blog_13cb5d69e0102vuvk.html

  6. 使用MSTest进行单元测试

    我之前写过一篇XUNit的简介:使用Xunit来进行单元测试.Xunit在当时确实是一个最简单易用的测试框架,然而,随着发展,Xunit也变得复杂了不少,光写一个最简单的测试就要导入8个包. 如果在大 ...

  7. CSS高速制作图片轮播的焦点

    来源:http://www.ido321.com/858.html 效果图: 演示地址:http://jsfiddle.net/Web_Code/q5qfd8aL/embedded/result/ 代 ...

  8. MyEclipse使用总结——MyEclipse中配置WebLogic12c服务器

    MyEclipse中配置WebLogic12c服务器的步骤如下: [Window]→[Preferences],如下图所示: 找到WebLogic的配置,如下图所示:

  9. SpringBoot配置多数据源

    原文:https://www.jianshu.com/p/033e0ebeb617 项目中用到了两个数据库,分别是Oracle和Mysql,涉及到了多数据源问题,这里做下记录 官方讲解:https:/ ...

  10. Linux学习11-CentOS如何设置java环境变量

    前言 之前用yum安装的java,现在想添加环境变量,yum安装的java路径在哪呢?如何找到安装的路径,把jdk添加到环境变量. 本篇详细讲解linux系统设置java环境变量 找到jdk路径 之前 ...