ZStack-CC2530-2.5.1a主要代码分析总结——明白ZStack-OSAL的原理和思想

一、下载ZStack-CC2530.2.5.1a

http://download.csdn.net/detail/thanksgining/8328925

下载后:

二、安装ZStack-CC2530.2.5.1a

安装后:

Components:顾名思义这个是库文件,里面放了一些ZDO,driver,hal,zcl等库代码

Documents:这个不用说大家都知道是放TI的开发文档的,你能够把这些文档一个个看懂,你对这个协议栈已经是了如指掌了。里面很多都是讲述协议栈的API的必须读

Projects:这个文件夹放的是TI协议栈的例子程序,一个个例子程序都是以一个个project的形式给我们的,学好这些例子程序的一两个,基本你就能做事情了

Tools这个文件是放TI的例子程序的一些上位机之类的程序,作为工具使用

Components文件夹

如上所言,全是一些库的东西,hal是硬件层面上的一些driver等等。mac、zmac是mac层的协议接口,mt是我们用到的API几乎都可以在这里找到例子。osal这个就是TI的ZStack协议栈的操作系统,是事件驱动的,stack是一些zdo和zcl等等。

三、打开SamleApp.eww工程,路径:Projects\zstack\Samples\SampleApp\CC2530DB

1、进入main函数,文件路径:ZMain下的ZMain.c

int main( void )
{
  /*
   * Turn off interrupts 关闭所有中断,其实就是关闭总中断
   * #define INTS_ALL    0xFF
   * 最终调用 EA = 0;
   */
  osal_int_disable( INTS_ALL );

  /*
   * Initialization for board related stuff such as LEDs
   * 初始化系统时钟、LEDs
   */
  HAL_BOARD_INIT();

  /*
   *  Make sure supply voltage is high enough to run
   * 检查芯片电压是否正常
   */
  zmain_vdd_check();

  // Initialize board I/O
  InitBoard( OB_COLD );

  /*
   * Initialze HAL drivers
   * 初始化ADC、DMA、AES、LED、LCD、KEY
   * UART、SPI等有放在此函数初始化,但没有实现
   * 硬件相关初始化
   */
  HalDriverInit();

  /*
   * Initialize NV System
   * 初始化FLASH、存储器
   */
  osal_nv_init( NULL );

  /*
   * Initialize the MAC
   * 初始化MAC层
   */
  ZMacInit();

  /*
   * Determine the extended address
   * 确定IEEE 64位地址
   */
  zmain_ext_addr();

#if defined ZCL_KEY_ESTABLISH   //没有定义
  // Initialize the Certicom certificate information.
  zmain_cert_init();
#endif

  /*
   * Initialize basic NV items
   * 初始化非易失变量
   */
  zgInit();

#ifndef NONWK
  // Since the AF isn't a task, call it's initialization routine
  afInit();
#endif

  <span style="color:#3333ff;"><strong>/*
   * Initialize the operating system
   * 初始化操作系统
   */
  osal_init_system();</strong></span>

  /*
   * Allow interrupts 允许所有中断,其实就是开总中断
   * #define INTS_ALL    0xFF
   * 最终调用 EA = 1;
   */
  osal_int_enable( INTS_ALL );

  /*
   * Final board initialization
   * 初始化按键
   * #define OB_READY 2
   */
  InitBoard( OB_READY );

  /*
   * Display information about this device
   * 在LCD上打印显示此设备的设备信息
   */
  zmain_dev_info();

  /* Display the device info on the LCD */
#ifdef LCD_SUPPORTED    //没有定义
  zmain_lcd_init();
#endif

#ifdef WDT_IN_PM1       //没有定义
  /* If WDT is used, this is a good place to enable it. */
  WatchDogEnable( WDTIMX );
#endif

  <strong><span style="color:#3333ff;">/*
   * No Return from here
   * 执行操作系统,进入后不会返回
   */
  osal_start_system(); </span></strong>

  return 0;  // Shouldn't get here.
} // main()

对于一个片上系统而言,必需有电源、晶振/时钟、存储器等部件组成,所有我们的协议栈也必需初始化这些。从main函数也可以看出,它确实也初始化的电压、时钟、存储器,还有网络、IEEE、系统、非易失变量等一些初始化,这些初始化主要根据具体的硬件平台。而ZStack协议栈采用的是多任务机制,并且采用轮询方式来执行这些任务。在调用osal_start_system启动系统之后,系统就开始永无止境地轮询来执行每个任务。在看系统启动后是如何轮询所有的任务之前,我们先来看下系统初始化函数osal_init_system

