打印

【转】初次接触zstack

[复制链接]
821|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
南国先生|  楼主 | 2017-1-8 12:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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



  • /*********************************************************************
  • * @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做了什么事情

[cpp] view plain copy



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

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

[cpp] view plain copy



  • 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  


相关帖子

沙发
南国先生|  楼主 | 2017-1-8 12:30 | 只看该作者

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

       首先,我们要来说的就是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



  • #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做了什么

[cpp] view plain copy



  • 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。


使用特权

评论回复
板凳
quansea| | 2017-1-8 13:06 | 只看该作者
初次接触!学习学习!!!

使用特权

评论回复
地板
vivilzb1985| | 2017-1-8 21:23 | 只看该作者
这个首先是涉及到操作系统方面的问题,有些复杂的。

使用特权

评论回复
5
vivilzb1985| | 2017-1-8 21:24 | 只看该作者
不过都有对应的文档的,跟着学习额就OK啦,,英文的就慢慢学习的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

160

帖子

3

粉丝