任务处理表tasksEvents是怎么被改动的及zigbee协议栈分析

      任务处理表taskEvents的处理有几种方式,记录下来完了可以来翻阅,哈哈。。。。

总的来说,添加任务都是通过OSAL.C》》uint8 osal_set_event( uint8 task_id, uint16 event_flag )添加的,那么在什么地方可以触发这个呢?

一、设置计时器,当其溢出时,触发事件处理

      首先任何程序都是从main函数开始的::

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 );             //初始化 I/O , LED 、 Timer 等

  // Initialze HAL drivers
  HalDriverInit();                  //初始化芯片各硬件模块

  // Initialize NV System
  osal_nv_init( NULL );             // 初始化 Flash 存储器

  // Initialize the MAC
  ZMacInit();                       //初始化 MAC 层

  // Determine the extended address
  zmain_ext_addr();                 //确定 IEEE 64 位地址

#if defined ZCL_KEY_ESTABLISH
  // Initialize the Certicom certificate information.
  zmain_cert_init();
#endif

  // 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_start_system(); ------转----osal_run_system();
/*********************************************************************
 * @fn      osal_run_system
 *
 * @brief
 *
 *   This function will make one pass through the OSAL taskEvents table
 *   and call the task_event_processor() function for the first task that
 *   is found with at least one event pending. If there are no pending
 *   events (all tasks), this function puts the processor into Sleep.
 *
 * @param   void
 *
 * @return  none
 */
 
void osal_run_system( void )
{
  uint8 idx = 0;

  osalTimeUpdate();        //该文重要地方,在这里扫描那个时间被触发,并置相应位
  Hal_ProcessPoll();

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;                //得到待处理的最高优先级任务索引号 idx
    }
  } 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);    // 退出临界区

    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);    // 退出临界区
  }
#if defined( POWER_SAVING )
  else  // Complete pass through all task events with no activity?
  {
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  {
    osal_task_yield();
  }
#endif
}
    进入函数:osalTimeUpdate();------转--------osalTimerUpdate( elapsedMSec );
    第二个方式也从这里开始,events = (tasksArr[idx])( idx, events );进入tasksArr[idx]列表中
/*********************************************************************
 * @fn      osalTimerUpdate
 *
 * @brief   Update the timer structures for a timer tick.
 *
 * @param   none
 *
 * @return  none
 *********************************************************************/
 
void osalTimerUpdate( uint16 updateTime )
{
  halIntState_t intState;
  osalTimerRec_t *srchTimer;
  osalTimerRec_t *prevTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  // Update the system time
  osal_systemClock += updateTime;
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  // Look for open timer slot
  if ( timerHead != NULL )
  {
    // Add it to the end of the timer list
    srchTimer = timerHead;
    prevTimer = (void *)NULL;

    // Look for open timer slot
    while ( srchTimer )
    {
      osalTimerRec_t *freeTimer = NULL;
     
      HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
      
      if (srchTimer->timeout <= updateTime)
      {
        srchTimer->timeout = 0;
      }
      else
      {
        srchTimer->timeout = srchTimer->timeout - updateTime;
      }
      
      // Check for reloading
      if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag) )
      {
        // Notify the task of a timeout
        //就在这里了,那么他是怎么触发的呢?
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );
        
        // Reload the timer timeout value
        srchTimer->timeout = srchTimer->reloadTimeout;
      }
      
      // When timeout or delete (event_flag == 0)
      if ( srchTimer->timeout == 0 || srchTimer->event_flag == 0 )
      {
        // Take out of list
        if ( prevTimer == NULL )
          timerHead = srchTimer->next;
        else
          prevTimer->next = srchTimer->next;

        // Setup to free memory
        freeTimer = srchTimer;

        // Next
        srchTimer = srchTimer->next;
      }
      else
      {
        // Get next
        prevTimer = srchTimer;
        srchTimer = srchTimer->next;
      }
      
      HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
      
      if ( freeTimer )
      {
        if ( freeTimer->timeout == 0 )
        {
            //就在这里了,那么他是怎么触发的呢?
          osal_set_event( freeTimer->task_id, freeTimer->event_flag );
        }
        osal_mem_free( freeTimer );
      }
    }
  }
}
    从上面看,似乎找到了源头,那么怎么才能触发呢?那么就得介绍一个函数了:OSAL_Timers.c》》uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
