Contiki Etimer 模块
一、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 模块的更多相关文章
- contiki etimer部分
1.前言 contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统.国内的研究和应用还处于初级阶段,甚至还不知道这个contiki如何发音,也没有 ...
- Contiki clock模块
一.functions for handling system time clock_time_t clock_time(void);//return the current system time ...
- Contiki Rtimer 模块
一.rtimer概述 The Contiki rtimer library provides scheduling and execution of real-time tasks (with pre ...
- Contiki Ctimer模块
Ctimer 提供和Etimer类似的功能,只是Ctimer是在一段时间后调用回调函数,没有和特定进程相关联. 而Etimer是在一段时间后发送PROCESS_EVENT_TIMER事件给特定的进程. ...
- [置顶] STM32移植contiki进阶之三(中):timer 中文版
鉴于自己英语水平不高,在这里,将上一篇关于contiki 的timer的文章翻译为中文,让自己在学习的时候,更方便点.文中有许多不是很通顺的地方,将就吧. Timers Contiki系统提供了一套时 ...
- Contiki-Timer 概述
Contiki有一个clock模块和一系列timer模块:timer,stimer,ctimer,etimer,和rtimer. 一.clock模块 clock模块提供一些处理系统时间的函数,还有一些 ...
- 简单的玩玩etimer <contiki学习笔记之九 补充>
这幅图片是对前面 <<contiki学习笔记之九>> 的一个补充说明. 简单的玩玩etimer <contiki学习笔记之九> 或许,自己正在掀开contiki ...
- 简单的玩玩etimer <contiki学习笔记之九>
好吧,我承认etimer有点小复杂,主要是它似乎和contiki的process搅在一起,到处都在call_process.那就先搜搜contiki下的etimer的example看看,然后再试着写一 ...
- Contiki Timer & Stimer 模块
一.Timer API struct timer { clock_time_t start; clock_time_t interval; }; CCIF void timer_set(struct ...
随机推荐
- 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解
深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...
- C# Graphics
Graphics.FillPie 方法 填充由一对坐标.一个宽度.一个高度以及两条射线指定的椭圆所定义的扇形区的内部. Graphics.FillPie (Brush, Int32, Int32, I ...
- java集合类型接口和实现类个人总结
转载:http://blog.csdn.net/qingchunbusanchang/article/details/39576749 java的集合是一个比较综合的概念,相关的知识有很多的博客里面做 ...
- 聚合数据Android SDK 12306火车票查询订票演示示例
1.聚合SDK是聚合数据平台,为移动开发者提供的免费数据接口.使用前请先到聚合平台(http://www.juhe.cn/)注册,申请相关数据. 2.下载聚合数据SDK,将开发包里的juhe_sdk_ ...
- git 安装方法
Windows上安装Git示例 在Windows上使用Git,可以从Git官网直接下载安装程序,(网速慢的同学请移步国内镜像),然后按默认选项安装即可. 安装完成后,在开始菜单里找到“Git”-> ...
- C# 字节数组拼接的速度实验(Array.copy(),Buffer.BlockCopy(),Contact())
无聊做了如题的一个算法的优劣性能比较,由于很多人都只关心结果,那么我先贴出结果如下: 由于我的测试数据量比较小,只能得出Array.Copy()和Buffer.BlockCopy()方法性能要好于Co ...
- Log4net日志记录、详细配置(自己使用>)
log4net库是Apache log4j框架在Microsoft.NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台.文件.数据库等)的工具 1.首先添加对log4net.dll的引 ...
- fabric使用实例(发布web包的一个例子)
#!/usr/bin/env python # -*- coding: utf-8 -* #添加中文注释的编码 #fabfile.py from fabric.api import * env.use ...
- QTreeWidget里嵌套表格QTableView
InformationPositionSubTableView::InformationPositionSubTableView(QStringList& columnNameList,QLi ...
- java变参
java变参是通过数组来实现的 Object[] addAll(Object[] array1, Object... array2)和Object[] addAll(Object[] array1, ...