uint8 osal_init_system( void )
{
  /*
   * Initialize the Memory Allocation System
   * 初始化内存分配
   */
  osal_mem_init();

  /*
   * Initialize the message queue
   * 初始化消息队列
   * typedef void * osal_msg_q_t;
   * osal_msg_q_t osal_qHead;
   * osal_qHead是一个void的指针,可以指向任何类型
   */
  osal_qHead = NULL;

  /*
   * Initialize the timers
   * 函数里只有一条语句:osal_systemClock = 0;
   * 而static uint32 osal_systemClock;
   * 初始化定时计时变量为0
   */
  osalTimerInit();

  /*
   * Initialize the Power Management System
   * 初始化电源管理
   */
  osal_pwrmgr_init();

  <span style="background-color: rgb(255, 255, 255);"><span style="color:#3333ff;"><strong>/*
   * Initialize the system tasks.
   * 初始化系统任务
   */
  osalInitTasks();</strong></span></span>

  /*
   * Setup efficient search for the first free block of heap.
   * 设置有效的搜索第一堆的自由块
   */
  osal_mem_kick();

  return ( SUCCESS );
}

系统的初始化主要从操作系统层面来做相应的初始化,比如内存管理、电源管理、消息队列等一些初始化。其中的定时器初始化,是因为ZStack-OSAL系统采用了定时捕捉任务事件的发生。这里主要是系统任务初始化函数osalInitTask(),将整个系统的所有任务都初始化了

void osalInitTasks( void )
{
  uint8 taskID = 0;  //8位长度的变量,任务ID,0~255

  /*
   * 任务事件表,全局变量
   * uint16 *tasksEvents; 从此定义可以看出taskEvents指向一张列数为16的二维表,一个任务中可以有多个事件
   * const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
   * 而tasksArr是所有任务事件处理函数的指针数组,即有多少个任务,就多少个任务事件处理函数,即taskCnt就为多少
   */
  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  /*将任务表全部初始化为0*/
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

  /*任务优先级由高向低依次排列,高优先级对应 taskID   的值反而小*/
  macTaskInit( taskID++ );               //mac层任务初始化,macTaskInit(0),不用关心,我们进入不了此函数
  nwk_init( taskID++ );                  //nwk层任务初始化,nwk_init(1),不用关心,我们进入不了此函数
  Hal_Init( taskID++ );                  //hal层任务初始化,Hal_Init(2),
#if defined( MT_TASK )                   //没有定义
  MT_TaskInit( taskID++ );
#endif
  APS_Init( taskID++ );                 //aps层任务初始化,APS_Init(3),不用关心,我们进入不了此函数
#if defined ( ZIGBEE_FRAGMENTATION )    //有定义,数据分包分割相关
  APSF_Init( taskID++ );                //apsf任务初始化,APSF_Init(4),不用关心,我们进入不了此函数
#endif
  ZDApp_Init( taskID++ );              //ZDO初始化,ZDApp_Init(5),
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) //有定义 IP冲突相关、跳频相关
  ZDNwkMgr_Init( taskID++ );           //nwk任务初始化,ZDNwkMgr_Init(6)
#endif
  SampleApp_Init( taskID );            //此例子有关任务事件初始化,可以进入函数做相应的修改,
}

任务初始化函数主要为所有的任务分配内存空间以及将任务事件初始化为0,然后就是ZStack-OSAL各层的初始化(ZStack-OSAL采用分层思想),至于每个任务初始化都做了些什么,暂时不进入分析。因为就算根据前辈们的分析,去分析每个任务初始化函数并且在每行代码都加上注释也不知道,任务初始化都做了些什么,这些代码到底有什么作用,一概不知。我就进去分析一些任务初始化代码,分析几天也不知道它们为什么要这样做,这样做有什么作用。我不希望你们也浪费时间来分析目前对我们学习ZStack-OSAL一些不好理解的代码,当然随着慢慢学习肯定会知道它们做了什么,为什么要这样做的。既然任务都已经初始化了,那就启动系统吧,回到main函数的osal_start_system启动系统函数

