一、Etimer概述

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

Etimer模块调用clock_time获得当前系统的时间。

The Contiki etimer library provides a timer mechanism that generate timed events. An event timer will post the event PROCESS_EVENT_TIMER to the process that set the timer when the event timer expires. The etimer library use clock_time() in the clock module to get the current system time.

二、Etimer数据结构

/*** A timer.** This structure is used for declaring a timer. The timer must be set* with etimer_set() before it can be used.** \hideinitializer*/
struct etimer {struct timer timer;//timer 记录时间struct etimer *next;//下一个etimer,为链表准备struct process *p;//etimer对应的进程process,即设置etimer的进程
};

全局变量:

static struct etimer *timerlist;//链表头

最后所有的etimer的组织形式如下所示:其中timerlist指向etimer0

图参考:http://blog.chinaunix.net/uid-9112803-id-2976929.html

1、etimer的插入

static void
add_timer(struct etimer *timer)
{struct etimer *t;etimer_request_poll();//以下部分,判断timer是否在当前链表中,且其没有被处理过(没有expired)if(timer->p != PROCESS_NONE) {//timer 没被处理过。etimer进程中,如果有etimer到期后,其相应的process会被设置为PROCESS_NONE/* Timer not on list. */for(t = timerlist; t != NULL; t = t->next) {//遍历,查找是否在当前链表中if(t == timer) {//找到/* Timer already on list, bail out. */timer->p = PROCESS_CURRENT();//设为当前进程update_time();//更新时间,有新的etimer加入,重新更新下next_expirationreturn;//返回
      }}}//添加进链表中//有两种情况,会执行以下代码//timer被处理过(expired)或者第一次添加进链表timer->p = PROCESS_CURRENT();timer->next = timerlist;timerlist = timer;update_time();//更新时间,有新的etimer加入,重新更新下next_expiration
 }

调用add_timer的函数有:etimer_set、etimer_reset、etimer_restart

etimer_set是初始化,使用前要先调用etimer_set函数,etimer第一次添加进链表

调用etimer_reset和etimer_restart这两个函数时,相应的etimer已经在etimer_process中被处理过了(已经从链表中删除了,而且etimer相应的process被设置为PROCESS_NONE),或者还没被处理过(还在链表中)。

注:etimer_process对expired的etimer进行处理时,会将其process设为PROCESS_NONE,且从timerlist链表中删除

2、etimer的删除

有三个地方会引起etimer的删除操作:

etimer_process中,当相应的etimer到期后,并向相应process发送PROCESS_EVENT_TIMER事件之后。

