开始学习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的机制进行了简要的分析,可能有些地方说的不太恰当,还望见谅。。