/*********************************************************************
 * @fn      osal_start_timerEx
 *
 * @brief
 *
 *   This function is called to start a timer to expire in n mSecs.
 *   When the timer expires, the calling task will get the specified event.
 *
 * @param   uint8 taskID - task id to set timer for
 * @param   uint16 event_id - event to be notified with
 * @param   UNINT16 timeout_value - in milliseconds.
 *
 * @return  SUCCESS, or NO_TIMER_AVAIL.
 */
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
  halIntState_t intState;
  osalTimerRec_t *newTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

  // Add timer----------------------------------------------------------
  newTimer = osalAddTimer( taskID, event_id, timeout_value );
    //-------------------------------------------------------------------
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}
      在这个函数中,它会开始一个timeout_value(ms)的计时器,当这个计时器溢出时,则会对taskID这个task,设置一个event_id,让这个任务在后面的主循环中运行到,但是是怎么实现的呢?还是要请osalTimerUpdate来帮忙。。。
     这个就总结到这吧,其实后面我也不是很懂,看的迷迷糊糊的,在后面我会帖上出处,,,
二、直接通过任务间的消息传递机制触发(以按键为例)
      本文前面有介绍从哪里进入,,,,events = (tasksArr[idx])( idx, events );进入tasksArr[idx]列表中
      然后进入函数:Hal_ProcessEvent,可以找到检查按键的函数:HalKeyPoll();
/**************************************************************************************************
 * @fn      HalKeyPoll
 *
 * @brief   Called by hal_driver to poll the keys
 *
 * @param   None
 *
 * @return  None
 **************************************************************************************************/
void HalKeyPoll (void)
{
  uint8 keys = 0;

  if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))  /* Key is active HIGH */
  {
    keys = halGetJoyKeyInput();  //判断键值
  }

  /* If interrupts are not enabled, previous key status and current key status
   * are compared to find out if a key has changed status.
   */
  if (!Hal_KeyIntEnable)
  {
    if (keys == halKeySavedKeys)
    {
      /* Exit - since no keys have changed */
      return;
    }
    /* Store the current keys for comparation next time */
    halKeySavedKeys = keys;
  }
  else
  {
    /* Key interrupt handled here */
  }

  if (HAL_PUSH_BUTTON1())
  {
    keys |= HAL_KEY_SW_6;
  }
  
    //在HalKeyPoll函数中,无论按键是ADC方式,或者是扫描IO口的方式,
    //最后都会生成一个键值keys, 然后通过下面的语句来调用按键服务程序
  /* Invoke Callback if new keys were depressed */
  if (keys && (pHalKeyProcessFunction))
  {
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
  }
}
          (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);这句话我刚开始看起来很奇怪,后来看懂了作者的意思,原来在主函数初始化InitBoard( OB_READY );中有这么一个函数:HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);进入这个函数可以看到
<span style="font-size:14px;">void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
{
  /* Enable/Disable Interrupt or */
  Hal_KeyIntEnable = interruptEnable;

  /* Register the callback fucntion */
  pHalKeyProcessFunction = cback;
  。。。。。。。。
}</span>
         这就间接的把pHalKeyProcessFunction初始化成OnBoard_KeyCallback了;接下来的事就让OnBoard_KeyCallback完成了,等哈继续往下面看。。。。。。
         在void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)上面有个函数void HalKeyInit( void )里面有句   pHalKeyProcessFunction  = NULL;我瞬间就看不懂了,,,后来才发现这两个函数都优先级不一样。。。
         接着往下看,让OnBoard_KeyCallback完成了,那么就进入OnBoard_KeyCallback会发现有这么个判断语句if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )直接深入OnBoard_SendKeys就可以发现osal_msg_send向上级应用程序发送消息的
         额,我的记录就到这了,本文只代表个人观点,出错概不负责,不过也希望看到这里的朋友评价其中的错误或者你的更高深的理解,附录:http://bbs.feibit.com/thread-16-1-1.html
           修改,最近在网上看到一个比较好的文章,他直接用图片的形式展示出来了, http://wenku.baidu.com/view/ef12e01d10a6f524ccbf85fb.html   如果资料被删除,请联系我,我这里有备份。。。。。
 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值