📄 hplatm128timer0asyncp.nc
字号:
/*
* "Copyright (c) 2005 Stanford University. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose, without fee, and without written
* agreement is hereby granted, provided that the above copyright
* notice, the following two paragraphs and the author appear in all
* copies of this software.
*
* IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* STANFORD UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
* PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND STANFORD UNIVERSITY
* HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS."
*/
/**
* The TOSSIM implementation of the Atm128 Timer0 counter. It handles
* overflow, scaling, and phase considerations.
*
* @date November 22 2005
*
* @author Philip Levis <pal@cs.stanford.edu>
* @author Martin Turon <mturon@xbow.com>
* @author David Gay <dgay@intel-research.net>
*/
// $Id: HplAtm128Timer0AsyncP.nc,v 1.1 2008/06/12 14:02:20 klueska Exp $/// $Id: HplAtm128Timer2C.nc,
#include <Atm128Timer.h>
#include <hardware.h>
module HplAtm128Timer0AsyncP {
provides {
interface HplAtm128Timer<uint8_t> as Timer0;
interface HplAtm128TimerCtrl8 as Timer0Ctrl;
interface HplAtm128Compare<uint8_t> as Compare;
interface HplAtm128TimerAsync as TimerAsync;
}
uses interface ThreadScheduler;
}
implementation {
bool inOverflow = 0;
uint8_t savedCounter = 0;
void adjust_zero(uint8_t currentCounter);
void cancel_overflow();
sim_event_t* allocate_overflow();
void configure_overflow(sim_event_t* e);
void schedule_new_overflow();
sim_time_t clock_to_sim(sim_time_t t);
sim_time_t sim_to_clock(sim_time_t t);
uint16_t shiftFromScale();
/* lastZero keeps track of the phase of the clock. It denotes the sim
* time at which the underlying clock started, which is needed to
* calculate when compares will occur. */
sim_time_t lastZero = 0;
/** This variable is needed to keep track of when the underlying
* timer starts, in order to reset lastZero. When oldScale is
* AVR_CLOCK_OFF and the scale is set to something else, the
* clock starts ticking. */
uint8_t oldScale = AVR_CLOCK_OFF;
void adjust_zero(uint8_t currentCounter);
void cancel_compare();
sim_event_t* allocate_compare();
void configure_compare(sim_event_t* e);
void schedule_new_compare();
sim_time_t clock_to_sim(sim_time_t t);
sim_time_t sim_to_clock(sim_time_t t);
uint16_t shiftFromScale();
default async event void Compare.fired() { }
AVR_ATOMIC_HANDLER(SIG_OUTPUT_COMPARE0) {
//stabiliseTimer0();
signal Compare.fired();
call ThreadScheduler.interruptPostAmble();
}
default async event void Timer0.overflow() { }
AVR_ATOMIC_HANDLER(SIG_OVERFLOW0) {
inOverflow = TRUE;
signal Timer0.overflow();
inOverflow = FALSE;
call ThreadScheduler.interruptPostAmble();
}
sim_time_t last_zero() {
if (lastZero == 0) {
lastZero = sim_mote_start_time(sim_node());
}
return lastZero;
}
void notify_changed() {
uint8_t newScale = call Timer0.getScale();
if (newScale != AVR_CLOCK_OFF &&
oldScale == AVR_CLOCK_OFF) {
lastZero = sim_time();
}
oldScale = newScale;
schedule_new_compare();
}
sim_time_t notify_clockTicksPerSec() {
return ATM128_TIMER0_TICKSPPS;
}
/**
* If the clock was stopped and has restarted, then
* we need to move the time when the clock was last
* zero to a time that reflects the current settings.
* For example, if the clock was stopped when the counter
* was 52 and then later restarted, then <tt>lastZero</tt>
* needs to be moved forward in time so that the 52
* reflects the current time.
*/
void adjust_zero(uint8_t currentCounter) {
sim_time_t now = sim_time();
sim_time_t adjust = currentCounter;
adjust = adjust << shiftFromScale();
adjust = clock_to_sim(adjust);
lastZero = now - adjust;
}
sim_time_t clock_to_sim(sim_time_t t) {
t *= sim_ticks_per_sec();
t /= notify_clockTicksPerSec();
return t;
}
sim_time_t sim_to_clock(sim_time_t t) {
t *= notify_clockTicksPerSec();
t /= sim_ticks_per_sec();
return t;
}
uint16_t shiftFromScale() {
uint8_t scale = call Timer0.getScale();
switch (scale) {
case 0:
return 0;
case 1:
return 0;
case 2:
return 3;
case 3:
return 5;
case 4:
return 6;
case 5:
return 7;
case 6:
return 8;
case 7:
return 10;
default:
return 255;
}
}
sim_event_t* compare;
void timer0_compare_handle(sim_event_t* evt) {
dbg("HplAtm128Timer0AsyncP", "Beginning compare 0x%p at %s\n", evt, sim_time_string());
if (evt->cancelled) {
return;
}
else {
char timeStr[128];
sim_print_now(timeStr, 128);
dbg("HplAtm128Timer0AsyncP", "Handling compare at 0x%p @ %s\n", evt, sim_time_string());
if (READ_BIT(ATM128_TCCR0, WGM01) && !READ_BIT(ATM128_TCCR0, WGM00)) {
dbg("HplAtm128Timer0AsyncP", "%s: CTC is set, clear timer.\n", __FUNCTION__);
call Timer0.set(0);
}
else {
dbg("HplAtm128Timer0AsyncP", "%s: TCCR is 0x%hhx, %i, %i\n", __FUNCTION__, TCCR0, (int)READ_BIT(ATM128_TCCR0, WGM01), (int)READ_BIT(ATM128_TCCR0, WGM00));
}
if (READ_BIT(ATM128_TIMSK, OCIE0)) {
dbg("HplAtm128Timer0AsyncP", "TIFR is %hhx\n", TIFR);
CLR_BIT(ATM128_TIFR, OCF0);
dbg("HplAtm128Timer0AsyncP", "TIFR is %hhx\n", TIFR);
dbg("HplAtm128Timer0AsyncP", "Compare interrupt @ %s\n", timeStr);
SIG_OUTPUT_COMPARE0();
}
else {
SET_BIT(ATM128_TIFR, OCF0);
}
// If we haven't been cancelled
if (!evt->cancelled) {
configure_compare(evt);
sim_queue_insert(evt);
}
}
}
sim_event_t* allocate_compare() {
sim_event_t* newEvent = sim_queue_allocate_event();
dbg("HplAtm128Timer0AsyncP", "Allocated compare at 0x%p\n", newEvent);
newEvent->handle = timer0_compare_handle;
newEvent->cleanup = sim_queue_cleanup_none;
return newEvent;
}
void configure_compare(sim_event_t* evt) {
sim_time_t compareTime = 0;
sim_time_t phaseOffset = 0;
uint8_t timerVal = call Timer0.get();
uint8_t compareVal = call Compare.get();
// Calculate how many counter increments until timer
// hits compare, considering wraparound, and special
// case of complete wraparound.
compareTime = ((compareVal - timerVal) & 0xff);
if (compareTime == 0) {
compareTime = 256;
}
// Now convert the compare time from counter increments
// to simulation ticks, considering the fact that the
// increment actually has a phase offset.
// The +1 is from the timer behavior: if you set OCR0 to be X,
// it will actually fire when TCNT is X+1
compareTime = (compareTime + 1) << shiftFromScale();
compareTime = clock_to_sim(compareTime);
compareTime += sim_time();
// How long into a timer tick was the clock actually reset?
// This covers the case when the compare is set midway between
// a tick, so it will go off a little early
phaseOffset = sim_time();
phaseOffset -= last_zero();
phaseOffset %= clock_to_sim(1 << shiftFromScale());
compareTime -= phaseOffset;
dbg("HplAtm128Timer0AsyncP", "Configuring new compare of %i for %i at time %llu (@ %llu)\n", (int)compareVal, sim_node(), compareTime, sim_time());
evt->time = compareTime;
}
void schedule_new_compare() {
if (compare != NULL) {
cancel_compare();
}
if (call Timer0.getScale() != AVR_CLOCK_OFF) {
sim_event_t* newEvent = allocate_compare();
configure_compare(newEvent);
compare = newEvent;
sim_queue_insert(newEvent);
}
}
//=== Read the current timer value. ===================================
async command uint8_t Timer0.get() {
uint8_t rval;
sim_time_t elapsed = sim_time() - last_zero();
elapsed = sim_to_clock(elapsed);
elapsed = elapsed >> shiftFromScale();
rval = (uint8_t)(elapsed & 0xff);
dbg("HplAtm128Timer0AsyncP", "HplAtm128Timer0AsyncP: Getting timer: %hhu\n", rval);
return rval;
}
//=== Set/clear the current timer value. ==============================
/**
* Set/clear the current timer value.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -