Contiki Timers 詳解

Timers

Contiki系統提供了一套時鐘庫用於應用程序和系統本身。時鐘庫包含了檢查時間超出、將系統從低功耗模式喚醒到預定時間,以及實時任務安排等功能。時鐘也用於應用程序,讓系統和其他一起工作,或者在恢復執行前進入低功耗模式一段時間。

The Contiki Timer Modules

Contiki 有一個時鐘模塊和一套時鐘:timer,stimer,ctimer,etimer和rtimer。不同的時鐘有不同的用處:有的時鐘提供了長運行時間低密度(時間間隔長),有的時鐘提供了短運行時間和高密度(時間間隔短),有的時鐘可以用在中斷上下文(rtimer),而其他時鐘則不行。

時鐘模塊提供了操作系統時間的功能,以及短時間阻塞CPU的功能。定時器庫是實現時鐘模塊的功能的基礎。

timer 和stimer庫提供了最簡單形式的定時器,用於檢查一段時間是否到期。應用程序需要問計時器,他們是否已經過期。然而兩者的區別在於:timer使用系統嘀嗒,而stimer 使用秒,允許更長的時間。不同於其他timer的是,timer和stimer庫可以從中斷中安全的使用,這使得他們在底層的驅動中特別有用。

Etimer 庫提供事件時間,他能用於contiki進程在一段時間後的計劃事件。他用於contiki的進程中,等待一段時間,在此時,其他的部分可以工作或進入低功耗模式。

