Z-STACK 学习 -- 事件处理的流程

     上篇我们说了协议栈运行的流程,这篇我们看下事件在协议栈中是怎样被处理的。

      处理事件有一个很重要的函数,就是 events = (tasksArr[idx])( idx, events ) ,乍一看这只是一个数组,其实tasksArr是一个指向数组的指针,当然我们也可以把 tasksArr[] 看成一个数组。在这个数组中存放的是所有的任务处理函数的入口,双击tasksArr按F12进入后可以看到以下的这段程序:

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
  zcl_event_loop,
  zclSampleTemperatureSensor_event_loop //用户自定义的任务处理函数,是我们自己写应用的地方
};

     从这里来调用各个层的任务处理函数,其中我们可以看到 events = (tasksArr[idx])( idx, events ) 这句中的数组 tasksArr[idx] 有一个索引号idx,这个索引号决定了调用第几个任务处理函数,比如 idx = 1,那么调用的就是  macEventLoop 这个任务处理函数。那么问题来了,这个索引号是怎么来的呢? 这段程序的下方还有一段程序:

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
  zcl_Init( taskID++ );
  zclSampleTemperatureSensor_Init( taskID );
}

     这段程序的意义是,为每个任务都打上了一个任务号,这个任务号 taskID 和 idx 是对应的,在各层的初始化中吧每个任务处理函数的任务号保存下来。任务号的数值越小,处理的优先级越高(初始化只进行一次,所以任务号的固定不变的)。其中的这段程序

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

     为 tasksEvents[] 这个数组分配了动态内存,大小等于任务的个数,并且把数组中的元素初值赋值为0。

     到此,我们了解了 events = (tasksArr[idx])( idx, events ) 中的 tasksArr[] 数组和 索引号 idx 。还有一个量没有看,那就是events。 上偏中我们提到了一段程序如下:

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

    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );
    activeTaskID = TASK_NO_TASK;

    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }

   这里要注意的是事件数组 tasksEvents[idx] 一共有16位,每一位用来表示一个事件,其中 0x8000 表示的是 SYS_EVENTS_CMD ,是系统消息,剩余的15位可以由我们用户定义。

     从上面的一段程序中可以看到 events = tasksEvents[idx] ,也就是说 events 的值就是事件数组中的值。OK,我们知道了 events = (tasksArr[idx])( idx, events ) 中 events 的值是从 events = tasksEvents[idx]得到的,那么 tasksEvents[idx] 的值是从哪里得到的呢?

     我们来看下面的几段程序:

uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )
{
  /*....省略...*/
  return ( osal_msg_enqueue_push( destination_task, msg_ptr, FALSE ) );
}
static uint8 osal_msg_enqueue_push( uint8 destination_task, uint8 *msg_ptr, uint8 push )
{
  /*....省略...*/
  // Signal the task that a message is waiting
  osal_set_event( destination_task, SYS_EVENT_MSG );
  return ( SUCCESS );
}
uint8 osal_set_event( uint8 task_id, uint16 event_flag )
#endif /* OSAL_PORT2TIRTOS */
{

  if ( task_id < tasksCnt )
  {
    halIntState_t   intState;
    HAL_ENTER_CRITICAL_SECTION(intState);    // Hold off interrupts
    tasksEvents[task_id] |= event_flag;  // Stuff the event bit(s)
    HAL_EXIT_CRITICAL_SECTION(intState);     // Release interrupts

#ifdef USE_ICALL
    ICall_signal(osal_semaphore);
#endif /* USE_ICALL */
    return ( SUCCESS );
  }
   else
  {
    return ( INVALID_TASK );
  }
}

     进过一系列的调用之后,我们看到了这样一条语句 tasksEvents[task_id] |= event_flag 这就是对 tasksEvents[task_id]的赋值。也就是说调用 osal_msg_send() 这个函数可以对 tasksEvents[task_id] 赋值。当然我们还有其他的办法,那就是调用函数osal_start_timerEx()(最终也是调用了osal_set_event()函数,这个之后的应用中会用到)。

     上述的函数  osal_msg_send( uint8 destination_task, uint8 *msg_ptr ) 有两个参数,分别为目标任务的ID,和指向消息的指针。它的功能是向一个任务发送消息(我们后面来说处理消息的程序)。此外,这个函数会触发目标任务的SYS_EVENT_MSG(系统消息任务),这也方便了对消息的处理。

     下篇我们来做一个实验,具体一个用户自定义事件的调用。

 

你可能感兴趣的:(ZIGBEE)