zoukankan      html  css  js  c++  java
  • The brief analysis of ZIGBEE OS mechanism ——开始学习zigbee

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

  • 相关阅读:
    Oracle存储过程 一个具体实例
    quartz定时格式配置以及JS验证
    day10_多进程、协程
    day10_锁、守护进程
    day10_单线程和多线程下载文件
    day10_多线程把六个网站写到文件里
    day10_主线程等待子线程的两种方式
    day10_修改父类的构造方法(不重要)和鸭子类型
    day10_hasattr和getattr、setattr、delattr和property的用法
    pycharm professional2019.1破解过程
  • 原文地址:https://www.cnblogs.com/ltfbk/p/zigbee_os_analysis.html
Copyright © 2011-2022 走看看