Ctimer 提供回調時間,他用於在一段時間之後,安排調用回調函數。就像事件定時器一樣,他們是用來等待一些時間,而在這段時間內,系統其他的部分可以工作或進入低功耗模式。當時間到期之後,回調定時器調用函數,他在任何代碼中都非常有用,以致沒有一個想協議實現那樣的顯式的contiki進程。(這裏我翻譯的不是很好,原文:they are especially useful in any code that do not have an explicit Contiki process such as protocol implementations 在其他方面,使用的回調定時器在Rime協議棧處理通信超時。

Rtimer 庫提供實時任務調度。Rtimer庫搶佔任何運行着的contiki進程,讓實時任務在預定的時間裏執行。實時任務用在關鍵代碼處理時間裏,例如X-MAC實現收音機開啓或關閉這種沒有延時的情況下。

The Clock Module

時鐘模塊提供操作系統時間的功能。

Contiki 時鐘模塊的API接口所示如下:clock_time() 函數以時鐘嘀嗒的形式返回當前系統時間。每秒時鐘嘀嗒的數是和平臺相關的,通常被指定爲常數CLOCK_SECOND 。系統時間被指定爲和平臺相關的類型clock_time_t ,在大多數情況下這是一個有限的無符號值,運行時會變很大。時鐘模塊也提供clock_seconds() 函數,以秒的形式獲得系統時間,其值爲一個無符號的長整型數,這個時間值會變的很大,直到他增加到最大,(在MSP430平臺上爲136年),然後系統重新開始,時間也從零開始。

時鐘模塊提供兩個函數阻塞CPU:clock_delay() ,阻塞CPU一個指定的延遲,clock_wait() ,阻塞CPU一個指定的時鐘嘀嗒。這些函數通常只用於底層驅動程序,在有必要等待很短的時間,但並不放棄控制CPU的情況。

函數clock_init() 由系統啓動,初始化時鐘模塊的時候調用。

時鐘模塊API:

clock_time_t clock_time() :獲得系統時間。

unsigned long clock_seconds() :以秒的形式獲得系統時間。

void clock_delay(unsigned int delay) :CPU延時。

void clock_wait(int delay) :CPU延時一定數量的系統嘀嗒。

void clock_init(void) :初始化時鐘模塊。

CLOCK_SECOND :每秒系統嘀嗒數。

Porting the Clock Module

時鐘模塊與平臺相關,他的應用在clock.c文件裏面。時鐘模塊處理系統時間,他的實現通常需要適時檢查事件計時器是否到時,然後通知etimer庫處理。

The Timer Library

Contiki 時鐘庫提供設置、重置、重啓時鐘的函數,並檢查一個時鐘是否到期。一個應用程序

需要“手動”地檢查定時器是否到期,而不是自動完成的。在時鐘模塊中,時鐘庫使用clock_timer()獲得當前的系統時間。

定時器被聲明爲struct類型,所有訪問定時器都是經過指針指向被聲明的定時器。

Contiki 定時器庫的API如下所示。定時器由timer_set()完成初始化,設置定時器從當前時間到指定時間的延遲,而且他還存儲了定時器的時間間隔。Timer_reset()可以從之前的到期時間重置定時器,timer_restart()從當前時間重新啓動定時器。Timer_reset()和timer_restart()都是調用timer_set(),用時間間隔設置定時器。這些函數的區別是:timer_reset()用完全相同的時間間隔設置定時器延時,而timer_restart()從當前時間設置時間間隔,使時間推移。

Timer_expired() 函數用來檢查定時器是否到期,timer_remaining()獲得一個定時器到期的剩餘時間。如果定時器已經過期,他的返回值未知的。

Timer 庫可以從中斷中安全的使用。下面的代碼顯示了一個簡單的例子:一個定時器如何在中斷中檢測超時。

Timer 庫API:

void timer_set(struct timer *t, clock_time_t interval) :啓動定時器。

void timer_reset(struct timer *t) :從以前到期時間重新啓動定時器。

void timer_restart(struct timer *t) :從當前時間重啓定時器。

int timer_expired(struct timer *t) :檢查定時器是否到期。

clock_time_t timer_remaining(struct timer *t) :獲得剩餘時間。

一個例子展示了一個定時器如何檢測超時:

static struct timer rxtimer;

void init(void) {

timer_set(&rxtimer, CLOCK_SECOND / 2);

}

interrupt(UART1RX_VECTOR)

uart1_rx_interrupt(void)

{

if(timer_expired(&rxtimer)) {

/* Timeout */

/* ... */

}

timer_restart(&rxtimer);

/* ... */

}

The Stimer Library

Contiki Stimer 庫提供的定時機制類似於timer庫,但是他的時間使用是秒,允許更長的到期時間,stimer庫在時鐘模塊中用clock_seconds()以秒的形式獲得當前的系統時間。

Contiki stimer 庫的API如下所示,他非常類似於timer的庫。不同的是,他以秒爲單位,而timer是以系統嘀嗒爲單位。

Stimer 庫可以從中斷中安全的使用。

Stimer 庫的API:

void stimer_set(struct stimer *t, unsigned long interval) :啓動timer。

void stimer_reset(struct stimer *t) :從到期時間中重啓timer。

void stimer_restart(struct stimer *t) :從當前時間重啓timer。

nt stimer_expired(struct stimer *t) :檢查時間是否到期。

unsigned long stimer_remaining(struct stimer *t) :獲得剩餘時間。

The Etimer Library

Contiki etimer 庫提供了一個定時器機制,產生定時事件。當事件時間到期時,事件定時器將向進程標示PROCESS_EVENT_TIMER來設置定時器。在時鐘模塊中,Etimer庫使用clock_time()獲得系統當前時間。

事件定時器聲明爲struct etimer類型,所有訪問事件定時器都需要通過指針來指向被聲明的etimer時間。

Contiki etimer 庫的API 如下所示。如同前面的那些定時器,事件定時器總是調用etimer_set()初始化,設置定時器從當前時間開始到指定時間的延時。etimer_reset() 可以從之前的到期時間啓動定時器。Etimer_restart()從當前時間重啓定時器,他們都使用相同的時間間隔,且最初都是由etimer_set()設置。etimer_reset()和etimer_restart()的區別在於:前者的時間從以前的到期時間,而後者的時間從當前時間開始,從而允許時間推移。一個事件定時器可以被etimer_stop()停止,這意味着etimer立即過期,而不會發佈一個定時器事件。Etimer_expired()用來檢查一個etimer時間是否過期。

注意:定時器事件被髮送到contiki進程用來調度事件定時器。(太繞了,暫時這麼理解吧)如果一個事件定時器在回調函數或者其他的contiki進程被設置, PROCESS_CONTEXT_BEGIN() 和PROCESS_CONTEXT_END()可以被用來臨時改變進程上下文。在processes中有更多關於進程管理的信息。

下面是一個簡單的例子:如何用etimer每秒安排process運行一次。

Etimer 庫不能從中斷中安全使用。

Etimer 庫的API:

void etimer_set(struct etimer *t, clock_time_t interval) :啓動定時器。

void etimer_reset(struct etimer *t) :從以前到期時間重啓定時器。

void etimer_restart(struct etimer *t) :從當前時間重啓定時器。

void etimer_stop(struct etimer *t) :停止定時器。

int etimer_expired(struct etimer *t) :檢查時間是否到期。

int etimer_pending() :檢查是否有非過期的事件計時器。

clock_time_t etimer_next_expiration_time() :得到下一個事件定時器過期時間。

void etimer_request_poll() :通知etimer庫,系統時間已經改變。

設置一個事件定時器,讓process每秒執行一次。

PROCESS_THREAD(example_process, ev, data)

{

static struct etimer et;

PROCESS_BEGIN();

/* Delay 1 second */

etimer_set(&et, CLOCK_SECOND);

while(1) {

PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

/* Reset the etimer to trig again in 1 second */

etimer_reset(&et);

/* ... */

}

PROCESS_END();

}

Porting the Etimer Library

Etimer 庫實現的核心是/sys/etimer.c ,與平臺無關,但需要回調etimer_request_poll()來處理事件定時器。這允許事件定時器到期時,從低功耗模式喚醒。Etimer庫提供三種功能:

etimer_pending() 檢查是否有任何非過期事件定時器。

etimer_next_expiration_time() 得到下一個事件定時器過期時間。

etimer_request_poll() 通知etimer庫,系統時間已經改變,一個etimer已經過期。這個函數從中斷調用是安全的。

時鐘模塊處理系統時間之後,通常還要回調etimer庫。(這句也不太懂,原文The implementation of the clock module usually also handles the callbacks to the etimer library since the module already handles the system time )可以通過定期調用etimer_request_poll()簡單地實現,或者利用etime_next_expiration_time(),或者在需要時通知etimer庫。

The Ctimer Library

Contiki ctimer 庫提供了一個定時器機制,當回調時間過期時,調用指定的函數。在時鐘模塊中Ctimer庫使用clock_timer()獲得當前的系統時間。

Contiki ctimer 庫的API如下所示,他和etimer的庫很像。區別在於ctimer_set()需要一個回調函數指針和數據指針作爲參數。當ctimer到期時,他將數據指針作爲參數調用回調函數。下面的代碼展示了ctimer如何安排回調函數每秒調用一次。

注意:儘管這個回調定時器指定回調函數,但是ctimer安排進程上下文的回調。除非你確定回調定時器如何工作,否則不採取任何特定的進程上下文回調。

Ctimer 庫從中斷中使用不是安全的。

Ctimer 庫的API:

void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr) :啓動定時器。

