您的位置:首页 > 其它

Zigbee系列 学习笔记二(工程文件分析)

2015-08-01 09:34 399 查看
以下为转载内容,因为学习Zigbee,稍作整理了一下,希望作者不要怪罪。

一、下载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



现在我们先来看看Projects这个文件夹,里面是Ti给我们的一些例子程序之类的东西。,Projects->zstack之后我们可以看到这样子的一堆目录



同样来说说这些目录都是干啥的,第一个就够霸气了,HomeAutomation,会英文的都知道,这是智能家居的例子,里面包含了一个开关程序例子,灯光例子,还有一个空中升级的例子。Libraies我就不说了,这是库的文件夹,OTA是啥来的呢?这是TI提供的一个空中升级的插件程序,你的程序不一定要用到。Samples这个文件夹放得是一个简单的例子程序,好了,其他的不说了,ZMain放的是main函数的文件,因为协议栈用到了很多种的板子,所以提供了不同类型板子的程序模块。我们一般用到的是TI2530DB里面的那部分程序。

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

  /* * Initialize the operating system * 初始化操作系统 */

  osal_init_system();

  /* * 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

  /* * No Return from here * 执行操作系统,进入后不会返回 */

  osal_start_system();

  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();

  /* * Initialize the system tasks. * 初始化系统任务 */

  osalInitTasks();

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

  osal_mem_kick();

  return ( SUCCESS );

}

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

首先,我们要来说的就是zstack的操作系统---OSAL,我们的协议栈其实是运行在TI的OSAL操作系统之上的,我们的程序(在程序中叫做task)和协议栈的各层都是作为osal的一个个任务在运行,由osal来调度的。我们刚才看到的是如何去启动了osal系统而已,既然我们的程序和协议栈都是osal的一个任务,那么我们如何把自己的任务注册进来呢?这是接下来我们要说的问题,至于osal的基本机制,我们以后再说,现在要做的是先让大家能够下载些程序下去玩玩,满足一下虚荣之心先。

四、建立自己的任务

还是按照例子来说比较好说,那么我们挑选的例子就是TI的一个基本的例子,实现了一些最基本的入网和收发数据亮灯程序。我挑选了ZStack-CC2530-2.5.1a\Projects\zstack\Samples\GenericApp这个工程来说明如何建立自己的任务,打开ZStack-CC2530-2.5.1a\Projects\zstack\Samples\GenericApp\CC2530DB里面的IAR工程,我们可以看到这样子的架构。



当然你重头到尾建立这样子一个工程是挺费劲的,TI已经提供好了,那就用TI的例子修改就行了,没必要重头到尾建立一次,我建过,还是要看着TI的配置来做,很麻烦,很多配置东西你要清楚才能配置好。我们要建立自己任务,那么这些东西都在App这个Group里面,看看里面有啥东西



可以看出只有三个文件,这三个文件却大有头,这样子的架构几乎成了TI的zstack的程序架构,几乎所有的都是这样子写的,GenericApp.h放的是一些用户的宏定义,GenericApp.c实现我们自己的任务代码,OSAL_GenericApp.c主要是实现osal协议的协议初始化接口的编写,我们的任务添加,就靠这三个文件了!好,我们先不看我们的任务代码是怎么实现的,我们先看OSAL_GenericApp.c是怎么添加我们的任务的和初始化osal的任务的,内容不多,就全放上来吧。

#include "ZComDef.h"
#include "hal_drivers.h"
#include "OSAL.h"
#include "OSAL_Tasks.h"

#if defined ( MT_TASK )
#include "MT.h"
#include "MT_TASK.h"
#endif

#include "nwk.h"
#include "APS.h"
#include "ZDApp.h"
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
#include "ZDNwkMgr.h"
#endif
#if defined ( ZIGBEE_FRAGMENTATION )
#include "aps_frag.h"
#endif

#include "GenericApp.h"

/*********************************************************************
* GLOBAL VARIABLES
*/

// The order in this table must be identical to the task initialization calls below in osalInitTask.
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
GenericApp_ProcessEvent
};

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

/*********************************************************************
* FUNCTIONS
*********************************************************************/

/*********************************************************************
* @fn      osalInitTasks
*
* @brief   This function invokes the initialization function for each task.
*
* @param   void
*
* @return  none
*/
void osalInitTasks( void )
{
uint8 taskID = 0;

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
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
GenericApp_Init( taskID );
}


其实里面就两样东西是重要的,一个是tasksArr这个数组,一个是osalInitTasks这个函数

tasksArr其实就是osal的一个任务列表,里面包含了osal系统中所有的任务,里面有我们任务处理事件的循环,当有消息是给我们的任务的时候osal就会调用我们的任务处理循环GenericApp_ProcessEvent,当然啦,osal没有win系统那么牛叉,更没有linux系统那么让人感到可爱,他是一个让人感到不恶心,可是不讨人喜欢的小小的实时操作系统。osalInitTasks这个其实就是任务初始化函数,在上面的osal_start_system之前会被调用,而且这个函数会调用很多任务的初始化函数,同样包括我们自己的任务的初始化函数GenericApp_Init,至于GenericApp_ProcessEvent和GenericApp_Init等下再说,我们先来看看到底是啥时候调用了osalInitTasks,以及tasksArr是如何被osal使用的。

我们回到main函数中,可以看到这样子的一个函数被调用了osal_init_system,我们再看看看osal_init_system做了什么

uint8 osal_init_system( void )
{
// Initialize the Memory Allocation System
osal_mem_init();

// Initialize the message queue
osal_qHead = NULL;

// Initialize the timers
osalTimerInit();

// Initialize the Power Management System
osal_pwrmgr_init();

// Initialize the system tasks.
osalInitTasks();

// Setup efficient search for the first free block of heap.
osal_mem_kick();

return ( SUCCESS );
}


很明显,在这里他不但初始化了osal的内存管理,电源管理,并且调用了我们的osalInitTasks函数来初始化osal的所有task,所以在系统进入大循环之前,这些任务是被初始化了的,而osal是如何知道我们的这些任务的呢,就是通过tasksArr这个数组。我们来看看osal_run_system可以看到这样子一段events = (tasksArr[idx])( idx, events );由此可以看出,我们的任务是这样子被添加进来的,并且任务初始化的时候每个task都带了一个taskID,osal就是根据这个taskID来区分每个task,event是哪个task发起的,应该发给哪个task。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: