Zigbee学习(二)之Zstack协议栈运行原理分析

Zigbee协议栈的实现方式采用的是分层的思想,分别有物理层、数据链路层(介质访问控制层)、网络层和应用层。每一层都实现了不同的功能,但是每一层实现的功能对于其它层来说又是封闭的,如果要进行数据互通,需要调用一些API函数。这是一些浅显的基本概念,百度一下都可以知道的啦!那么整个协议栈是如何执行的呢?我们直接来看代码吧!打开Zmain.c文件,之前是一些宏定义,暂时先不用管,看到主函数:

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

 上述代码蓝色部分都是一些宏定义和注释,只要看黑色字体部分就好了,不难发现都是一些初始化操作,直到osal_start_system();这个函数才是真正系统运行的开始,那么我来分析一下这个函数的具体运行机理吧,自己也是学来的,说的不好请见谅哦!

void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop
#endif
  {
    uint8 idx = 0;

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

    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
  }
}

首先,我们可以发现上述代码是个无限循环FOR函数,紧接着的两个函数osaltimeupdate()应该也是初始化定时器吧,HAL_ProcessPoll()是对一些硬件轮询,检查是否发生参数变化之类的,接下来就是一个do...while的循环函数,意思是如果tasksEvents[idx]不为0那么就跳出循环,否则idx自增1,与tasksCnt比较,如果没有超过tasksCnt就继续循环do...while,如果超过了就跳出循环,如果再摸一个idx的循环过程中tasksEvent[idx]非空,则执行下面的代码,将tasksEvents[idx]赋值给events,然后清零,对(tasksArr[idx])( idx, events )求解并将值赋值给events,最后再和tasksEvents[idx]做或运算。那么这整个过程是什么意思呢?我们要来看一下tasksArr[idx]和tasksEvents是如何定义的。首先看tasksArr[idx]:

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
  PuppyApp_ProcessEvent
};

不难发现,这是一个数组,数组的每个元素都是一个函数指针,指向了不同的事件处理函数,函数名即函数首地址。我们再找tasksEvents在哪里定义的,发现osalInitTasks( void )这个osal任务初始化函数中有定义,看一下这个函数的代码:

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
  PuppyApp_Init( taskID );
}

在这个函数中,先定义了一个任务ID号,tasksEvents所指向的地址长度是两个字节,然后使tasksEvents指向一个为任务总数*2个字节大小的空间的首地址,并将空间内容初始化为0,这里就可以知道tasksEvents其实就是指向每个任务事件的指针了。而且不难发现,这个函数中的任务排序和tasksArr[]数组定义的排序是一样的。事实上,当摸个tasksEvents[idx]非空时,就表明有对应该任务的事件要处理,可能是一件,也可能是很多件。然后通过idx在taskArr[idx]中找到相应的事件处理函数进行处理,处理完了之后有这样一句指令return(events^SYS_EVENT_MSG),当然后面的宏定义可能不一样,这是一个异或处理,1^1=0,1^0=1,也就是说SYS_EVENT_MSG这个事件处理完了清零了,剩下的events继续反馈上去,进行下一轮的循环然后处理。

整个协议栈轮询的过程就是这样,是不是很清楚了呢!没清楚也没关系,我会再写一篇按键的小例子帮助理解~!

 

你可能感兴趣的:(PuppyZigbee)