/*---------------------------------------------------------------------------*/
PROCESS_THREAD(etimer_process, ev, data)
{
……
again:u = NULL;for(t = timerlist; t != NULL; t = t->next) {if(timer_expired(&t->timer)) {//到期
#if WITH_GUARDif(!sheph_ok() || process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK)
#elseif(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK)//发送PROCESS_EVENT_TIMER事件
#endif{/* Reset the process ID of the event timer, to signal that theetimer has expired. This is later checked in theetimer_expired() function. */t->p = PROCESS_NONE;if(u != NULL) {u->next = t->next;} else {timerlist = t->next;}t->next = NULL;update_time();//有变动,更新时间goto again;} else {etimer_request_poll();}}u = t;//记录上一个t}}PROCESS_END();

etimer_process中,当有进程退出时,对应的etimer也要删除。

PROCESS_THREAD(etimer_process, ev, data)
{struct etimer *t, *u;PROCESS_BEGIN();timerlist = NULL;while(1) {PROCESS_YIELD();if(ev == PROCESS_EVENT_EXITED) {struct process *p = data;while(timerlist != NULL && timerlist->p == p) {timerlist = timerlist->next;}if(timerlist != NULL) {t = timerlist;while(t->next != NULL) {if(t->next->p == p) {t->next = t->next->next;} elset = t->next;}}continue;} else if(ev != PROCESS_EVENT_POLL) {continue;}……PROCESS_END();
}

etimer_stop函数

void
etimer_stop(struct etimer *et)
{struct etimer *t;/* First check if et is the first event timer on the list. */if(et == timerlist) {timerlist = timerlist->next;update_time();//有变动,更新下一个expired时间} else {/* Else walk through the list and try to find the item before theet timer. */for(t = timerlist; t != NULL && t->next != et; t = t->next);if(t != NULL) {/* We've found the item before the event timer that we are aboutto remove. We point the items next pointer to the event afterthe removed item. */t->next = et->next;update_time();//有变动,更新next_expiration}}/* Remove the next pointer from the item to be removed. */et->next = NULL;/* Set the timer as expired */et->p = PROCESS_NONE;
}

三、Etimer相关API

1、updata_time(static)

这个函数最主要的就是更新next_expiration这个变量,即下次expire的时间。

static void
update_time(void)
{clock_time_t tdist;clock_time_t now;struct etimer *t;if (timerlist == NULL) {next_expiration = 0;} else {now = clock_time();t = timerlist;/* Must calculate distance to next time into account due to wraps */tdist = t->timer.start + t->timer.interval - now;for(t = t->next; t != NULL; t = t->next) {if(t->timer.start + t->timer.interval - now < tdist) {tdist = t->timer.start + t->timer.interval - now;}}
#if USE_RTC_CLKclock_set_expire(tdist);
#endifnext_expiration = now + tdist;}
}

注意:

这里不用担心clock_time wrap而出错的问题,具体可查看http://www.cnblogs.com/songdechiu/p/5397070.html

如果USE_RTC_CLK,则etimer还没到期时,MCU进入低功耗模式。

2、etimer_set、etimer_reset、etimer_restart等

代码如下:

/*---------------------------------------------------------------------------*/
void
etimer_set(struct etimer *et, clock_time_t interval)
{timer_set(&et->timer, interval);add_timer(et);
}
/*---------------------------------------------------------------------------*/
void
etimer_reset(struct etimer *et)
{timer_reset(&et->timer);add_timer(et);
}
/*---------------------------------------------------------------------------*/
void
etimer_restart(struct etimer *et)
{timer_restart(&et->timer);add_timer(et);
}

void
etimer_adjust(struct etimer *et, int timediff)
{et->timer.start += timediff;update_time();
}
/*---------------------------------------------------------------------------*/
int
etimer_expired(struct etimer *et)
{return et->p == PROCESS_NONE;
}
/*---------------------------------------------------------------------------*/
clock_time_t
etimer_expiration_time(struct etimer *et)
{return et->timer.start + et->timer.interval;
}
/*---------------------------------------------------------------------------*/
clock_time_t
etimer_start_time(struct etimer *et)
{return et->timer.start;
}

Like the previous timers, an event timer is always initialized by a call to etimer_set() which sets the timer to expire the specified delay from current time. etimer_reset() can then be used to restart the timer from previous expire time andetimer_restart() to restart the timer from current time, both using the same time interval that was originally set by etimer_set(). The difference between etimer_reset() andetimer_restart() is that the former schedules the timer from previous expiration time while the latter schedules the timer from current time thus allowing time drift. An event timer can be stopped by a call to etimer_stop() which means it will be immediately expired without posting a timer event. etimer_expired() is used to determine if the event timer has expired.

四、Porting the Etimer Library

clock底层需要通知etimer_process,有etimer即将到期。然后etimer_process进行相应的处理。

The clock module implementation usually also handles the notifications to the etimer library when it is time to check for expired event timers.

主要用到三个函数:

if(etimer_pending() && etimer_next_expiration_time() <= current_clock) {etimer_request_poll();}

clock模块用于通知的主要代码。

1、etimer_pending

int
etimer_pending(void)
{return timerlist != NULL;
}

判断timerlist是否为空

2、etimer_next_expiration_time

clock_time_t
etimer_next_expiration_time(void)
{return etimer_pending() ? next_expiration : 0;
}

最近一个etimer到期的时间点next_expiration

每次调用update_time,这个变量都会更新。

3、etimer_request_poll

void
etimer_request_poll(void)
{process_poll(&etimer_process);
}

通知etimer_process是时候检查etimer的expired了,并进行处理。

五、etimer_process进程

PROCESS(etimer_process, "Event timer");PROCESS_THREAD(etimer_process, ev, data)
{struct etimer *t, *u;PROCESS_BEGIN();timerlist = NULL;//初始化timerlistwhile(1) {PROCESS_YIELD();//等待事件if(ev == PROCESS_EVENT_EXITED) {//有别的进程要exit//这个时候需要把跟p相关的etimer从timerlist中removestruct process *p = data;while(timerlist != NULL && timerlist->p == p) {//timerlist就是remove对象timerlist = timerlist->next;}if(timerlist != NULL) {//timerlist后边的remove操作t = timerlist;while(t->next != NULL) {if(t->next->p == p) {t->next = t->next->next;} elset = t->next;}}continue;//删除完毕,继续返回循环,等待事件} else if(ev != PROCESS_EVENT_POLL) {continue;//不是PROCESS_EVENT_POLL,继续等待//直到PROCESS_EVENT_POLL事件到来,才能执行下边的操作//因为只有PROCESS_EVENT_POLL才是标志着有etimer到期了,需要进行处理
    }again://这部分是对etimer的expired进行处理
u = NULL;for(t = timerlist; t != NULL; t = t->next) {//遍历if(timer_expired(&t->timer)) {//有etimer到期
#if WITH_GUARDif(!sheph_ok() || process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK)
#elseif(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK)//向相关process发送PROCESS_EVENT_TMER事件成功
#endif{/* Reset the process ID of the event timer, to signal that theetimer has expired. This is later checked in theetimer_expired() function. */t->p = PROCESS_NONE;//标志这个etimer已经被处理过//将etimer从timerlist中removeif(u != NULL) {//timerlist后边的remove操作u->next = t->next;} else {//timerlist的remove操作timerlist = t->next;}t->next = NULL;//将remove去的对象的next设置为NULLupdate_time();//更新时间goto again;//继续回到again,进行expired检查,处理} else {etimer_request_poll();//发送事件不成功,继续poll
        }}u = t;//记录上一个t,方便后续进行链表的remove操作
    }}PROCESS_END();
}

六、etimer的使用

#include "sys/etimer.h"PROCESS_THREAD(example_process, ev, data){static struct etimer et;//声明etimer
   PROCESS_BEGIN();/* Delay 1 second */etimer_set(&et, CLOCK_SECOND);//初始化etimer,即一秒钟后到期,并将process设置为example_processwhile(1) {//等待事件,并且当条件etimer_expired(&et)成立时//从上文,我们知道etimer到期时,etimer_process会将相应的etimer的p设置为PROCESS_NONE,并向相应的process发送PROCESS_EVENT_TIMER事件PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));/* Reset the etimer to trig again in 1 second */etimer_reset(&et);/* ... */}PROCESS_END();}

 The etimer library cannot safely be used from interrupts.

转载于:https://www.cnblogs.com/songdechiu/p/5954783.html

Contiki Etimer 模块相关推荐

  1. contiki学习笔记 clock部分

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

  2. 【MPC5744P】S32DS配置etimer, pit中断

    DEVKIT-mpc5744p配置etimer中断 软件:S32 Design Studio for Power Architecture Version 2.1 新建工程,配置与生成代码 本文工程下 ...

  3. contiki学习笔记(五)ctimer和etimer

    四.callback timer 回调计时器(ctimer) Callback timer(回调计时器) Contiki system ctimer模块提供了一个计时器机制(机制)调用指定的C函数ct ...

  4. 关于contiki中的Ctimer和Etimer

    文件目录: contiki\core\sys\ 1 etimer 1.1 说明 事件定时器,发生超时的时候会得到一个事件,etimer include了timer,timer使用的是clock的系统滴 ...

  5. contiki学习笔记 etimer部分

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

  6. contiki学习笔记(八)rtimer stimer 计时器库

    九.实时任务调度(rtimer) 实时模块处理实时任务的调度和执行(具有可预测的执行时间). Data Structures struct rtimerRepresentation of a real ...

  7. contiki学习笔记(三)contiki系统

    contiki系统函数源代码中包含了如下几个部分 具体实现见后文 一. Argument buffer(参数缓存区) The argument buffer can be used when pass ...

  8. Contiki教程——进程

    概述 Contiki中的代码可以运行在下列两种执行上下文之一:合作式或者抢占式.合作式代码按顺序运行,抢占式代码可以暂停正在运行的合作式代码.Contiki中的进程运行在合作式上下文中,而中断和实时定 ...

  9. Contiki的内核分析-定时器模型

    导读 本文通过分析Contiki的源码,梳理Contiki的定时器模型中一共5个定时器的工作机制和原理. 引入 从本文开始,我们开始探究Contiki的5个定时器模型,遵循从易到难的原则,我们先开始两 ...

最新文章

  1. vscode 高效使用指南
  2. cocos2d-x注意事项(十)Lua发展飞机战争-4-创建主角
  3. 缺陷检测 | PCB AOI质量检测之自动定位核选取算法
  4. VTK修炼之道16:图像处理_窗口分割和图像融合(ViewportvtkImageBlend)
  5. [算法笔记]-环形链表Ⅱ-解题方法
  6. Oracle数据库中闪回恢复的详细分析
  7. android 源码中的单例,Android源码中的一种单例实现
  8. 【LeetCode 剑指offer刷题】树题4:104 Maximum Depth of Binary Tree
  9. 关于政务版本中的公文签名及签章
  10. Binet‘s Formula 算法
  11. 研究生必备的文献翻译软件知云文献翻译替代品--Mac monterey
  12. 上取整与下取整的解析
  13. 计算机在英语专业的应用论文,计算机英语双语应用分析论文
  14. 雷达探测项目仿真代码(Matlab代码实现)
  15. Fabrie:PPT有风险,设计师请停用
  16. 一篇搞懂OOA/OOD/OOP的区别
  17. docker自定义elasticsearch镜像——集成中文分词器smartcn
  18. pythonmacd指标编写_利用python编写macd、kdj、rsi、ma等指标 -
  19. 简单的爬虫入门--爬取百度股票信息--来自mooc嵩老师视频
  20. 【雷达通信】基于matla模拟雷达定位

热门文章

  1. android服务常驻后台,android-如何始终在后台运行服务?
  2. canvasnest 移动距离_GitHub - XiaoxinJiang/canvas-nest: 仿知乎登录页面canvas-nest
  3. python全栈开发网络_Python 全栈开发:网络编程
  4. zipparameters 使用_zip4j的简单运用
  5. php5框架,Thinkphp5.1框架
  6. Vue 3.0已进入发布候选阶段!
  7. 华科大计算机跨考,华中科大计算机概况_跨考网
  8. c语言读取txt第二行数值,c语言读取文件的第二行
  9. vue canvas插件_基于vue.js 制作在线桌椅定制选择交互特效源码
  10. 20201008:力扣209周周赛题解(下)