From 302a07344cdf7f6f37207c766e9ad3de25ea54bf Mon Sep 17 00:00:00 2001 From: nifi Date: Tue, 31 Aug 2010 13:05:40 +0000 Subject: [PATCH] * Updated to show base shape in line charts (can be disabled in menu) * Added simple packet delivery chart based on sequence numbers --- .../sics/contiki/collect/CollectServer.java | 26 ++- .../se/sics/contiki/collect/SensorData.java | 19 +- .../contiki/collect/SensorDataAggregator.java | 27 ++- .../contiki/collect/gui/SeqnoChartPanel.java | 183 ++++++++++++++++++ .../contiki/collect/gui/TimeChartPanel.java | 16 +- 5 files changed, 257 insertions(+), 14 deletions(-) create mode 100644 examples/sky-shell/src/se/sics/contiki/collect/gui/SeqnoChartPanel.java diff --git a/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java b/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java index 5c2082f7a..9f02319a0 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: CollectServer.java,v 1.9 2008/11/10 21:14:20 adamdunkels Exp $ + * $Id: CollectServer.java,v 1.10 2010/08/31 13:05:40 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2008/11/10 21:14:20 $ - * $Revision: 1.9 $ + * Updated : $Date: 2010/08/31 13:05:40 $ + * $Revision: 1.10 $ */ package se.sics.contiki.collect; @@ -82,6 +82,7 @@ import se.sics.contiki.collect.gui.BarChartPanel; import se.sics.contiki.collect.gui.MapPanel; import se.sics.contiki.collect.gui.SerialConsole; import se.sics.contiki.collect.gui.TimeChartPanel; +import se.sics.contiki.collect.gui.SeqnoChartPanel; /** * @@ -350,6 +351,7 @@ public class CollectServer { return data.getLatency(); } }, + new SeqnoChartPanel(this, "Received Packets", "Received Packets", "Seqno", "Received Packets"), serialConsole }; for (int i = 0, n = visualizers.length; i < n; i++) { @@ -458,6 +460,24 @@ public class CollectServer { toolsMenu.add(runInitScriptItem); toolsMenu.addSeparator(); + final JCheckBoxMenuItem baseShapeItem = new JCheckBoxMenuItem("Base Shape Visible"); + baseShapeItem.setSelected(true); + baseShapeItem.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) { + boolean visible = baseShapeItem.getState(); + if (visualizers != null) { + for(Visualizer v : visualizers) { + if (v instanceof TimeChartPanel) { + ((TimeChartPanel)v).setBaseShapeVisible(visible); + } + } + } + } + + }); + toolsMenu.add(baseShapeItem); + final JCheckBoxMenuItem scrollItem = new JCheckBoxMenuItem("Scroll Layout"); scrollItem.addActionListener(new ActionListener() { diff --git a/examples/sky-shell/src/se/sics/contiki/collect/SensorData.java b/examples/sky-shell/src/se/sics/contiki/collect/SensorData.java index fce0b2839..58b669858 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/SensorData.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/SensorData.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: SensorData.java,v 1.7 2010/02/04 16:21:47 adamdunkels Exp $ + * $Id: SensorData.java,v 1.8 2010/08/31 13:05:40 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2010/02/04 16:21:47 $ - * $Revision: 1.7 $ + * Updated : $Date: 2010/08/31 13:05:40 $ + * $Revision: 1.8 $ */ package se.sics.contiki.collect; @@ -50,12 +50,14 @@ public class SensorData implements SensorInfo { private final int[] values; private final long nodeTime; private final long systemTime; + private int seqno; public SensorData(Node node, int[] values, long systemTime) { this.node = node; this.values = values; this.nodeTime = ((values[TIMESTAMP1] << 16) + values[TIMESTAMP2]) * 1000L; this.systemTime = systemTime; + this.seqno = values[SEQNO]; } public Node getNode() { @@ -66,6 +68,14 @@ public class SensorData implements SensorInfo { return node.getID(); } + public int getSeqno() { + return seqno; + } + + public void setSeqno(int seqno) { + this.seqno = seqno; + } + public int getValue(int index) { return values[index]; } @@ -189,9 +199,8 @@ public class SensorData implements SensorInfo { double v = -4.0 + 405.0 * values[HUMIDITY] / 10000.0; if(v > 100) { return 100; - } else { - return v; } + return v; } public double getLight1() { diff --git a/examples/sky-shell/src/se/sics/contiki/collect/SensorDataAggregator.java b/examples/sky-shell/src/se/sics/contiki/collect/SensorDataAggregator.java index b6ea6ff98..c746c18d4 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/SensorDataAggregator.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/SensorDataAggregator.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: SensorDataAggregator.java,v 1.2 2008/11/26 14:22:54 nifi Exp $ + * $Id: SensorDataAggregator.java,v 1.3 2010/08/31 13:05:40 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 20 aug 2008 - * Updated : $Date: 2008/11/26 14:22:54 $ - * $Revision: 1.2 $ + * Updated : $Date: 2010/08/31 13:05:40 $ + * $Revision: 1.3 $ */ package se.sics.contiki.collect; @@ -47,6 +47,9 @@ public class SensorDataAggregator implements SensorInfo { private final Node node; private long[] values; + private int minSeqno = Integer.MAX_VALUE; + private int maxSeqno = Integer.MIN_VALUE; + private int seqnoDelta = 0; private int dataCount; public SensorDataAggregator(Node node) { @@ -79,9 +82,19 @@ public class SensorDataAggregator implements SensorInfo { } public void addSensorData(SensorData data) { + int s = data.getValue(SEQNO) + seqnoDelta; for (int i = 0, n = Math.min(VALUES_COUNT, data.getValueCount()); i < n; i++) { values[i] += data.getValue(i); } + + // Handle wrapping sequence numbers + if (dataCount > 0 && maxSeqno - s > 2) { + s += maxSeqno - seqnoDelta; + seqnoDelta = maxSeqno; + } + data.setSeqno(s); + if (s < minSeqno) minSeqno = s; + if (s > maxSeqno) maxSeqno = s; dataCount++; } @@ -159,4 +172,12 @@ public class SensorDataAggregator implements SensorInfo { return getAverageValue(BEST_NEIGHBOR_ETX) / 16.0; } + public int getMinSeqno() { + return minSeqno; + } + + public int getMaxSeqno() { + return maxSeqno; + } + } diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/SeqnoChartPanel.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/SeqnoChartPanel.java new file mode 100644 index 000000000..41a64d152 --- /dev/null +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/SeqnoChartPanel.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: SeqnoChartPanel.java,v 1.1 2010/08/31 13:05:40 nifi Exp $ + * + * ----------------------------------------------------------------- + * + * TimeChartPanel + * + * Authors : Joakim Eriksson, Niclas Finne + * Created : 3 jul 2008 + * Updated : $Date: 2010/08/31 13:05:40 $ + * $Revision: 1.1 $ + */ + +package se.sics.contiki.collect.gui; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; + +import javax.swing.JPanel; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import se.sics.contiki.collect.CollectServer; +import se.sics.contiki.collect.Node; +import se.sics.contiki.collect.SensorData; +import se.sics.contiki.collect.SensorDataAggregator; +import se.sics.contiki.collect.Visualizer; + +/** + * + */ +public class SeqnoChartPanel extends JPanel implements Visualizer { + + private static final long serialVersionUID = 4302047079820959307L; + + protected final CollectServer server; + protected final String title; + protected final XYSeriesCollection dataSet; + protected final XYSeries series; + protected final JFreeChart chart; + protected final ChartPanel chartPanel; + + private Node[] selectedNodes; + + public SeqnoChartPanel(CollectServer server, String title, + String chartTitle, String timeAxisLabel, String valueAxisLabel) { + super(new BorderLayout()); + this.server = server; + this.title = title; + this.series = new XYSeries(chartTitle); + this.dataSet = new XYSeriesCollection(this.series); + this.chart = ChartFactory.createXYLineChart( + chartTitle, timeAxisLabel, valueAxisLabel, this.dataSet, PlotOrientation.VERTICAL, + false, false, false + ); + this.chartPanel = new ChartPanel(chart); + this.chartPanel.setPreferredSize(new Dimension(500, 270)); + add(chartPanel, BorderLayout.CENTER); + } + + @Override + public String getTitle() { + return title; + } + + @Override + public Component getPanel() { + return this; + } + + @Override + public void nodeAdded(Node node) { + // Ignore + } + + @Override + public void nodesSelected(Node[] nodes) { + if (this.selectedNodes != nodes) { + this.selectedNodes = nodes; + if (isVisible()) { + updateCharts(); + } + } + } + + @Override + public void nodeDataReceived(SensorData data) { + if (isVisible() && selectedNodes != null) { + Node node = data.getNode(); + for (int i = 0, n = selectedNodes.length; i < n; i++) { + if (node == selectedNodes[i]) { + updateCharts(); + break; + } + } + } + } + + @Override + public void clearNodeData() { + if (isVisible()) { + updateCharts(); + } + } + + private void updateCharts() { + series.clear(); + if (this.selectedNodes != null) { + int minSeqno = Integer.MAX_VALUE; + int maxSeqno = Integer.MIN_VALUE; + for(Node node: this.selectedNodes) { + SensorDataAggregator sda = node.getSensorDataAggregator(); + if (sda.getMinSeqno() < minSeqno) { + minSeqno = sda.getMinSeqno(); + } + if (sda.getMaxSeqno() > maxSeqno) { + maxSeqno = sda.getMaxSeqno(); + } + } + if (minSeqno < maxSeqno) { + int[] seqnos = new int[maxSeqno - minSeqno + 1]; + for(Node node: this.selectedNodes) { + for(int i = 0, n = node.getSensorDataCount(); i < n; i++) { + seqnos[node.getSensorData(i).getSeqno() - minSeqno]++; + } + } + for(int i = 0; i < seqnos.length; i++) { + series.add(i + minSeqno, seqnos[i]); + } + } + } + } + + public double getRangeMinimumSize() { + return chart.getXYPlot().getRangeAxis().getAutoRangeMinimumSize(); + } + + public void setRangeMinimumSize(double size) { + chart.getXYPlot().getRangeAxis().setAutoRangeMinimumSize(size); + } + + public void setVisible(boolean visible) { + if (visible) { + updateCharts(); + } else { + series.clear(); + } + super.setVisible(visible); + } + +} diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/TimeChartPanel.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/TimeChartPanel.java index 63d10db66..9ccff7bf8 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/TimeChartPanel.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/TimeChartPanel.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: TimeChartPanel.java,v 1.3 2008/08/29 10:00:23 nifi Exp $ + * $Id: TimeChartPanel.java,v 1.4 2010/08/31 13:05:40 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2008/08/29 10:00:23 $ - * $Revision: 1.3 $ + * Updated : $Date: 2010/08/31 13:05:40 $ + * $Revision: 1.4 $ */ package se.sics.contiki.collect.gui; @@ -47,6 +47,7 @@ import javax.swing.JPanel; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.Second; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; @@ -88,6 +89,7 @@ public abstract class TimeChartPanel extends JPanel implements Visualizer { ); this.chartPanel = new ChartPanel(chart); this.chartPanel.setPreferredSize(new Dimension(500, 270)); + setBaseShapeVisible(true); add(chartPanel, BorderLayout.CENTER); } @@ -210,6 +212,14 @@ public abstract class TimeChartPanel extends JPanel implements Visualizer { } } + public boolean getBaseShapeVisible() { + return ((XYLineAndShapeRenderer)this.chart.getXYPlot().getRenderer()).getBaseShapesVisible(); + } + + public void setBaseShapeVisible(boolean visible) { + ((XYLineAndShapeRenderer)this.chart.getXYPlot().getRenderer()).setBaseShapesVisible(visible); + } + public int getRangeTick() { return rangeTick; }