打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
定时器触发事件流程

参考文章:
http://bbs.feibit.com/thread-3420-1-1.html
https://e2e.ti.com/support/wireless_connectivity/f/158/t/189014

以osal_start_timerEx(uint8 taskID, uint16 event_id, uint16 timeout_value)函数为出发点,看看时间到了,事件是怎么被置位的。

OSAL.Timers.c:    osal_start_timerEx(uint8 taskID, uint16 event_id, uint16 timeout_value)    {        .......        newTimer = osalAddTimer( taskID, event_id, timeout_value );        ......    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

函数最核心的就是上面这条语句,猜想z-stack中应该也有一个定时器队列(类似消息队列),这个队列应该是按心跳计时?
——————————————————————————————

OSAL.Timers.c:    osalAddTimer( uint8 task_id, uint16 event_flag, uint16 timeout )    {        newTimer = osalFindTimer( task_id, event_flag );        if ( newTimer )         {             // Timer is found - update it.              newTimer->timeout = timeout;            return ( newTimer );         }      else      {        newTimer = osal_mem_alloc( sizeof( osalTimerRec_t ) );        if ( newTimer )     {      newTimer->task_id = task_id;      newTimer->event_flag = event_flag;      newTimer->timeout = timeout;      newTimer->next = (void *)NULL;      newTimer->reloadTimeout = 0;        if ( timerHead == NULL )      {             timerHead = newTimer;      }        else      {          srchTimer = timerHead;          while ( srchTimer->next )                srchTimer = srchTimer->next;          srchTimer->next = newTimer;      }          return ( newTimer );    }    else      return ( (osalTimerRec_t *)NULL );  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

函数开始先寻找这个定时任务是不是已经存在了,如果存在进入if条件,更新剩余时间值,返回。如果不存在进入else,生成新的定时任务,并填充osalTimerRec_t结构体。
这里还有一个判断定时队列不是空的,如果空的就把这个新生成的定时任务设为头结点;如果队列不空,则遍历队列,找到最后一个结点,把newTimer插到队尾。

——————————————————————————————————

OSAL.Timers.c:    osalFindTimer( uint8 task_id, uint16 event_flag )    {        .......        while ( srchTimer )      {        if ( srchTimer->event_flag == event_flag &&srchTimer->task_id == task_id )          break;    srchTimer = srchTimer->next;  }  return ( srchTimer );}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

由于采用独热码编码,事件编码类型又是uint16的,所以每个任务下可以定义最多15个事件(有一个0x8000是强制事件),“srchTimer->event_flag == event_flag &&srchTimer->task_id == task_id”这一句也能看出定时队列是以事件为节点的。

——————————————————————————————————
说了这么多,还只是说了一个定时事件是怎么插入到定时队列的。对于插入之后时间的更新还没说,时间到了怎么设置事件标志也没说。

我想,既然是定时事件,那么事件的时间肯定要倒计时的,倒计时应该出现在一个循环中,自然而然想到了osal_run_system( void )。进入找找看。
  • 1
  • 2

—————————————————————————————————

OSAL_Clock.c:    在osal_run_system()中有osalTimeUpdate( )    {        ......        tmp = macMcuPrecisionCount();          if ( tmp != previousMacTimerTick )       {         ticks320us = (tmp - previousMacTimerTick) & 0xffffffffu;  //两次运行间隔        previousMacTimerTick = tmp;         tmp = (ticks320us * 8) + remUsTicks;       CONVERT_320US_TO_MS_ELAPSED_REMAINDER( tmp, elapsedMSec, remUsTicks );        if ( elapsedMSec )       {          osalClockUpdate( elapsedMSec );          osalTimerUpdate( elapsedMSec );       }     }   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

tmp为计数器,函数返回的是溢出次数,每次溢出的单位是320us,就是说tmp值记录了每一次调用这个函数时候timer2计数器经过了多少次320us。
只要系统不是刚上电运行,if的判断语句就为真,因为tmp随着系统运行不断变大的(没搞懂什么时候溢出?)两值相减得出了两次运行到这里的心跳差。
把tmp赋值给previousMacTimerTick ,用来进行下一次运行到这里的比较。
接下来代码的解释参考http://bbs.feibit.com/thread-3420-1-1.html的解释,里面非常清楚。
经过CONVERT_320US_TO_MS_ELAPSED_REMAINDER这个宏定义之后,将上次运行之后经过的时间保存到elapsedMSec中(单位是ms)。

——————————————————————————————————

OSAL_Timers.c:    osalTimerUpdate( uint16 updateTime )    {        ......        if ( timerHead != NULL ) //如果定时队列不空     {        srchTimer = timerHead; //把队列头结点赋值      prevTimer = (void *)NULL;        while ( srchTimer )    {      osalTimerRec_t *freeTimer = NULL;  //生成一个自由定时器,用来保存剩余时间为0的节点        ......      if (srchTimer->timeout <= updateTime) //剩余时间小于已经经过的时间      {        srchTimer->timeout = 0;      }      else  //剩余时间大于经过时间的则减去经过时间      {        srchTimer->timeout = srchTimer->timeout - updateTime;      }      if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag) )      {               osal_set_event( srchTimer->task_id, srchTimer->event_flag );               srchTimer->timeout = srchTimer->reloadTimeout;      }     // 这个函数很有意思,前面被置0的任务不是在这里被osal_set_event的,因为osal_start_timerEx()里面的osalAddTimer()的函数体里面有newTimer->reloadTimeout = 0。意思就是说每个加到定时器队列的节点的reloadTimeout值都是0,那么肯定进不去这个if语句,那这个语句要来干嘛?(估计是有其他层,里面会改动这个值,但我还没看到)     ```if ( srchTimer->timeout == 0 || srchTimer->event_flag == 0 )      {        if ( prevTimer == NULL ) //如果删除的是头结点             timerHead = srchTimer->next;        else   //删除的不是头结点             prevTimer->next = srchTimer->next;       freeTimer = srchTimer; //保存“定时时间到”的节点       srchTimer = srchTimer->next; //往下一个节点走,这样才能遍历完整个队列      }else  //更新了之后剩余时间不为0      {        prevTimer = srchTimer;        srchTimer = srchTimer->next;      }  if ( freeTimer ) //这里才是osal_set_event()的地方      {        if ( freeTimer->timeout == 0 )        {          osal_set_event( freeTimer->task_id, freeTimer->event_flag );        }//为什么要加这个if呢,因为如果一轮遍历下来都没有时间为0的事件,那么开头生成的结构体就要释放,否则内存会挤满        osal_mem_free( freeTimer );      }   }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

这样子的话,主循环每次进入osalTimeUpdate( )就是更新队列里面的节点的时间,实现了定时任务的倒计时。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Z-Stack中OSAL定时器事件触发流程分析
系统时钟定时器
将TIzigbee开源协议栈中的OS操作系统移植出来,放在STC12C60S2中使用
ZIGBEE电源管理POWER_SAVING有关的函数
Zstack OSAL详解
wait_event_interruptible_timeout和schedule_timeout区别
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服