开始学习zigbee已有一周时间了,其实自从zigbee开发板买来之后,就星星点点的在看,只是方法不对一下子陷入进了代码和官方协议栈的原理中,一时摸不着头脑。前几天由于项目的需要,又开始研究zigbee,这次我开始从全局出发,才渐渐有了眉目。

首先,我对于zigbee官方协议栈的osal的流程进行了理解,当然这里得感谢“雪帕”的博文,以及看过的一篇论文《Zstack OSAL详解》,给了我很大的启示,除此之外还得提到一个大牛:小峰,他的博文分析,十分的详细,不懂时可以参考参考,很有启发。

下面,我就一些os的运行机制,进行一个简要的说明,因为我觉得只有理解了os的机制,才能开始后继的理解,才能有点眉目。

接下来先介绍几个术语:

任务:以我的理解,任务就是提交给os需要处理的需求,一个任务在执行之间必须首先添加,并且相应的任务处理也得进行注册任务id进行绑定,这样在事件触发时才能根据任务id找到对应的任 务处理函数,进行相应的处理。

事件:一个任务可以有16个事件,采用十六位的编码,其中SYS_EVENT_MSG已被定义为0x8000,每个事件采用热独码进行编码,即每一位代表一个时间,当该位置位时说明有相应的事件发生,同时这样便于提取事件,如if(events & SYS_EVENT_MSG){ code   },函数传进来的事件event与已经定义好的SYS_EVENT_MSG进行按位相与,结果非零时进入分支处理代码进行相应的处理。return (events ^ SYS_EVENT_MSG);这句话就可以清除掉该事件位标志。

消息:每个事件可以有256个消息,每个消息可通过osal_set_event()设置,或通过osal_msg_receive()接受别的任务发过来的消息。例如:下面几个消息是系统事件SYS_EVENT_MSG已经定义好的,在用时可以复制到自己的程序中使用。

AF_INCOMING_MSG_CMD:用来指示接收到的AF信息。
KEY_ CHANGE:用来确认按键动作。
ZDO_ NEW_ DSTADDR:用来指示自动匹配请求。
ZDO_STATE_CHANGE:用来指示网络状态的变化

大家都知道,可以称为os的一般都是多任务进行的,那么zigbee的os是如何运行的呢?

os是轮询式的操作系统,它每隔1ms就开始对添加的任务进行轮询,这里维持了一个事件表tasksEvents[idx],若有任务的事件置位时,则转入相应的处理函数进行处理。

这里是通过idx标志找到对应的事件处理函数的(因为之前添加时将处理函数与任务id进行的绑定)

以Sample.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();  // 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_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 );

}

接下来初始化任务

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  

SampleApp_Init( taskID );//初始化用户添加的任务

}

之前对事件处理函数进行了定义

// The order in this table must be identical to the task initialization calls below in osalInitTask.

//注意这里保存的是任务处理函数的函数地址,这里的任务的顺序必须和初始化任务时的顺序一致,其实也就是将任务id与具体的任务处理函数绑定在了一起,通过任务id就可以调用具体的任务处理函数。

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  

SampleApp_ProcessEvent //用户定义的任务对应的事件处理函数

};

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );//计算任务的个数,根据个数分配空间

uint16 *tasksEvents;//定义任务处理事件表

这样就添加了任务,并将任务事件处理函数与任务通过id建立了对应关系。

然后进入事件轮询式操作系统

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  

 }

}

至此对于os的机制进行了简要的分析,可能有些地方说的不太恰当,还望见谅。。

posted on 2013-03-21 11:24  阑珊寻梦  阅读(360)  评论(0编辑  收藏  举报