博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
zigbee学习笔记4----初次接触zstack
阅读量:4049 次
发布时间:2019-05-25

本文共 7981 字,大约阅读时间需要 26 分钟。

 

1.写在前面

之前一直在写裸机下的cc2530的那部分,现在觉得这样子写没啥意思,所以不再写那部分了,需要 ,这里面有你们需要的,而且里面写的很不错,所以请需要的人请移步。在这篇学习笔记中将初次接触Ti公司的zstack。

2.揭开她的面纱

          在开始的第一个笔记中我写到了如何安装zstack,其实很多人可能和我一样,开始装了zstack不知道拿来干嘛的,特别是一些刚接触这个行业的人,所以我们先来搞清楚zstack是装来干嘛的!其实很简单,zstack安装了之后得到了不是一大堆文件夹吗?里面包含了很多TI开源的代码和不开源的一些库,我们在编程的时候需要用到这些代码和库,就像我们写c语言程序的时候很多#include这些,很多都是库文件一样,而且Ti给了很多例子程序给我们,我们开始学习就从这些例子程序开始学起,特别重要的就是学习不是只看懂TI的例程就可以了,还要学会去修改TI的例程,把一个实现的简单的功能的程序,改编成一个实现复杂功能的程序。

       工欲善其事,必先利其器,在学习zstack之前我们先要安装两个软件辅助我们学习,一个就是大名鼎鼎的source insight,一个同样是大名鼎鼎的IAR(8.0),source insight辅助我们查看代码,IAR作为开发编译工具使用,当然,IAR也能作为看代码的工具,只是没有source insight那么直观。这两个软件的安装使用请询问百度或者谷歌。

       我们先来看看我们装完zstack之后得到的目录结构

      

      在图中我们可以看到好几个目录,我在第一篇中都解析过这些目录里面有啥干啥用的,如果你不想在你安装的目录去弄这些东西,你完全可以把这些文件拷贝到别的地方去弄,我就把他铐到了G盘去,这样子做的好处就是,就算你够衰把文件搞不见了,你还有原来的那个,不至于又要重装一次。现在我们先来看看Projects这个文件夹,里面是Ti给我们的一些例子程序之类的东西。,Projects->zstack之后我们可以看到这样子的一堆目录

     

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

     先来看看这个main函数,也许这个是c程序猿的通病,一下子就要找入口。
/********************************************************************* * @fn      main * @brief   First function called after startup. * @return  don't care */int main( void ){  // Turn off interrupts  osal_int_disable( INTS_ALL );  // Initialization for board related stuff such as 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  HalDriverInit();  // Initialize NV System  osal_nv_init( NULL );  // Initialize the MAC  ZMacInit();  // Determine the extended address  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  osal_int_enable( INTS_ALL );  // Final board initialization  InitBoard( OB_READY );  // Display information about this device  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  osal_start_system(); // No Return from here  return 0;  // Shouldn't get here.} // main()

也许有人会问,大循环去哪啦?别着急,其实main做了一大堆东西之后在osal_start_system这里就进入大循环了,我们先来看看osal_start_system做了什么事情

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

这会儿你看到你可爱的大循环了吧,继续看看osal_run_system做了什么东西

void osal_run_system( void ){  uint8 idx = 0;  osalTimeUpdate();  Hal_ProcessPoll();  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);    events = tasksEvents[idx];    tasksEvents[idx] = 0;  // Clear the Events for this task.    HAL_EXIT_CRITICAL_SECTION(intState);    activeTaskID = idx;    events = (tasksArr[idx])( idx, events );    activeTaskID = TASK_NO_TASK;    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,我们的协议栈其实是运行在TI的OSAL操作系统之上的,我们的程序(在程序中叫做task)和协议栈的各层都是作为osal的一个个任务在运行,由osal来调度的。我们刚才看到的是如何去启动了osal系统而已,既然我们的程序和协议栈都是osal的一个任务,那么我们如何把自己的任务注册进来呢?这是接下来我们要说的问题,至于osal的基本机制,我们以后再说,现在要做的是先让大家能够下载些程序下去玩玩,满足一下虚荣之心先。

3.建立自己的任务

      还是按照例子来说比较好说,那么我们挑选的例子就是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。

        至于GenericApp_ProcessEvent和GenericApp_Init是怎么实现的,下篇再说。

       

你可能感兴趣的文章
关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
查看>>
vsftp 配置具有匿名登录也有系统用户登录,系统用户有管理权限,匿名只有下载权限。
查看>>
linux安装usb wifi接收器
查看>>
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>
关于对象赋值及返回临时对象过程中的构造与析构
查看>>
VS 2005 CRT函数的安全性增强版本
查看>>
Visual Studio 2010:C++0x新特性
查看>>
drwtsn32.exe和adplus.vbs进行dump文件抓取
查看>>
cppcheck c++静态代码检查
查看>>
在C++中使用Lua
查看>>
一些socket的编程经验
查看>>
socket编程中select的使用
查看>>
可以在线C++编译的工具站点
查看>>
关于无人驾驶的过去、现在以及未来,看这篇文章就够了!
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
为什么读了很多书,却学不到什么东西?
查看>>
长文干货:如何轻松应对工作中最棘手的13种场景?
查看>>
如何用好碎片化时间,让思维更有效率?
查看>>
No.174 - LeetCode1305 - 合并两个搜索树
查看>>