Contiki内核是基于事件驱动和Protothreads机制,事件既可以是外部事件(比如按键,数据到达),也可以是内部事件(如时钟中断)。定时器的重要性不言而喻,Contiki提供了5种定时器模型,即timer(描述一段时间,以系统时钟滴答数为单位),stimer(描述一段时间,以秒为单位),ctimer(定时器到期,调用某函数,用于Rime协议栈),etimer(定时器到期,触发一个事件),rtimer(实时定时器,在一个精确的时间调用函数)。

  鉴于etimer在Contiki使用的广泛性,管理这些etimer由系统进程etimer_process管理,本小节详细简单介绍etimer相关技术细节。

etimer组织结构

  etimer作为一类特殊事件存在,也是跟进程绑定。除此之外,还需要变量描述定时器属性,etimer结构体如下:

  1. /**
  2. * A timer.
  3. *
  4. * This structure is used for declaring a timer. The timer must be set
  5. * with etimer_set() before it can be used.
  6. *
  7. * \hideinitializer
  8. */
  9. struct etimer {
  10. struct timer timer; //包含起始时刻和间隔两成员变量
  11. struct etimer *next; //指向下一个etimer
  12. struct process *p;
  13. };
  1. /**
  2. * A timer.
  3. *
  4. * This structure is used for declaring a timer. The timer must be set
  5. * with timer_set() before it can be used.
  6. *
  7. * \hideinitializer
  8. */
  9. struct timer {
  10. clock_time_t start;
  11. clock_time_t interval;
  12. };

  成员变量timer用于描述定时器属性,包含起始时刻及间隔,将起始时刻与间隔相加与当前时钟对比,便可知道是否到期。变量p指向所绑定的进程(p为NULL则表示该定时器与所有进程绑定)。成员变量next,指向下一个etimer,系统所有etimer被链接成一个链表,链表头是timerlist,如下图所示:

  1. static struct etimer *timerlist;

 

添加etimer

  定义一个etimer结构体,调用etimer_set函数将etimer添加到timerlist,函数etimer_set流程图如下:

  1. void
  2. etimer_set(struct etimer *et, clock_time_t interval)
  3. {
  4. timer_set(&et->timer, interval);//设置起始时刻和时间间隔
  5. add_timer(et);//将etimer添加到timerlist
  6. }
  7. /**
  8. * Set a timer.
  9. *
  10. * This function is used to set a timer for a time sometime in the
  11. * future. The function timer_expired() will evaluate to true after
  12. * the timer has expired.
  13. *
  14. * \param t A pointer to the timer
  15. * \param interval The interval before the timer expires.
  16. *
  17. */
  18. void timer_set(struct timer *t, clock_time_t interval)
  19. {
  20. t->interval = interval; //设置时间间隔
  21. t->start = clock_time(); //设置起始时刻
  22. }
  23. static void add_timer(struct etimer *timer)
  24. {
  25. struct etimer *t;
  26.  
  27. etimer_request_poll();//提升etimer系统进程的优先级
  28.  
  29. if(timer->p != PROCESS_NONE) {//该etimer处理过
  30. for(t = timerlist; t != NULL; t = t->next) {
  31. if(t == timer) {
  32. /* Timer already on list, bail out. */
  33. /*此etimer已经在etimer链表中*/
  34. timer->p = PROCESS_CURRENT();//将现有进程赋给此etimer的进程
  35. update_time();
  36. return;
  37. }
  38. }
  39. }
  40.  
  41. /* Timer not on list. */
  42. /*此etimer不在etimer链表中,放到etimer链表表头*/
  43. timer->p = PROCESS_CURRENT();
  44. timer->next = timerlist;
  45. timerlist = timer;
  46.  
  47. update_time();
  48. }

  etimer_set首先设置etimer成员变量timer的值(由timer_set函数完成),即用当前时间初始化start,并设置间隔interval,接着调用add_timer函数,该函数首先将管理etimer系统进程etimer_process优先级提升,以便定时器时间到了可以得到更快的响应。接着确保欲加入的etimer不在timerlist中(通过遍历timerlist实现),若该etimer已经在etimer链表中,则无须将etimer加入链表,仅更新时间。否则将该etimer插入到timerlist链表头位置,并更新事件(update_timer)。这里更新时间的意思是求出etimer链表中,还需要多长next_expiration(全局静态变量)时间,就会有etimer到期。

