一、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_expiration
return;//返回
}
}
} //添加进链表中
//有两种情况,会执行以下代码
//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_GUARD
if(!sheph_ok() || process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK)
#else
if(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 the
etimer has expired. This is later checked in the
etimer_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() {
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;
} else
t = 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 the
et 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 about
to remove. We point the items next pointer to the event after
the 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 = ;
} 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_CLK
clock_set_expire(tdist);
#endif
next_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 : ;
}

最近一个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;//初始化timerlist while() {
PROCESS_YIELD();//等待事件 if(ev == PROCESS_EVENT_EXITED) {//有别的进程要exit
//这个时候需要把跟p相关的etimer从timerlist中remove
struct 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;
} else
t = 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_GUARD
if(!sheph_ok() || process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK)
#else
if(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 the
etimer has expired. This is later checked in the
etimer_expired() function. */
t->p = PROCESS_NONE;//标志这个etimer已经被处理过
//将etimer从timerlist中remove
if(u != NULL) {//timerlist后边的remove操作
u->next = t->next;
} else {//timerlist的remove操作
timerlist = t->next;
}
t->next = NULL;//将remove去的对象的next设置为NULL
update_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_process while() {
//等待事件,并且当条件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.

Contiki Etimer 模块的更多相关文章

  1. contiki etimer部分

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

  2. Contiki clock模块

    一.functions for handling system time clock_time_t clock_time(void);//return the current system time ...

  3. Contiki Rtimer 模块

    一.rtimer概述 The Contiki rtimer library provides scheduling and execution of real-time tasks (with pre ...

  4. Contiki Ctimer模块

    Ctimer 提供和Etimer类似的功能,只是Ctimer是在一段时间后调用回调函数,没有和特定进程相关联. 而Etimer是在一段时间后发送PROCESS_EVENT_TIMER事件给特定的进程. ...

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

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

  6. Contiki-Timer 概述

    Contiki有一个clock模块和一系列timer模块:timer,stimer,ctimer,etimer,和rtimer. 一.clock模块 clock模块提供一些处理系统时间的函数,还有一些 ...

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

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

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

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

  9. Contiki Timer & Stimer 模块

    一.Timer API struct timer { clock_time_t start; clock_time_t interval; }; CCIF void timer_set(struct ...

随机推荐

  1. 【DQ冰淇淋】—— Babylon 冰淇淋三维互动营销项目总结

    前言:在学习过Babylon.js基础之后,我上手的第一个网页端3D效果制作项目就是‘DQ冰淇淋’.这个小项目应用到了Babylon最基础的知识,既可以选味道,选点心,也可以旋转.倒置冰淇淋,互动起来 ...

  2. 给交换机端口设ip

    先给端口设vlan,再给vlan设ip [H3C]vlan [H3C-vlan100]port GigabitEthernet // <H3C>sy System View: return ...

  3. greenDAO学习分享总结

    greenDAO(最新版本号V2.0.0的Readme) ======== greenDAO is a light & fast ORM solution for Android that m ...

  4. oracle select into相关

    自定义参数输出: declare v_test integer :=0 ;beginselect count(*) into v_test  from tf_estate_card t ;dbms_o ...

  5. Oracle 修改带数据的字段类型

    http://www.cnblogs.com/LDaqiang/articles/1157998.html由于需求变动,现要将一个类型NUMBER(8,2)的字段类型改为 char.大体思路如下:   ...

  6. 2个YUV视频拼接技术

    http://blog.csdn.net/huahuahailang/article/details/9040847 2个YUV视频拼接技术 http://zhongcong386.blog.163. ...

  7. Android 虚化图片的方法

    Android 虚化图片 模糊图片 图片毛玻璃效果. 效果如图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaDNjNGxlbm92bw==/font/ ...

  8. 非标准USBasp下载线烧录Arduino BootLoader的参数设置

    本文仅适用于BootLoader损坏且买到国产“免驱USBasp下载线”导致Arduino IDE无法识别从而不能烧写的情况.是一种略显非主流的操作方式. 因为Arduino的IDE并不支持这种免驱的 ...

  9. x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*()

    x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*() 帧间预測是指利用视频时间域相关性,使用临近已编码图像像素预測当前图像的像素,以达到有效去除视频时域冗 ...

  10. u-boot-2014-04 网络不通解决一例

    不久前我移植了u-boot-214-04到Tq2440的板子上,基本功能都有了,网卡也可以使用了.有一天打算把u-boot-2010-06也也一直到tq2440上,移植完后发现u-boot-214-0 ...