Index: Oscilloscope/OscilloscopeC.nc
===================================================================
--- Oscilloscope/OscilloscopeC.nc	(revision 5158)
+++ Oscilloscope/OscilloscopeC.nc	(working copy)
@@ -12,6 +12,7 @@
  * Oscilloscope demo application. See README.txt file in this directory.
  *
  * @author David Gay
+ * @author Roger Larsson, ltu.se
  */
 #include "Timer.h"
 #include "Oscilloscope.h"
@@ -20,22 +21,25 @@
 {
   uses {
     interface Boot;
-    interface SplitControl as RadioControl;
+    interface SplitControl as CommunicationControl;
     interface AMSend;
     interface Receive;
     interface Timer<TMilli>;
-    interface Read<uint16_t>;
+    interface Read<uint16_t> as ChannelRead[uint8_t];
     interface Leds;
+    interface GeneralIO as Enable;
   }
 }
 implementation
 {
   message_t sendBuf;
   bool sendBusy;
+  bool sendQueue;
 
   /* Current local state - interval, version and accumulated readings */
   oscilloscope_t local;
 
+  uint8_t oversample; /* local.oversample downto 0 */
   uint8_t reading; /* 0 to NREADINGS */
 
   /* When we head an Oscilloscope message, we check it's sample count. If
@@ -53,20 +57,39 @@
   event void Boot.booted() {
     local.interval = DEFAULT_INTERVAL;
     local.id = TOS_NODE_ID;
-    if (call RadioControl.start() != SUCCESS)
+    local.oversample = 10;
+    local.channels = uniqueCount("Channel");
+    if (call CommunicationControl.start() != SUCCESS)
       report_problem();
+    call Enable.set();
   }
 
+  void prepareReadings()
+  {
+	uint8_t cc;
+	for (cc=0; cc < NREADINGS; cc++)
+	    local.readings[cc] = 0;
+
+	reading = 0;
+	oversample = local.oversample;
+
+	/* Part 2 of cheap "time sync": increment our count if we didn't
+	   jump ahead. */
+	if (!suppressCountChange)
+	  local.count++;
+	suppressCountChange = FALSE;
+  }
+
   void startTimer() {
     call Timer.startPeriodic(local.interval);
-    reading = 0;
+    prepareReadings();
   }
 