etimer管理

  Contiki用一个系统进程etimer_process管理所有的etimer定时器。进程退出时,会向所有进程发送事件PROCESS_EVENT_EXITED,当然也包括etimer系统进程etimer_process。当etimer_process拥有执行权的时候,便查看是否有相应的etimer绑定到该进程,若有就删除这些etimer。除此之外,etimer_process还会处理到期的etimer,etimer_process的thread函数流程图如下:

  

  1. PROCESS_THREAD(etimer_process, ev, data)
  2. {
  3. struct etimer *t, *u;
  4.  
  5. PROCESS_BEGIN();
  6.  
  7. timerlist = NULL;
  8.  
  9. while() {
  10. PROCESS_YIELD();
  11. /*事件是否为退出事件*/
  12. if(ev == PROCESS_EVENT_EXITED) {
  13. struct process *p = data;
  14.  
  15. while(timerlist != NULL && timerlist->p == p) {
  16. timerlist = timerlist->next;
  17. }
  18. /*如果有退出进程绑定etimer,删除所有相关的etimer*/
  19. if(timerlist != NULL) {
  20. t = timerlist;
  21. while(t->next != NULL) {
  22. if(t->next->p == p) {
  23. t->next = t->next->next;
  24. }
  25. else
  26. t = t->next;
  27. }
  28. }
  29. continue;
  30. } else if(ev != PROCESS_EVENT_POLL) {
  31. continue;
  32. }
  33.  
  34. again:
  35.  
  36. u = NULL;
  37. /*处理所有到期的etimer*/
  38. for(t = timerlist; t != NULL; t = t->next) {
  39. if(timer_expired(&t->timer)) {
  40. if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
  41.  
  42. /* Reset the process ID of the event timer, to signal that the
  43. etimer has expired. This is later checked in the
  44. etimer_expired() function. */
  45. t->p = PROCESS_NONE;
  46. if(u != NULL) {
  47. u->next = t->next;
  48. } else {
  49. timerlist = t->next;
  50. }
  51. t->next = NULL;
  52. update_time();
  53. goto again;
  54. } else {
  55. etimer_request_poll();
  56. }
  57. }
  58. u = t;
  59. }
  60.  
  61. }
  62.  
  63. PROCESS_END();
  64. }

  etimer_process获得执行权时,若传递的是退出事件,遍历整个timerlist,将与该进程(通过参数data传递)相关的etimer从timerlist删除,而后转去所有到期的etimer。通过遍历整个etimer查看到期的etimer,若有到期,发绑定的进程触发事件PROCESS_EVENT_TIMER,并将etimer的进程指针设为空(事件已加入事件队列,处理完毕),接着删除该etimer,求出下一次etimer到期时间,继续检查是否还有etimer到期。提升etimer_process优先级,若接下来都没有etimer到期了,就退出。总之,遍历timerlist,只要etimer到期,处理之后重头遍历整个链表,直到timerlist没有到期的etimer就退出。

参考博客:http://jelline.blog.chinaunix.net