/*
 * 这个是任务系统轮询的主要函数。他会查找发生的事件然后调用相应的事件执行函数。
 * 如果没有事件登记要发生,那么就进入睡眠模式。这个函数是永远不会返回的。
 */
void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )  //都没有定义,所有进入for死循环
  for(;;)  // Forever Loop 死循环,采用轮询方法查询任务事件
#endif
  {
    /*作为for死循环的执行语句,执行系统*/
    osal_run_system();
  }
}

这个for死循环,每循环一次就执行oasl_run_system函数一些,看看oasl_run_system函数是怎样的轮询法

void osal_run_system( void )
{
  uint8 idx = 0;

  /*扫描哪个任务事件被触发了,然后把相应的标志为置1*/
  osalTimeUpdate();
  Hal_ProcessPoll();

  /*从最高优先级任务依次判断每个任务是否有事件触发,如果则跳出循环*/
  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;//得到待处理的最高优先级任务索引号idx
    }
  } while (++idx < tasksCnt);

  /*如果idx小于所有任务的数量,则表示有任务事件发生*/
  if (idx < tasksCnt)
  {
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];         //保存触发的(活动的)任务事件
    tasksEvents[idx] = 0;  // Clear the Events for this task.清除此任务的事件
    HAL_EXIT_CRITICAL_SECTION(intState);

    activeTaskID = idx;              //保存活动的任务事件的ID号
    events = (tasksArr[idx])( idx, events );  //执行对应的任务事件处理函数,tasksArr[idx]是个函数指针
    activeTaskID = TASK_NO_TASK; //#define TASK_NO_TASK      0xFF

    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.添加后面未处理的事件到当前事件任务中
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
#if defined( POWER_SAVING )  //没有定义
  else  // Complete pass through all task events with no activity?
  {
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)      //没有定义
  {
    osal_task_yield();
  }
#endif
}

ZStack-OSAL系统用一个定时任务(osalTimerRec_t)链表将所有的任务定时执行串在一起,并用timerHead指向这个链表头。osal_run_system中的osalTimeUpdate()就是来判断任务的定时是否到时,到时就为对应的任务设置任务事件。当此任务设置了任务事件,即对应的tasksEvents[idx]不为0,所用在上述的do
while()循环就break退出,并获得对应任务的id,此时的idx就是此任务的id。最后调用events = (tasksArr[idx])( idx, events );执行任务对应的任务事件处理函数,tasksArr是一个函数指针数组,每个数组成员都指向一个任务事件处理函数。从这里可以看出我们是通过任务的ID号来找到对应的任务事件处理函数,所以所有任务事件处理函数的顺序要与所有任务初始化的顺序一致。即tasksArr这个函数指针数组的成员顺序,要与oaslInitTasks中的任务初始化顺序一致,下面给出tasksArr

typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );
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
};

总结

ZStack-OSAL所有的任务事件用一张二维表来表示,二维表的每行代表一个任务,二维表的列来表示对应任务的事件。用tasksEvents指针指向这张二维表,tasksEvents在OSAL_SampleApp.c中定义如下:

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
uint16 *tasksEvents;

从这里我们也可以看出,通过计算任务事件处理函数的个数,来知道整个系统有多少个任务。tasksCnt表示系统任务总数。

tasksEvents指针指向的二维表初始化,此初始化在任务初始化函数osalInitTasks中,初始化如下:

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  /*将任务表全部初始化为0*/
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

一旦任务的定时到时间了,此任务就被设置有事件(设置相应的事件),有事件的任务tasksEvents[idx]就不为0,则根据任务ID号找到对应的任务事件处理函数对任务事件进行处理。(当然上述任务数量不一定就是14个,只是为了说明问题,前面的0~13指的是任务ID号)。

时间: 2024-11-01 18:50:35

ZStack-CC2530-2.5.1a主要代码分析总结——明白ZStack-OSAL的原理和思想的相关文章

转: ZigBee/Z-Stack CC2530实现低功耗运行的配置简介

转: ZigBee/Z-Stack CC2530实现低功耗运行的配置简介http://bbs.elecfans.com/jishu_914377_1_1.html(出处: 中国电子技术论坛) 设备支持低功耗运行是ZigBee网络的一大特点,该特性借助CC2530芯片能够很好地体现出来.CC2530芯片有五种运行模式,分别为主动模式.空闲模式.PM1.PM2和PM3.主动模式是一般运行模式:空闲模式除了CPU内核停止运行外,其他和主动模式一样:PM1.PM2.PM3是低功耗运行模式,CC2530通