void ctimer_reset(struct ctimer *t) :從以前到期的時間重啓定時器。

void ctimer_restart(struct ctimer *t) :從當前時間重啓定時器。

void ctimer_stop(struct ctimer *t) :停止定時器。

int ctimer_expired(struct ctimer *t) :檢查定時器是否過期。

設置一個ctimer,每秒調用一次函數。

static void

callback(void *ptr)

{

ctimer_reset(&timer);

/* ... */

}

void

init(void)

{

ctimer_set(&timer, CLOCK_SECOND, callback, NULL);

}

Porting the Ctimer Library

Ctimer 庫的實現使用etimer庫,不需要近一步移植。

The Rtimer Library

Contiki rtimer 庫提供了實時任務調度和執行(可預測執行時間)。Rtimer使用自己的時鐘模塊調度,允許更高的時鐘分辨率。RTIMER_SECOND()函數以嘀嗒的形式獲取當前系統時間,RTIMER_SECOND指定每秒的時鐘節拍數。

不像其他的contiki定時器庫,實時任務搶佔正常執行的進程,立即執行任務。在實時任務中能做什麼是有約束的,因爲大多數函數不處理具有優先權的任務。中斷安全函數例如asprocess_poll()在實時任務中總是安全的,但是任何可能的衝突與正常執行必須是同步的。

實時任務可以使用函數RTIMER_TIME(struct rtimer *t)在任務被執行的最後一次檢索所需的執行時間。

這裏沒有例子,這裏的文檔解釋的是從2007年以前的API,是誤導。

Porting the Rtimer Library

Rtimer 庫實現的核心是/sys/rtimer.c ,與平臺無關,取決於rtime-arch.c處理平臺的相關功能,如調度等。下面三個功能在移植rtimer庫是需要實現。

rtimer_arch_init() 被rtimer庫調用,初始化rtimer代碼。

rtimer_arch_now() 用來獲取當前的系統實時時間。

rtimer_arch_schedule() 需要一個參數---喚醒時間,請求喚醒回調。

除了這三個函數,rtimer架構代碼需要定義RTIMER_ARCH_SECOND作爲每秒的滴答數,rtimer_clock_t數據類型用於rtimer時間,這些都是在rtimer-arch.h文件中聲明的。

Rtimer 庫與平臺相關的函數:

RTIMER_ARCH_SECOND :每秒的滴答數。

void rtimer_arch_init(void) :初始化rtimer。

rtimer_clock_t rtimer_arch_now() :獲取當前時間。

int rtimer_arch_schedule(rtimer_clock_t wakeup_time) :安排一個rtimer_run_next()調用。

Conclusions

Contiki 包含一組定時器庫,應用於contiki核心模塊和應用程序。定時器庫用來檢測超時、安排處理事件和函數回調來讓系統處理一些其他事情,或者進入低功耗模式一段時間,在這之後恢復執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章