contiki-定时器etimer的更多相关文章

  1. [置顶] STM32移植contiki进阶之三(中):timer 中文版

    鉴于自己英语水平不高,在这里,将上一篇关于contiki 的timer的文章翻译为中文,让自己在学习的时候,更方便点.文中有许多不是很通顺的地方,将就吧. Timers Contiki系统提供了一套时 ...

  2. contiki-进程

    进程的结构 Contiki的进程由两部分组成:进程控制块和进程线程.进程控制块存储在内存中,它包含进程运行时的信息,比如:进程名.进程状态.指向进程线程的指针. 进程线程是存储在ROM中的一个代码块. ...

  3. contiki etimer部分

    1.前言     contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统.国内的研究和应用还处于初级阶段,甚至还不知道这个contiki如何发音,也没有 ...

  4. 简单的玩玩etimer <contiki学习笔记之九 补充>

    这幅图片是对前面  <<contiki学习笔记之九>>  的一个补充说明. 简单的玩玩etimer <contiki学习笔记之九> 或许,自己正在掀开contiki ...

  5. 简单的玩玩etimer <contiki学习笔记之九>

    好吧,我承认etimer有点小复杂,主要是它似乎和contiki的process搅在一起,到处都在call_process.那就先搜搜contiki下的etimer的example看看,然后再试着写一 ...

  6. Contiki Etimer 模块

    一.Etimer概述 Etimer提供产生时间事件(timed event)的机制,当设定好的timer到期时,将会给设定etimer的process发送一个PROCESS_EVENT_TIMER 事 ...

  7. etimer

     Contiki包含一个时钟模型和5个定时器模型(timer, stimer, ctimer, etimer, and rtimer),先学习etimer吧. etimer是一个结构体,(个人用eve ...

  8. contiki在keil下的stm32平台移植

    参考博客: http://www.aiuxian.com/article/p-705047.html http://blog.csdn.net/u013232419/article/details/4 ...

  9. Contiki系统介绍

    本文内容来源为contiki英文介绍,自己为了学习,将其大致翻译成中文,以便了解. 欢迎转载,转载请注明来源,如果有什么翻译不合适的地方,请留言指出,相互交流学习. 介绍 Contiki是一个开放源码 ...

随机推荐

  1. [osx] intellij-idea快捷键大全

    官方地址:https://resources.jetbrains.com/assets/products/intellij-idea/IntelliJIDEA_ReferenceCard_mac.pd ...

  2. Linux字符界面安装VMware tools

    以往用VMware虚拟机都是装的桌面版,无奈实验室电脑属于老爷机,跑桌面linux实在有点吃不消,只能装个Basic Server玩玩了... 在桌面环境下装VMwaretools很简单,直接点击VM ...

  3. 学习笔记:MySQL列属性

    列属性 a)         null|not null 缺省值是null,也就是允许为空,如果是not null而又没有给该字段赋值的话,系统会首先查询该字段有没有默认值 b)         de ...

  4. 电脑安装Android4.0虚拟机的做法

    在开始教程之前,先给大家展示一下成功运行Android 4.0虚拟机的界面,经过笔者测试,体验很流畅,喜欢DIY和对开发感兴趣的朋友们可以猛击下一页,继续浏览教程. 准备工作 在体验前我们首先要下载J ...

  5. ClientScript.RegisterStartupScript 不起作用

    asp.net webform 使用 ClientScript.RegisterStartupScript 不起作用 form 加上 runat="server",ok

  6. 巧用margin/padding的百分比值实现高度自适应(多用于占位,避免闪烁)

    本文依赖于一个基础却又容易混淆的css知识点:当margin/padding取形式为百分比的值时,无论是left/right,还是top/bottom,都是以父元素的width为参照物的!也许你会说, ...

  7. jsp九大内置对象、四种作用域、跳转方式

    jsp有四种属性范围: page -> 页面级别,显然只有在一个页面内可用. request -> 请求级别 服务器跳转,一次请求之后消失. session -> 会话级别 客户端跳 ...

  8. [课程设计]Scrum 3.3 多鱼点餐系统开发进度(下单详细信息页面设计)

    Scrum 3.3 多鱼点餐系统开发进度(下单详细信息页面设计)  1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题:餐厅到店点 ...

  9. 对C++虚函数的理解

    关于类不断被继承的过程,从整体上看,是一个从抽象到逐渐具体化的过程,基类可以是非常非常抽象的东西,而最终实例化的派生类就非常具体了. 虚函数的意义,就在于定义了一个从最早的基类到最终的派生类都可能会用 ...

  10. C# 整数转二进制字符串

    可以便于调试位运算 void Execute() { , ); , ); , ); Debug.Log("1: " + a); Debug.Log("2: " ...