contiki-定时器etimer
Contiki内核是基于事件驱动和Protothreads机制,事件既可以是外部事件(比如按键,数据到达),也可以是内部事件(如时钟中断)。定时器的重要性不言而喻,Contiki提供了5种定时器模型,即timer(描述一段时间,以系统时钟滴答数为单位),stimer(描述一段时间,以秒为单位),ctimer(定时器到期,调用某函数,用于Rime协议栈),etimer(定时器到期,触发一个事件),rtimer(实时定时器,在一个精确的时间调用函数)。
鉴于etimer在Contiki使用的广泛性,管理这些etimer由系统进程etimer_process管理,本小节详细简单介绍etimer相关技术细节。
etimer组织结构
etimer作为一类特殊事件存在,也是跟进程绑定。除此之外,还需要变量描述定时器属性,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; //包含起始时刻和间隔两成员变量
struct etimer *next; //指向下一个etimer
struct process *p;
};
/**
* A timer.
*
* This structure is used for declaring a timer. The timer must be set
* with timer_set() before it can be used.
*
* \hideinitializer
*/
struct timer {
clock_time_t start;
clock_time_t interval;
};
成员变量timer用于描述定时器属性,包含起始时刻及间隔,将起始时刻与间隔相加与当前时钟对比,便可知道是否到期。变量p指向所绑定的进程(p为NULL则表示该定时器与所有进程绑定)。成员变量next,指向下一个etimer,系统所有etimer被链接成一个链表,链表头是timerlist,如下图所示:
static struct etimer *timerlist;

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

void
etimer_set(struct etimer *et, clock_time_t interval)
{
timer_set(&et->timer, interval);//设置起始时刻和时间间隔
add_timer(et);//将etimer添加到timerlist
}
/**
* Set a timer.
*
* This function is used to set a timer for a time sometime in the
* future. The function timer_expired() will evaluate to true after
* the timer has expired.
*
* \param t A pointer to the timer
* \param interval The interval before the timer expires.
*
*/
void timer_set(struct timer *t, clock_time_t interval)
{
t->interval = interval; //设置时间间隔
t->start = clock_time(); //设置起始时刻
}
static void add_timer(struct etimer *timer)
{
struct etimer *t; etimer_request_poll();//提升etimer系统进程的优先级 if(timer->p != PROCESS_NONE) {//该etimer处理过
for(t = timerlist; t != NULL; t = t->next) {
if(t == timer) {
/* Timer already on list, bail out. */
/*此etimer已经在etimer链表中*/
timer->p = PROCESS_CURRENT();//将现有进程赋给此etimer的进程
update_time();
return;
}
}
} /* Timer not on list. */
/*此etimer不在etimer链表中,放到etimer链表表头*/
timer->p = PROCESS_CURRENT();
timer->next = timerlist;
timerlist = timer; update_time();
}
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函数流程图如下:

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;
}
/*如果有退出进程绑定etimer,删除所有相关的etimer*/
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;
} again: u = NULL;
/*处理所有到期的etimer*/
for(t = timerlist; t != NULL; t = t->next) {
if(timer_expired(&t->timer)) {
if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) { /* 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;
} } PROCESS_END();
}
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的更多相关文章
- [置顶] STM32移植contiki进阶之三(中):timer 中文版
鉴于自己英语水平不高,在这里,将上一篇关于contiki 的timer的文章翻译为中文,让自己在学习的时候,更方便点.文中有许多不是很通顺的地方,将就吧. Timers Contiki系统提供了一套时 ...
- contiki-进程
进程的结构 Contiki的进程由两部分组成:进程控制块和进程线程.进程控制块存储在内存中,它包含进程运行时的信息,比如:进程名.进程状态.指向进程线程的指针. 进程线程是存储在ROM中的一个代码块. ...
- contiki etimer部分
1.前言 contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统.国内的研究和应用还处于初级阶段,甚至还不知道这个contiki如何发音,也没有 ...
- 简单的玩玩etimer <contiki学习笔记之九 补充>
这幅图片是对前面 <<contiki学习笔记之九>> 的一个补充说明. 简单的玩玩etimer <contiki学习笔记之九> 或许,自己正在掀开contiki ...
- 简单的玩玩etimer <contiki学习笔记之九>
好吧,我承认etimer有点小复杂,主要是它似乎和contiki的process搅在一起,到处都在call_process.那就先搜搜contiki下的etimer的example看看,然后再试着写一 ...
- Contiki Etimer 模块
一.Etimer概述 Etimer提供产生时间事件(timed event)的机制,当设定好的timer到期时,将会给设定etimer的process发送一个PROCESS_EVENT_TIMER 事 ...
- etimer
Contiki包含一个时钟模型和5个定时器模型(timer, stimer, ctimer, etimer, and rtimer),先学习etimer吧. etimer是一个结构体,(个人用eve ...
- contiki在keil下的stm32平台移植
参考博客: http://www.aiuxian.com/article/p-705047.html http://blog.csdn.net/u013232419/article/details/4 ...
- Contiki系统介绍
本文内容来源为contiki英文介绍,自己为了学习,将其大致翻译成中文,以便了解. 欢迎转载,转载请注明来源,如果有什么翻译不合适的地方,请留言指出,相互交流学习. 介绍 Contiki是一个开放源码 ...
随机推荐
- excel手机号码归属地批量公式查询 vlookup函数
Excel手机号码归属地 批量公式查询 vlookup函数 xls 手机号码 添加一列 地区归属地 使用 公式:=(VLOOKUP(LEFT(B2,7),号段数据库!B:D,2,0)& ...
- web分享QQ好友、QQ空间、新浪微博的api接口
QZone: "http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url={{URL}}&title={{TITL ...
- QuickRun-快速运行助手
大家平时需要打开软件的时候都是怎么操作的?一般来说有三种方式: 切换到桌面再点击软件的快捷方式(会将当前正在操作的软件隐藏,再切换回之前的状态比较麻烦,特别是桌面被密密麻麻的图标铺满的时候,找到一个快 ...
- 补全Gemfile缺少到javascript gem
如果缺少某个gem,查看并修改Gemfile文件 第一步要先修改源 source 'https://ruby.taobao.org' 下面补全这两个gem gem 'execjs' gem 'ther ...
- [原创]Visual Studio 使用 Just My Code引起无法断点
今天遇到的问题,同样的代码,在一台机器上用Release配置可以命中断点,在另一台上用Release断点就都失效了.后来发现是因为断点失效的机器上设置了Just My Code.在Debug-Opti ...
- express框架路由配置及congtroller自动加载
express框架在node官方推荐的一个框架,关于如何入门的文章,已经很多了,我就不在累赘了,本文的核心是如何修改文件使得更接近一个MVC的框架 express原生是通过require的方式实现了模 ...
- Windows下底层数据包发送实战
1.简介 所谓“底层数据包”指的是在“运行”于数据链路层的数据包,简单的说就是“以太网帧”,而我们常用的Socket只能发送“运行”在传输层的TCP.UDP等包,这些传输层数据包已经能满足绝大部分需求 ...
- Django(三)
1.Django请求的生命周期 路由系统 -> 视图函数(获取模板+数据-->渲染) -> 字符串返回给用户 2.路由系统 /index/ ...
- centos7 卸载openJDK 安装jdk7
[root@cms02 root]# rpm -qa | grep jdk java--openjdk-headless-1.7.0.75-2.5.4.2.el7_0.x86_64 java--ope ...
- 【转载】移动web开发经验总结
本文出自: http://blog.163.com/hsb001_mobile/blog/static/15524028020111177221254/ 1.-webkit-tap-highlight ...