09 事件驱动的OSAL简要分析

1、应用层是一个任务,它有一个系统分配给他的数值唯一的编号叫任务ID
2、任务可以处理事件,处理事件的这些代码都在一个函数里,这个函数叫任务事件处理函数
3、应用层任务还有一个 2个字节的变量 —任务事件变量

4、应用层任务事件变量 和 应用层定义的事件的关系,如果事件变量和某个事件的宏值(该宏定义事先定义好)与操作为1,那么表示应用层任务将要处理这个事件。对应SimonApp_ProcessEvent函数!

5、而系统在运行的时候会不断的去读应用层任务事件变量,当它发现这个变量为0就认为,应用层任务当前没有事件需要去处理,如果发现这个变量不为0,它就认为应用层任务有事件将要去处理,它就会去调用应用层任务事件处理函数UINT16 SimonApp_ProcessEvent( byte task_id, UINT16 events ),并且把任务事件变量的值传给events;在这个事件处理函数里,events;会分别和应用层定义的所有事件宏值进行与操作,如果发现那个不为0,那么就去执行这个事件处理的相应代码。对应如下代码:

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

6、任务事件处理函数是一个数组,程序员提前定义好!
在OSAL_SimonApp.c中,const pTaskEventHandlerFn tasksArr[]数组是一个函数指针数组!一般应用层的任务事件处理函数指针添加在末尾,下标显然是8,一般来说整个函数指针数组有9个元素!

// The order in this table must be identical to the task initialization calls below in osalInitTask.
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
  SimonApp_ProcessEvent
};

7、任务数常量和任务事件变量
虽然任务事件处理函数指针数组确定好了,但是任务事件变量数组还没有定义,所以需要定义一个事件变量数组(或者动态内存分配),但是在定义数组的时候,需要指定要分配的内存大小(元素个数),根据函数指针数组tasksArr确定需要多少个元素,然后再分配相应的内存空间!对应OSAL_SimonApp.c中如下代码:

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
uint16 *tasksEvents;

以及

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

8、osal_set_event(SimonApp_TaskID,SimonApp_SEND_MSG_EVT);
为什么调用上面的设置任务事件函数,SimonApp_TaskID就会去执行SimonApp_SEND_MSG_EVT事件相应的处理代码。
这个函数的本质是,把SimonApp_TaskID(应用层任务)的任务事件变量中对应于SimonApp_SEND_MSG_EVT宏值为1的那个位变成1,这样的话首先这个任务事件变量就变成了非0,系统在检测到任务事件变量为非0,就会去调用任务事件处理函数SimonApp_ProcessEvent,在这个函数里,任务事件变量肯定和SimonApp_SEND_MSG_EVT宏值与操作为1,所以必定会执行处理这个事件相关的代码。

9、几乎每一个层都是一个任务,那么每一个层都有1个任务ID、 任务事件处理函数 、 任务事件变量。

UN函数数组={任务事件处理A,任务事件处理B,任务事件处理C..}

Arr变量数组={任务事件变量a,任务事件变量b,任务事件变量c..}
任务ID系统不是随便分配,我们可以通过这个值立即找到这个任务自己的任务事件处理函数和事件变量。
对应关系是:FUN[0]<—> Arr[0]

应用层任务的任务ID是8。
FUN[8]<—–> Arr[8]
tasksArr[8]就是我们应用层事件处理函数
tasksEvents[8]就是我们应用层事件变量

10、关注2个函数
(1)osal_init_system,在这个函数里的osalInitTasks,系统给所有任务分配任务ID.

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

(2)osal_start_system();

所以ZSTACK协议栈在稳定工作时,它行为是

for(;;)
{

}
死循环里,不断去读所有任务的任务事件变量,如果发现所有任务的任务事件变量都为0,没问题,说明所有任务都没有事件将要去处理,再次重逢这个过程,直到发现某个任务事件变量不为0,就会通过不为0的这个任务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
  }
}

你可能感兴趣的:(ZigBee)