初次接触zstack

来源:互联网 发布:mac开启root权限 编辑:程序博客网 时间:2024/06/07 13:56

zstack安装了之后得到了不是一大堆文件夹吗?里面包含了很多TI开源的代码和不开源的一些库,我们在编程的时候需要用到这些代码和库,就像我们写c语言程序的时候很多#include这些,很多都是库文件一样,而且Ti给了很多例子程序给我们,我们开始学习就从这些例子程序开始学起,特别重要的就是学习不是只看懂TI的例程就可以了,还要学会去修改TI的例程,把一个实现的简单的功能的程序,改编成一个实现复杂功能的程序。

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

       

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

      

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

     先来看看这个main函数,也许这个是c程序猿的通病,一下子就要找入口。
[cpp] view plain copy
  1. /********************************************************************* 
  2.  * @fn      main 
  3.  * @brief   First function called after startup. 
  4.  * @return  don't care 
  5.  */  
  6. int main( void )  
  7. {  
  8.   // Turn off interrupts  
  9.   osal_int_disable( INTS_ALL );  
  10.   
  11.   // Initialization for board related stuff such as LEDs  
  12.   HAL_BOARD_INIT();  
  13.   
  14.   // Make sure supply voltage is high enough to run  
  15.   zmain_vdd_check();  
  16.   
  17.   // Initialize board I/O  
  18.   InitBoard( OB_COLD );  
  19.   
  20.   // Initialze HAL drivers  
  21.   HalDriverInit();  
  22.   
  23.   // Initialize NV System  
  24.   osal_nv_init( NULL );  
  25.   
  26.   // Initialize the MAC  
  27.   ZMacInit();  
  28.   
  29.   // Determine the extended address  
  30.   zmain_ext_addr();  
  31.   
  32. #if defined ZCL_KEY_ESTABLISH  
  33.   // Initialize the Certicom certificate information.  
  34.   zmain_cert_init();  
  35. #endif  
  36.   
  37.   // Initialize basic NV items  
  38.   zgInit();  
  39.   
  40. #ifndef NONWK  
  41.   // Since the AF isn't a task, call it's initialization routine  
  42.   afInit();  
  43. #endif  
  44.   
  45.   // Initialize the operating system  
  46.   osal_init_system();  
  47.   
  48.   // Allow interrupts  
  49.   osal_int_enable( INTS_ALL );  
  50.   
  51.   // Final board initialization  
  52.   InitBoard( OB_READY );  
  53.   
  54.   // Display information about this device  
  55.   zmain_dev_info();  
  56.   
  57.   /* Display the device info on the LCD */  
  58. #ifdef LCD_SUPPORTED  
  59.   zmain_lcd_init();  
  60. #endif  
  61.   
  62. #ifdef WDT_IN_PM1  
  63.   /* If WDT is used, this is a good place to enable it. */  
  64.   WatchDogEnable( WDTIMX );  
  65. #endif  
  66.   
  67.   osal_start_system(); // No Return from here  
  68.   
  69.   return 0;  // Shouldn't get here.  
  70. // main()  

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

[cpp] view plain copy
  1. void osal_start_system( void )  
  2. {  
  3. #if !defined ( ZBIT ) && !defined ( UBIT )  
  4.   for(;;)  // Forever Loop  
  5. #endif  
  6.   {  
  7.     osal_run_system();  
  8.   }  
  9. }  

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

[cpp] view plain copy
  1. void osal_run_system( void )  
  2. {  
  3.   uint8 idx = 0;  
  4.   
  5.   osalTimeUpdate();  
  6.   Hal_ProcessPoll();  
  7.   
  8.   do {  
  9.     if (tasksEvents[idx])  // Task is highest priority that is ready.  
  10.     {  
  11.       break;  
  12.     }  
  13.   } while (++idx < tasksCnt);  
  14.   
  15.   if (idx < tasksCnt)  
  16.   {  
  17.     uint16 events;  
  18.     halIntState_t intState;  
  19.   
  20.     HAL_ENTER_CRITICAL_SECTION(intState);  
  21.     events = tasksEvents[idx];  
  22.     tasksEvents[idx] = 0;  // Clear the Events for this task.  
  23.     HAL_EXIT_CRITICAL_SECTION(intState);  
  24.   
  25.     activeTaskID = idx;  
  26.     events = (tasksArr[idx])( idx, events );  
  27.     activeTaskID = TASK_NO_TASK;  
  28.   
  29.     HAL_ENTER_CRITICAL_SECTION(intState);  
  30.     tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.  
  31.     HAL_EXIT_CRITICAL_SECTION(intState);  
  32.   }  
  33. #if defined( POWER_SAVING )  
  34.   else  // Complete pass through all task events with no activity?  
  35.   {  
  36.     osal_pwrmgr_powerconserve();  // Put the processor/system into sleep  
  37.   }  
  38. #endif  
  39.   
  40.   /* Yield in case cooperative scheduling is being used. */  
  41. #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)  
  42.   {  
  43.     osal_task_yield();  
  44.   }  
  45. #endif  
  46. }  

也许现在你看不明白他写了什么,放心总有一天你看得明白的,可是有个疑问会不会冒出来了呢?那我自己的代码写在哪啊!难过,难道我还得改这个大循环不成?!别急,现在我们来说说这协议栈是怎么工作的。

       首先,我们要来说的就是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的任务的,内容不多,就全放上来吧

[cpp] view plain copy
  1. #include "ZComDef.h"  
  2. #include "hal_drivers.h"  
  3. #include "OSAL.h"  
  4. #include "OSAL_Tasks.h"  
  5.   
  6. #if defined ( MT_TASK )  
  7.   #include "MT.h"  
  8.   #include "MT_TASK.h"  
  9. #endif  
  10.   
  11. #include "nwk.h"  
  12. #include "APS.h"  
  13. #include "ZDApp.h"  
  14. #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )  
  15.   #include "ZDNwkMgr.h"  
  16. #endif  
  17. #if defined ( ZIGBEE_FRAGMENTATION )  
  18.   #include "aps_frag.h"  
  19. #endif  
  20.   
  21. #include "GenericApp.h"  
  22.   
  23. /********************************************************************* 
  24.  * GLOBAL VARIABLES 
  25.  */  
  26.   
  27. // The order in this table must be identical to the task initialization calls below in osalInitTask.  
  28. const pTaskEventHandlerFn tasksArr[] = {  
  29.   macEventLoop,  
  30.   nwk_event_loop,  
  31.   Hal_ProcessEvent,  
  32. #if defined( MT_TASK )  
  33.   MT_ProcessEvent,  
  34. #endif  
  35.   APS_event_loop,  
  36. #if defined ( ZIGBEE_FRAGMENTATION )  
  37.   APSF_ProcessEvent,  
  38. #endif  
  39.   ZDApp_event_loop,  
  40. #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )  
  41.   ZDNwkMgr_event_loop,  
  42. #endif  
  43.   GenericApp_ProcessEvent  
  44. };  
  45.   
  46. const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );  
  47. uint16 *tasksEvents;  
  48.   
  49. /********************************************************************* 
  50.  * FUNCTIONS 
  51.  *********************************************************************/  
  52.   
  53. /********************************************************************* 
  54.  * @fn      osalInitTasks 
  55.  * 
  56.  * @brief   This function invokes the initialization function for each task. 
  57.  * 
  58.  * @param   void 
  59.  * 
  60.  * @return  none 
  61.  */  
  62. void osalInitTasks( void )  
  63. {  
  64.   uint8 taskID = 0;  
  65.   
  66.   tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);  
  67.   osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));  
  68.   
  69.   macTaskInit( taskID++ );  
  70.   nwk_init( taskID++ );  
  71.   Hal_Init( taskID++ );  
  72. #if defined( MT_TASK )  
  73.   MT_TaskInit( taskID++ );  
  74. #endif  
  75.   APS_Init( taskID++ );  
  76. #if defined ( ZIGBEE_FRAGMENTATION )  
  77.   APSF_Init( taskID++ );  
  78. #endif  
  79.   ZDApp_Init( taskID++ );  
  80. #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )  
  81.   ZDNwkMgr_Init( taskID++ );  
  82. #endif  
  83.   GenericApp_Init( taskID );  
  84. }  


其实里面就两样东西是重要的,一个是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做了什么

[cpp] view plain copy
  1. uint8 osal_init_system( void )  
  2. {  
  3.   // Initialize the Memory Allocation System  
  4.   osal_mem_init();  
  5.   
  6.   // Initialize the message queue  
  7.   osal_qHead = NULL;  
  8.   
  9.   // Initialize the timers  
  10.   osalTimerInit();  
  11.   
  12.   // Initialize the Power Management System  
  13.   osal_pwrmgr_init();  
  14.   
  15.   // Initialize the system tasks.  
  16.   osalInitTasks();  
  17.   
  18.   // Setup efficient search for the first free block of heap.  
  19.   osal_mem_kick();  
  20.   
  21.   return ( SUCCESS );  
  22. }  

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

0 0