java代码分析及分析工具

java代码分析及分析工具 一个项目从搭建开始,开发的初期往往思路比较清晰,代码也比较清晰.随着时间的推移,业务越来越复杂.代码也就面临着耦合,冗余,甚至杂乱,到最后谁都不敢碰. 作为一个互联网电子商务网站的业务支撑系统,业务复杂不言而喻.从09年开始一直沿用到现在,中间代码经过了多少人的手,留下了多少的坑,已经记不清楚了,谁也说不清了. 代码的维护成本越来越高.代码已经急需做调整和改善.最近项目组专门设立了一个小组,利用业余时间做代码分析的工作,目标对核心代码进行分析并进行设计重构. 代码分析

Java静态代码分析工具Infer

Java静态代码分析工具Infer 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.Infer介绍 Infer是Facebook最新开源的静态程序分析工具,用于在发布移动应用之前对代码进行分析,找出潜在的问题.目前Facebook使用此工具分析Facebook的App,包括Android.iOS.Facebook Messenger和Instagram等. Facebook称该工具帮助其每个月检查出应用潜在的数百个Bug,例如一些空指针访问.资源

$*和[email&#160;protected]之间区别代码分析

#!/bin/bash set 'apple pie' pears peaches for i in $*           /*单引号被去掉,循环单个字符输出*/ do echo $i done [[email protected] Ex_14.02-14.31]# sh 14-14-1 apple pie pears peaches -------------------------------------------------------------- #!/bin/bash set

《linux 内核完全剖析》 keyboard.S 部分代码分析(key_map)

keyboard.S 部分代码分析(key_map) keyboard中间有这么一段,我一开始没看明白,究竟啥意思 key_map: .byte 0,27 .ascii "1234567890-=" .byte 127,9 .ascii "qwertyuiop[]" .byte 13,0 .ascii "asdfghjkl;'" .byte '`,0 .ascii "\\zxcvbnm,./" .byte 0,'*,0,32

20145234黄斐《网络对抗技术》实验四,恶意代码分析

恶意代码 概述 恶意代码是指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的计算机代码.最常见的恶意代码有计算机病毒(简称病毒).特洛伊木马(简称木马).计算机蠕虫(简称蠕虫).后门.逻辑炸弹等. 特征: 恶意的目的,获取靶机权限.用户隐私等 本身是计算机程序,可以执行,并作用于靶机 通过执行发生作用,一般来说不运行是没问题的 恶意代码分析 在大多数情况下,进行恶意代码分析时,我们将只有恶意代码的可执行文件本身,而这些文件并不是我们人类可读的.为了了解这些文件的意义,你需要使用各种工具和技巧

20145326蔡馨熠《网络对抗》——恶意代码分析

20145326蔡馨熠<网络对抗>--恶意代码分析 1.实验后回答问题 (1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所以想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监控.. 需要监控什么? 系统中各种程序.文件的行为. 还需要注意是否会出现权限更改的行为. 注册表. 是否有可疑进程. 如果有网络连接的情况,需要注意这个过程中的IP地址与端口. 用什么来监控? 最先想到的肯定是使用wireshark抓包了,再进行进一步分析. Sysinternals

代码分析—“CA0052 没有选择要分析的目标”(VS2012)

情况: 1.未采用代码分析时程序正常编译 2.采用代码分析,会提示"没有选择分析目标"或"未加载制定版本的程序集"...的错误 分析: 是由于代码分析依赖程序集的强签名,包括版本 解决方案: 1.修改代码分析工具的配置项: FxCopCmd.exe.config里节点AssemblyReferenceResolveMode的Value值StrongName修改为StrongNameIgnoringVersion或None 2.修改当前分析的项目: .csproj增加

常用 Java 静态代码分析工具的分析与比较

转载自: http://www.oschina.net/question/129540_23043 简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能.特性等方面对它们进行分析和比较,希望能够帮助 Java 软件开发人员了解静态代码分析工具,并选择合适的工具应用到软件开发中. 引言 在 Java 软件开发过程中,开发团队往往要花费大量的时间和精力发现并修改代