查看: 5530|回复: 3

Z-Stack操作系统的一些理解

[复制链接]
小猴子872 发表于 2013-5-14 09:59:39 | 显示全部楼层 |阅读模式
Z-Stack操作系统

       学习ZigBee有两个月了,学习期间也走了不少弯路,刚开始调试了几个LED小灯的实验,串口通信实验,点对点通信实验,以为这样基本就差不多可以做定位系统了,于是直接跳到定位这一块,实际上远没有那么简单。我想很多初学者都是打开协议栈就被左边那一列给镇住了,看到那么多代码都不知道从何入手,下面我重点介绍一下关于ZigBee协议栈操作系统的原理,让更多初学者能看清Z-Stack操作系统(其实只是一个简单的小系统,看明白了觉得也没有多复杂)的工作过程。
       下面的图片是我根据书上的资料自己绘制出来的,从这个图中可以看到Z-Stack的整个系统的工作流程。
   [attachimg]2938
Z-Stack操作系统
       似乎这个对于初学者来说也看不出什么道道来,我在看代码的时候完全不知道从哪里看起。即使找到了主函数,找到了OSAL_start_system()也不知道他到底是怎么运行的。首先我们先好好看一些这个微操作系统的工作流程:在ZMain主函数当中,基本上都是一些初始化函数,从中断、系统时钟、堆栈等等到最后按键、液晶显示初始化,这个对于我们来说基本上不用看,只需大致了解其功能即可,就像在电脑上编程只需了解软件和底层硬件的接口一样。在初始化函数执行完以后便进入了osal_start_system()函数,开始OSAL操作系统。OSAL操作系统里面有七个任务,该循环轮询查询每个任务是否有需要处理的事件,如果有则处理,没有则跳到下一个任务,这七个任务有不同的优先级,从图中可以看出MAC层拥有最高的优先级,MAC层如果有任务,则下面的任务不会被处理。
       好了,基本上对于该操作系统有了一个简单的了解以后,我们再来结合代码看看代码到底是怎么运行的。
       先大致浏览一下协议栈的目录,可以看到有ZMain文件夹(如下乳所示),这个应该就是主函数,看了很多资料确定了确实是从这里开始运行的。

       打开ZMain.c,找到ZSEG int main( void )函数,函数内容如下:
ZSEG int main( void )
{

// Turn off interrupts
osal_int_disable( INTS_ALL );
  // Initialize HAL
  HAL_BOARD_INIT();
  // Make sure supply voltage is high enough to run
  zmain_vdd_check();
  // Initialize stack memory
  zmain_ram_init();
  // Initialize board I/O
  InitBoard( OB_COLD );
  // Initialze HAL drivers
  HalDriverInit();
  // Initialize NV System
  osal_nv_init( NULL );
  // Determine the extended address
  zmain_ext_addr();
  // Initialize basic NV items
  zgInit();
  // Initialize the MAC
  ZMacInit();
#ifndef NONWK
  // Since the AF isn't a task, call it's initialization routine
  afInit();
#endif
#ifdef LCD_SUPPORTED
  HalLcdInit();
#endif
    // Initialize the operating system
  osal_init_system();
  // Allow interrupts
  osal_int_enable( INTS_ALL );
  // Final board initialization
  InitBoard( OB_READY );
  //HalLcdInit();
  // Display information about this device
  zmain_dev_info();
  /* Display the device info on the LCD */
#ifdef LCD_SUPPORTED
  zmain_lcd_init();
#endif
  osal_start_system(); // No Return from here
} // main()


       大致看一下,和上述图中的初始化基本上一样。功能描述都换做了绿色字体以便查看,这些英文不是很难,大都可以看懂什么意思我就不再标注了,实在不懂可以看上边图片,有具体解释。
       函数最后是  osal_start_system(); // No Return from here开始OSAL操作系统,并且标注了这里没有返回,也就是说在OSAL操作系统里面会一直永无止境的执行下去知道系统停止工作。那么osal_start_system()这个函数在哪呢?一般习惯好的话看程序就知道什么意思,更何况是那么大的一个公司,在函数前面有一个osal,我们就顺着osal找下去。查看协议栈会发现有一个OSAL文件夹,那么函数很有可能就在这里面。如下图:

       在OSAL里面仔细查找可以找到这个函数,具体如下:
void osal_start_system( void )
{
#if !defined ( ZBIT )
  for(;;)  // Forever Loop
#endif
  {
    uint8 idx = 0;
    Hal_ProcessPoll();  // This replaces MT_SerialPoll() and osal_check_timer().
    do {
      if (tasksEvents[idx])  // Task is highest priority that is ready.
      {
        break;
      }
} 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);
      events = (tasksArr[idx])( idx, events );   //通过指针调用来执行对应的任务处理函数
//进入/退出临界区,保存尚未处理的事件
          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
    }
}
       操作系统专门分配了存放所有任务事件的tasksEvents[]这样一个数组,每一个单元对应存放着每一个任务的所有事件。在这个函数中首先通过do-while来找出这个任务事件数组当中具有优先级最高的事件,得到该事件的idx,通过events = (tasksArr[idx])( idx, events );这一函数来得到事件的指针地址,最后对事件进行处理。那么这样来说我们只需要知道这个tasksEvents里面任务都是什么那么这个操作系统就相当明了了。

       一般在协议栈当中都会有例子程序,我们打开其中一个GenericApp,路径如图所示。
       接下来打开OSAL_GenericApp.c,该文件是应用层和OSAL操作系统互动的一个文件,这里面没有多少代码,轻易地就可以发现其中的const pTaskEventHandlerFn tasksArr[],具体如下:


const pTaskEventHandlerFn tasksArr[] = {
  macEventLoop,        //MAC层任务处理函数
  nwk_event_loop,       //网络层任务处理函数
  Hal_ProcessEvent,      //板硬件抽象层任务处理函数
#if defined( MT_TASK )     //如果定义了MT_TASK则扫描该处理函数
  MT_ProcessEvent,        //调试任务处理函数,可选
#endif
  APS_event_loop,           //应用层任务处理函数,用户不要更改
  ZDApp_event_loop,     //ZigBee设备应用层任务处理函数,用户可根据需要更改
  GenericApp_ProcessEvent      //用户应用层任务处理函数,用户自己生成
};
(注:有些初学者不明白#if defined( MT_TASK )--- #endif是什么意思,在此说明一下,这就是一个判断语句,如果定义了MA_TASK则执行该语句,在哪里定义呢,打开Project---Option,如下图所示,如果在Defined  symbols这个框中定义了MT_TASK 则执行。其他的同)
       结合刚开始的架构图,可以看出操作系统循环扫描tasksArr[]中的七个任务,有任务则处理,而我们需要自己设定的就是GenericApp_ProcessEvent这个函数。
       说明一点,Z-Stack操作系统就是这个构架,基本上就是这个模式,代码不会有太大出入,不信可以多找几个例子按照上述顺序看下来,基本都一样。
       这下就知道了我们到底要在什么地方写程序了,打开GenericApp.c找到GenericApp_ProcessEvent这个函数,我们来看看里面到底有什么。


其中的代码我先不贴上来,先说一下GenericApp_ProcessEvent这个函数的整体框架,了解了这个以后再看这个函数就非常容易了。

UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
  ………………
  if ( events & SYS_EVENT_MSG )        //系统消息事件
  {
    ………………
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        case ZDO_CB_MSG:                //ZDO的反馈信息
………………
        case KEY_CHANGE:                //按键事件
              ………………
        case AF_DATA_CONFIRM_CMD:       //AF数据确认
         ………………
        case AF_INCOMING_MSG_CMD:       //AF信息输入
         ………………
        case ZDO_STATE_CHANGE:           //ZDO状态改变
         ………………
              case ZDO_MATCH_DESC_RSP_SENT:    //ADO匹配描述符相应
              ………………
              case SAPICB_DATA_CNF:              //发送数据确认
              ………………
        default:
         ………………
      }
………………
    }
    return (events ^ SYS_EVENT_MSG);     //返回未处理的事件
  }

if ( events & ZB_ALLOW_BIND_TIMER )    //允许绑定时间事件
………………
if ( events & ZB_BIND_TIMER )    //绑定时间事件
………………
if ( events & ZB_ENTRY_EVENT )   
………………
  if ( events & GENERICAPP_SEND_MSG_EVT )    //用户自定义事件
  {
   ………………
  }
………………
  return 0;
}
这个函数的意思非常明了,如果有按键,则执行case KEY_CHANGE:下边的代码,如果有消息接收,则执行case AF_INCOMING_MSG_CMD:,其他的都是这样,因为这里是将操作系统构架,所以不再详细讲解过多代码的作用(其实这么多代码我也不是很懂,大致知道常用的就行,需要用到那个在具体查阅),如果用户自定义事件有消息产生,则执行规定的事件。
       基本上Z-stack操作系统就是这个构架,看明白了其实觉得这个操作系统其实也挺微小的,和Windows比起来确实没法比,不过这对于初学者足够头痛了。GenericApp_ProcessEvent里面的代码我就不具体分析了,整个操作系统就是这样一个模式,没什么出入,看不明白多看几遍,我当初就看了十几遍才稍微了解了点,对于讲解中有什么错误大家多多指点。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
 楼主| 小猴子872 发表于 2013-5-14 10:01:43 | 显示全部楼层
第一次发,图片没有显示出来,带上附件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
luodanoo 发表于 2013-7-25 11:26:33 | 显示全部楼层
顶一个
ranl1988 发表于 2013-7-31 11:01:16 | 显示全部楼层
顶一个!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表