]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/tossim/HilTimerMilliC.nc
Merge devel code into the trunk.
[tinyos-2.x.git] / tos / lib / tossim / HilTimerMilliC.nc
diff --git a/tos/lib/tossim/HilTimerMilliC.nc b/tos/lib/tossim/HilTimerMilliC.nc
new file mode 100644 (file)
index 0000000..0f1b4a2
--- /dev/null
@@ -0,0 +1,173 @@
+// $Id$
+/*
+ * "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."
+ */
+
+/**
+ * This is a TOSSIM-specific implementation of TimerMilliC that
+ * directly emulates timers rather than their underlying hardware.  It
+ * is intended to be a basic fill-in for microcontrollers that do not
+ * have TOSSIM simulation support.
+ *
+ * @author Philip Levis
+ * @date   December 1 2005
+ */
+
+#include <Timer.h>
+
+module HilTimerMilliC {
+  provides interface Init;
+  provides interface Timer<TMilli> as TimerMilli[uint8_t num];
+}
+implementation {
+
+  enum {
+    TIMER_COUNT = uniqueCount("UQ_TIMER_MILLI")
+  };
+
+  typedef struct tossim_timer {
+    uint32_t t0;
+    uint32_t dt;
+    bool isPeriodic;
+    bool isActive;
+    sim_event_t* evt;
+  } tossim_timer_t;
+
+  tossim_timer_t timers[TIMER_COUNT];
+  sim_time_t initTime;
+
+  void initializeEvent(sim_event_t* evt, uint8_t timerID);
+  
+  sim_time_t clockToSim(sim_time_t clockVal) {
+    return (clockVal * sim_ticks_per_sec()) / 1024;
+  }
+
+  sim_time_t simToClock(sim_time_t sim) {
+    return (sim * 1024) / sim_ticks_per_sec();
+  }
+  
+  command error_t Init.init() {
+    memset(timers, 0, sizeof(timers));
+    initTime = sim_time();
+    return SUCCESS;
+  }
+  
+  command void TimerMilli.startPeriodic[uint8_t id]( uint32_t dt ) {
+    call TimerMilli.startPeriodicAt[id](call TimerMilli.getNow[id](), dt);
+  }
+  command void TimerMilli.startOneShot[uint8_t id]( uint32_t dt ) {
+    call TimerMilli.startOneShotAt[id](call TimerMilli.getNow[id](), dt);
+  }
+
+  command void TimerMilli.stop[uint8_t id]() {
+    timers[id].isActive = 0;
+    if (timers[0].evt != NULL) {
+      timers[0].evt->cancelled = 1;
+      timers[0].evt->cleanup = sim_queue_cleanup_total;
+      timers[0].evt = NULL;
+    }
+  }
+
+  // extended interface
+  command bool TimerMilli.isRunning[uint8_t id]() {return timers[id].isActive;}
+  command bool TimerMilli.isOneShot[uint8_t id]() {return !timers[id].isActive;}
+  
+  command void TimerMilli.startPeriodicAt[uint8_t id]( uint32_t t0, uint32_t dt ) {
+    call TimerMilli.startOneShotAt[id](t0, dt);
+    timers[id].isPeriodic = 1;
+  }
+  command void TimerMilli.startOneShotAt[uint8_t id]( uint32_t t0, uint32_t dt ) {
+    uint32_t currentTime = call TimerMilli.getNow[id]();
+    sim_time_t fireTime = sim_time();
+
+    call TimerMilli.stop[id]();
+    
+    timers[id].evt = sim_queue_allocate_event();
+    initializeEvent(timers[id].evt, id);
+
+    fireTime += clockToSim(dt);
+    
+    // Be careful about signing and casts, etc.
+    if (currentTime > t0) {
+      fireTime -= clockToSim(currentTime - t0);
+    }
+    else {
+      fireTime += clockToSim(t0 - currentTime);      
+    }
+
+    timers[id].evt->time = fireTime;
+    timers[id].isPeriodic = 0;
+    timers[id].isActive = 1;
+    timers[id].t0 = t0;
+    timers[id].dt = dt;
+
+    sim_queue_insert(timers[id].evt);
+  }
+    
+  command uint32_t TimerMilli.getNow[uint8_t id]() {
+    sim_time_t nowTime = sim_time();
+    nowTime -= initTime;
+    nowTime = simToClock(nowTime);
+    return nowTime & 0xffffffff;
+  }
+  
+  command uint32_t TimerMilli.gett0[uint8_t id]() {
+    return timers[id].t0;
+  }
+  command uint32_t TimerMilli.getdt[uint8_t id]() {
+    return timers[id].dt;
+  }
+
+  void tossim_timer_handle(sim_event_t* evt) {
+    uint8_t* datum = (uint8_t*)evt->data;
+    uint8_t id = *datum;
+    signal TimerMilli.fired[id]();
+
+    // We should only re-enqueue the event if it is a follow-up firing
+    // of the same timer.  If the timer is stopped, it's a one shot,
+    // or someone has started a new timer, don't re-enqueue it.
+    if (timers[id].isActive &&
+       timers[id].isPeriodic &&
+       timers[id].evt == evt) {
+      evt->time = evt->time += clockToSim(timers[id].dt);
+      sim_queue_insert(evt);
+    }
+    // If we aren't enqueueing it, and nobody has done something that
+    // would cause the event to have been garbage collected, then do
+    // so.
+    else if (timers[id].evt == evt) {
+      call TimerMilli.stop[id]();
+    }
+  }
+  
+  void initializeEvent(sim_event_t* evt, uint8_t timerID) {
+    uint8_t* data = (uint8_t*)malloc(sizeof(uint8_t));
+    *data = timerID;
+
+    evt->handle = tossim_timer_handle;
+    evt->cleanup = sim_queue_cleanup_none;
+    evt->data = data;
+  }
+
+ default event void TimerMilli.fired[uint8_t id]() {}
+}
+