-  event void RadioControl.startDone(error_t error) {
+  event void CommunicationControl.startDone(error_t error) {
     startTimer();
   }
 
-  event void RadioControl.stopDone(error_t error) {
+  event void CommunicationControl.stopDone(error_t error) {
   }
 
   event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
@@ -83,7 +106,7 @@
 	local.interval = omsg->interval;
 	startTimer();
       }
-    if (omsg->count > local.count)
+    if (omsg->count > local.count) /* TODO: review wrap handling... */
       {
 	local.count = omsg->count;
 	suppressCountChange = TRUE;
@@ -93,34 +116,52 @@
   }
 
   /* At each sample period:
-     - if local sample buffer is full, send accumulated samples
+     - if local sample buffer is full, copy accumulated samples
      - read next sample
+     - send samples
   */
   event void Timer.fired() {
-    if (reading == NREADINGS)
+    const int readings_fit = NREADINGS/uniqueCount("Channel");
+
+    /* Copy (minimal work before conversation start) */
+    if (reading == readings_fit) {
+        // Last chance to update local fields here!
+ 	if (sizeof local > call AMSend.maxPayloadLength()) {
+	   report_problem();
+	} else {
+	     memcpy(call AMSend.getPayload(&sendBuf, sizeof(local)), &local, sizeof local);
+	     sendQueue = TRUE;
+        }
+    }
+
+    /* Start conversation (before sending to minimize jitter) */
+    /* TODO: Start conversation for all channels when fired */
+    if (call ChannelRead.read[0U]() != SUCCESS)
+       report_problem();
+
+    if (reading == readings_fit) {
+	prepareReadings(); /* will reset readings too */
+    }
+
+    /* Send */
+    if (sendQueue)
       {
-	if (!sendBusy && sizeof local <= call AMSend.maxPayloadLength())
+	if (!sendBusy)
 	  {
-	    // Don't need to check for null because we've already checked length
-	    // above
-	    memcpy(call AMSend.getPayload(&sendBuf, sizeof(local)), &local, sizeof local);
-	    if (call AMSend.send(AM_BROADCAST_ADDR, &sendBuf, sizeof local) == SUCCESS)
+	    if (call AMSend.send(AM_BROADCAST_ADDR, &sendBuf, sizeof local) == SUCCESS) {
+	      sendQueue = FALSE;
 	      sendBusy = TRUE;
+	    }
 	  }
 	if (!sendBusy)
 	  report_problem();
 
-	reading = 0;
-	/* Part 2 of cheap "time sync": increment our count if we didn't
-	   jump ahead. */
-	if (!suppressCountChange)
-	  local.count++;
-	suppressCountChange = FALSE;
       }
-    if (call Read.read() != SUCCESS)
-      report_problem();
+
   }
 
+
+
   event void AMSend.sendDone(message_t* msg, error_t error) {
     if (error == SUCCESS)
       report_sent();
@@ -130,13 +171,31 @@
     sendBusy = FALSE;
   }
 
-  event void Read.readDone(error_t result, uint16_t data) {
+  default command error_t ChannelRead.read[uint8_t]() {}
+
+  event void ChannelRead.readDone[uint8_t channel](error_t result, uint16_t data) {
     if (result != SUCCESS)
       {
 	data = 0xffff;
 	report_problem();
       }
-    if (reading < NREADINGS) 
-      local.readings[reading++] = data;
+
+    if (channel < uniqueCount("Channel")) {
+       local.readings[reading*uniqueCount("Channel") + channel] += data;
+    }
+
+    /* NEXT CHANNEL */
+    channel++;
+    if (channel == uniqueCount("Channel")) {
+       if (--oversample == 0) {
+       	  reading++;
+	  oversample = local.oversample;
+       }
+       return;
+    }
+    if (call ChannelRead.read[channel]() != SUCCESS)
+       report_problem();
   }
+
 }
+
Index: Oscilloscope/java/Graph.java
===================================================================
--- Oscilloscope/java/Graph.java	(revision 5158)
+++ Oscilloscope/java/Graph.java	(working copy)
@@ -164,34 +164,42 @@
     /* Inner class to simplify drawing a graph. Simplify initialise it, then
        feed it the X screen and graph coordinates, from left to right. */
     private class SingleGraph {
-    int lastsx, lastsy, nodeId;
+    int lastsx, lastsy[], nodeId;
 
     /* Start drawing the graph mote id */
     SingleGraph(Graphics g, int id) {
         nodeId = id;
         lastsx = -1;
-        lastsy = -1;
+        lastsy = null;
     }
 
     /* Next point in mote's graph is at x value gx, screen coordinate sx */
     void nextPoint(Graphics g, int gx, int sx) {
-        int gy = parent.parent.data.getData(nodeId, gx);
-        int sy = -1;
+        int gy[] = parent.parent.data.getData(nodeId, gx);
+	for (int ch=0; gy != null && ch<gy.length; ch++) {
+	    int sy = -1;
 
-        if (gy >= 0) { // Ignore missing values
-        double rsy = height - yscale * (gy - gy0);
+	    if (gy != null && gy[ch] >= 0) { // Ignore missing values
+		double rsy = height - yscale * (gy[ch] - gy0);
 
-        // Ignore problem values
-        if (rsy >= -1e6 && rsy <= 1e6) {
-            sy = (int)(rsy + 0.5);
-        }
+		// Ignore problem values
+		if (rsy >= -1e6 && rsy <= 1e6) {
+		    sy = (int)(rsy + 0.5);
+		}
 
-        if (lastsy >= 0 && sy >= 0) {
-            g.drawLine(lastsx, lastsy, sx, sy);
-        }
-        }
-        lastsx = sx;
-        lastsy = sy;
+		// Got OK value, length should be OK too
+		if (lastsy == null) {
+		    lastsy = new int[gy.length];
+		}
+		else if (lastsy[ch] >= 0 && sy >= 0) {
+		    g.drawLine(lastsx, lastsy[ch], sx, sy);
+		}
+	    }
+	    // Wait for OK value
+	    if (lastsy != null)
+		lastsy[ch] = sy;
+	}
+	lastsx = sx;
     }
     }
 
Index: Oscilloscope/java/run
===================================================================
--- Oscilloscope/java/run	(revision 5158)
+++ Oscilloscope/java/run	(working copy)
@@ -1,4 +1,5 @@
 #!/bin/sh
+cd `dirname $0`
 if cygpath -w / >/dev/null 2>/dev/null; then
   CLASSPATH="oscilloscope.jar;$CLASSPATH"
 else
Index: Oscilloscope/java/Node.java
===================================================================
--- Oscilloscope/java/Node.java	(revision 5158)
+++ Oscilloscope/java/Node.java	(working copy)
@@ -8,6 +8,8 @@
  * 94704.  Attention:  Intel License Inquiry.
  */
 
+import java.util.*;
+
 /**
  * Class holding all data received from a mote.
  */
@@ -16,7 +18,9 @@
        INCREMENT itself must be a multiple of Constant.NREADINGS. This
        simplifies handling the extension and clipping of old data
        (see setEnd) */
-    final static int INCREMENT = 100 * Constants.NREADINGS;
+    final static int CHANNELS = Constants.NCHANNELS;
+    final static int WINDOW = 1;
+    final static int INCREMENT = 100 * Constants.NREADINGS/WINDOW;
     final static int MAX_SIZE = 100 * INCREMENT; // Must be multiple of INCREMENT
 
     /* The mote's identifier */
@@ -25,54 +29,40 @@
     /* Data received from the mote. data[0] is the dataStart'th sample
        Indexes 0 through dataEnd - dataStart - 1 hold data.
        Samples are 16-bit unsigned numbers, -1 indicates missing data. */
-    int[] data;
+    Vector data;
     int dataStart, dataEnd;
 
+    float[] window_func;
+
     Node(int _id) {
     id = _id;
+    window_func = new float[WINDOW];
+    for (int i=0; i<WINDOW; i++) {
+	window_func[i] = 1.0f; // rectangular
     }
+    }
 
     /* Update data to hold received samples newDataIndex .. newEnd.
        If we receive data with a lower index, we discard newer data
        (we assume the mote rebooted). */
     private void setEnd(int newDataIndex, int newEnd) {
+	
     if (newDataIndex < dataStart || data == null) {
-        /* New data is before the start of what we have. Just throw it
-           all away and start again */
+        // New data is before the start of what we have. Just throw it
+        //   all away and start again
+	System.out.println("DEBUG: data is before our start");
+
         dataStart = newDataIndex;
-        data = new int[INCREMENT];
+	dataEnd = newDataIndex;
+        data = new Vector();
     }
-    if (newEnd > dataStart + data.length) {
-        /* Try extending first */
-        if (data.length < MAX_SIZE) {
-        int newLength = (newEnd - dataStart + INCREMENT - 1) / INCREMENT * INCREMENT;
-        if (newLength >= MAX_SIZE) {
-            newLength = MAX_SIZE;
-        }
+    data.ensureCapacity(newEnd - dataStart + 1);
+    // System.out.println("DEBUG: setend(" + newDataIndex + ", " + newEnd + ") with dataStart=" + dataStart + " dataEnd=" + dataEnd);
 
-        int[] newData = new int[newLength];
-        System.arraycopy(data, 0, newData, 0, data.length);
-        data = newData;
-
-        }
-        if (newEnd > dataStart + data.length) {
-        /* Still doesn't fit. Squish.
-           We assume INCREMENT >= (newEnd - newDataIndex), and ensure
-           that dataStart + data.length - INCREMENT = newDataIndex */
-        int newStart = newDataIndex + INCREMENT - data.length;
-
-        if (dataStart + data.length > newStart) {
-            System.arraycopy(data, newStart - dataStart, data, 0,
-                     data.length - (newStart - dataStart));
-        }
-        dataStart = newStart;
-        }
-    }
     /* Mark any missing data as invalid */
-    for (int i = dataEnd < dataStart ? dataStart : dataEnd;
-         i < newDataIndex; i++) {
-        data[i - dataStart] = -1;
-    }
+    /* Fill to start position, from old end to new start */
+    for (int i = dataEnd; i < newDataIndex; i++)
+	data.add(null);
 
     /* If we receive a count less than the old count, we assume the old
        data is invalid */
@@ -82,20 +72,23 @@
 
     /* Data received containing NREADINGS samples from messageId * NREADINGS 
        onwards */
-    void update(int messageId, int[] readings) {
-    int start = messageId * Constants.NREADINGS;
-    setEnd(start, start + Constants.NREADINGS);
-    for (int i = 0; i < readings.length; i++) {
-        data[start - dataStart + i] = readings[i];
+    void update(int messageId, int[][] readings) {
+	int len = readings.length;
+	int start = messageId * len; // assume all messages of same length...
+
+	setEnd(start, start + len);
+
+	for (int i = 0; i < len; i++) {
+	    data.add(readings[i]);
+	}
     }
-    }
 
     /* Return value of sample x, or -1 for missing data */
-    int getData(int x) {
+    int[] getData(int x) {
     if (x < dataStart || x >= dataEnd) {
-        return -1;
+        return null;
     } else {
-        return data[x - dataStart];
+        return (int[])data.get(x - dataStart);
     }
     }
 
Index: Oscilloscope/java/Data.java
===================================================================
--- Oscilloscope/java/Data.java	(revision 5158)
+++ Oscilloscope/java/Data.java	(working copy)
@@ -23,7 +23,8 @@
 
     /* Data received from mote nodeId containing NREADINGS samples from
        messageId * NREADINGS onwards. Tell parent if this is a new node. */
-    void update(int nodeId, int messageId, int readings[]) {
+    void update(int nodeId, int messageId, int readings[][]) {
+	/* TODO: rewrite to use Vector */
     if (nodeId >= nodes.length) {
         int newLength = nodes.length * 2;
         if (nodeId >= newLength) {
@@ -43,9 +44,9 @@
     }
 
     /* Return value of sample x for mote nodeId, or -1 for missing data */
-    int getData(int nodeId, int x) {
+    int[] getData(int nodeId, int x) {
     if (nodeId >= nodes.length || nodes[nodeId] == null)
-        return -1;
+        return new int[0];
     return nodes[nodeId].getData(x);
     }
 
Index: Oscilloscope/OscilloscopeAppC.nc
===================================================================
--- Oscilloscope/OscilloscopeAppC.nc	(revision 5158)
+++ Oscilloscope/OscilloscopeAppC.nc	(working copy)
@@ -19,17 +19,35 @@
 configuration OscilloscopeAppC { }
 implementation
 {
-  components OscilloscopeC, MainC, ActiveMessageC, LedsC,
-    new TimerMilliC(), new DemoSensorC() as Sensor, 
-    new AMSenderC(AM_OSCILLOSCOPE), new AMReceiverC(AM_OSCILLOSCOPE);
+  components DelugeC;
+  components LedsC;
 
+  DelugeC.Leds -> LedsC;
+
+  components OscilloscopeC, MainC,
+    new TimerMilliC(), HplMMA7261QTC as Accel;
+#ifdef DELUGE_BASESTATION
+  components SerialActiveMessageC as ActiveMessageC_,
+    new SerialAMSenderC(AM_OSCILLOSCOPE) as AMSenderC_,
+    new SerialAMReceiverC(AM_OSCILLOSCOPE) as AMReceiverC_;
+#else
+  components ActiveMessageC as ActiveMessageC_,
+    new AMSenderC(AM_OSCILLOSCOPE) as AMSenderC_,
+    new AMReceiverC(AM_OSCILLOSCOPE) as AMReceiverC_;
+#endif
+
+
   OscilloscopeC.Boot -> MainC;
-  OscilloscopeC.RadioControl -> ActiveMessageC;
-  OscilloscopeC.AMSend -> AMSenderC;
-  OscilloscopeC.Receive -> AMReceiverC;
+  OscilloscopeC.CommunicationControl -> ActiveMessageC_;
+  OscilloscopeC.AMSend -> AMSenderC_;
+  OscilloscopeC.Receive -> AMReceiverC_;
   OscilloscopeC.Timer -> TimerMilliC;
-  OscilloscopeC.Read -> Sensor;
+
+  OscilloscopeC.ChannelRead[unique("Channel")] -> Accel.AccelX;
+  OscilloscopeC.ChannelRead[unique("Channel")] -> Accel.AccelY;
+  OscilloscopeC.ChannelRead[unique("Channel")] -> Accel.AccelZ;
+
   OscilloscopeC.Leds -> LedsC;
-
+  OscilloscopeC.Enable -> Accel.Sleep; /* Sleep is active low */ 
   
 }
Index: Oscilloscope/Oscilloscope.h
===================================================================
--- Oscilloscope/Oscilloscope.h	(revision 5158)
+++ Oscilloscope/Oscilloscope.h	(working copy)
@@ -16,7 +16,7 @@
 enum {
   /* Number of readings per message. If you increase this, you may have to
      increase the message_t size. */
-  NREADINGS = 10,
+  NREADINGS = 9,
 
   /* Default sampling period. */
   DEFAULT_INTERVAL = 256,
@@ -29,6 +29,8 @@
   nx_uint16_t interval; /* Samping period. */
   nx_uint16_t id; /* Mote id of sending mote. */
   nx_uint16_t count; /* The readings are samples count * NREADINGS onwards */
+  nx_uint8_t  oversample; /* readings are accumulated, rectangle window - simple addition */
+  nx_uint8_t  channels; /* no of interleaved channels in readings */
   nx_uint16_t readings[NREADINGS];
 } oscilloscope_t;
 
Index: Oscilloscope/Makefile
===================================================================
--- Oscilloscope/Makefile	(revision 5158)
+++ Oscilloscope/Makefile	(working copy)
@@ -1,3 +1,6 @@
 COMPONENT=OscilloscopeAppC
+BOOTLOADER=tosboot
 
+#CFLAGS += -DDELUGE_LIGHT_BASESTATION
+
 include $(MAKERULES)
