From bba653f20c696a968c02852ee5d86e3a25c22b8a Mon Sep 17 00:00:00 2001 From: nifi Date: Wed, 15 Sep 2010 16:15:10 +0000 Subject: [PATCH] Added categories for cleaner tab layout * Added estimated packet loss and next hop change count to node info panel --- .../sics/contiki/collect/CollectServer.java | 361 +++++++++--------- .../contiki/collect/SensorDataAggregator.java | 35 +- .../se/sics/contiki/collect/Visualizer.java | 7 +- .../contiki/collect/gui/BarChartPanel.java | 19 +- .../se/sics/contiki/collect/gui/MapPanel.java | 16 +- .../contiki/collect/gui/NodeInfoPanel.java | 191 +++++---- .../contiki/collect/gui/PacketChartPanel.java | 15 +- .../contiki/collect/gui/SeqnoChartPanel.java | 15 +- .../contiki/collect/gui/SerialConsole.java | 15 +- .../contiki/collect/gui/TimeChartPanel.java | 17 +- 10 files changed, 416 insertions(+), 275 deletions(-) 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 7efb2919e..049ce7284 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.17 2010/09/14 23:04:50 nifi Exp $ + * $Id: CollectServer.java,v 1.18 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2010/09/14 23:04:50 $ - * $Revision: 1.17 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.18 $ */ package se.sics.contiki.collect; @@ -59,6 +59,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.Hashtable; import java.util.Properties; import javax.swing.BorderFactory; @@ -100,6 +101,12 @@ public class CollectServer { public static final String INIT_SCRIPT = "collect-init.script"; public static final String FIRMWARE_FILE = "sky-shell.ihex"; + /* Categories for the tab pane */ + private static final String MAIN = "main"; + private static final String NETWORK = "Network"; + private static final String SENSORS = "Sensors"; + private static final String POWER = "Power"; + private Properties config = new Properties(); private String configFile; @@ -113,6 +120,7 @@ public class CollectServer { private JFrame window; private JTabbedPane mainPanel; + private HashMap categoryTable = new HashMap(); private JMenuItem serialItem; private JMenuItem runInitScriptItem; @@ -165,6 +173,7 @@ public class CollectServer { }); nodeModel = new DefaultListModel(); + nodeModel.addElement(""); nodeList = new JList(nodeModel); nodeList.setPrototypeCellValue("888.888"); nodeList.addListSelectionListener(new ListSelectionListener() { @@ -177,9 +186,17 @@ public class CollectServer { int iMax = nodeList.getMaxSelectionIndex(); if ((iMin < 0) || (iMax < 0)) { selected = null; + } else if (nodeList.getSelectedIndex() == 0) { + selected = getNodes(); + if (nodeModel.size() > 1) { + nodeList.setSelectionInterval(1, nodeModel.size() - 1); + } } else { Node[] tmp = new Node[1 + (iMax - iMin)]; int n = 0; + if (iMin < 1) { + iMin = 1; + } for(int i = iMin; i <= iMax; i++) { if (nodeList.isSelectedIndex(i)) { tmp[n++] = (Node) nodeModel.getElementAt(i); @@ -199,16 +216,17 @@ public class CollectServer { nodeList.setBorder(BorderFactory.createTitledBorder("Nodes")); ListCellRenderer renderer = nodeList.getCellRenderer(); if (renderer instanceof JLabel) { - ((JLabel)renderer).setHorizontalAlignment(JLabel.RIGHT); + ((JLabel)renderer).setHorizontalAlignment(JLabel.CENTER); } window.getContentPane().add(new JScrollPane(nodeList), BorderLayout.WEST); mainPanel = new JTabbedPane(); mainPanel.setBackground(nodeList.getBackground()); mainPanel.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); + categoryTable.put(MAIN, mainPanel); - serialConsole = new SerialConsole(this); - mapPanel = new MapPanel(this); + serialConsole = new SerialConsole(this, MAIN); + mapPanel = new MapPanel(this, MAIN); String image = getConfig("collect.mapimage"); if (image != null) { mapPanel.setMapBackground(image); @@ -216,7 +234,148 @@ public class CollectServer { final int defaultMaxItemCount = 250; visualizers = new Visualizer[] { mapPanel, - new BarChartPanel(this, "Average Power", "Average Power Consumption", + new BarChartPanel(this, SENSORS, "Average Temperature", "Temperature", "Nodes", "Celsius", + new String[] { "Celsius" }) { + { + chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + } + protected void addSensorData(SensorData data) { + Node node = data.getNode(); + String nodeName = node.getName(); + SensorDataAggregator aggregator = node.getSensorDataAggregator(); + dataset.addValue(aggregator.getAverageTemperature(), categories[0], nodeName); + } + }, + new TimeChartPanel(this, SENSORS, "Temperature", "Temperature", "Time", "Celsius") { + { + chart.getXYPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + setRangeTick(5); + setRangeMinimumSize(10.0); + setGlobalRange(true); + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getTemperature(); + } + }, + new TimeChartPanel(this, SENSORS, "Battery Voltage", "Battery Voltage", + "Time", "Volt") { + { + setRangeTick(1); + setRangeMinimumSize(4.0); + setGlobalRange(true); + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getBatteryVoltage(); + } + }, + new TimeChartPanel(this, SENSORS, "Battery Indicator", "Battery Indicator", + "Time", "Indicator") { + { + chart.getXYPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + setRangeTick(5); + setRangeMinimumSize(10.0); + setGlobalRange(true); + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getBatteryIndicator(); + } + }, + new TimeChartPanel(this, SENSORS, "Relative Humidity", "Humidity", "Time", "%") { + { + setMaxItemCount(defaultMaxItemCount); + chart.getXYPlot().getRangeAxis().setRange(0.0, 100.0); + } + protected double getSensorDataValue(SensorData data) { + return data.getHumidity(); + } + }, + new TimeChartPanel(this, SENSORS, "Light 1", "Light 1", "Time", "-") { + { + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getLight1(); + } + }, + new TimeChartPanel(this, SENSORS, "Light 2", "Light 2", "Time", "-") { + { + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getLight2(); + } + }, + new TimeChartPanel(this, NETWORK, "Network Hops (Over Time)", "Network Hops", "Time", "Hops") { + { + ValueAxis axis = chart.getXYPlot().getRangeAxis(); + ((NumberAxis)axis).setAutoRangeIncludesZero(true); + axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getValue(SensorData.HOPS); + } + }, + new BarChartPanel(this, NETWORK, "Network Hops (Per Node)", "Network Hops", "Nodes", "Hops", + new String[] { "Last Hop", "Average Hops" }, false) { + { + chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + } + protected void addSensorData(SensorData data) { + dataset.addValue(data.getValue(SensorData.HOPS), categories[0], data.getNode().getName()); + dataset.addValue(data.getNode().getSensorDataAggregator().getAverageValue(SensorData.HOPS), categories[1], data.getNode().getName()); + } + }, + new TimeChartPanel(this, NETWORK, "Latency", "Latency", "Time", "Seconds") { + { + setMaxItemCount(defaultMaxItemCount); + } + protected double getSensorDataValue(SensorData data) { + return data.getLatency(); + } + }, + new PacketChartPanel(this, NETWORK, "Received (Over Time)", "Time", "Received Packets"), + new BarChartPanel(this, NETWORK, "Received (Per Node)", "Received Packets Per Node", "Nodes", "Packets", + new String[] { "Packets", "Duplicates" }) { + { + chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + } + protected void addSensorData(SensorData data) { + Node node = data.getNode(); + SensorDataAggregator sda = node.getSensorDataAggregator(); + dataset.addValue(sda.getDataCount(), categories[0], node.getName()); + dataset.addValue(sda.getDuplicateCount(), categories[1], node.getName()); + } + }, + new BarChartPanel(this, NETWORK, "Received (5 min)", "Received Packets (last 5 min)", "Nodes", "Packets", + new String[] { "Packets", "Duplicates" }) { + { + chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); + } + protected void addSensorData(SensorData data) { + Node node = data.getNode(); + int packetCount = 0; + int duplicateCount = 0; + long earliestData = System.currentTimeMillis() - (5 * 60 * 1000); + for(int index = node.getSensorDataCount() - 1; index >= 0; index--) { + SensorData sd = node.getSensorData(index); + if (sd.getNodeTime() < earliestData) { + break; + } + if (sd.isDuplicate()) { + duplicateCount++; + } else { + packetCount++; + } + } + dataset.addValue(packetCount, categories[0], node.getName()); + dataset.addValue(duplicateCount, categories[1], node.getName()); + } + }, + new BarChartPanel(this, POWER, "Average Power", "Average Power Consumption", "Nodes", "Power (mW)", new String[] { "LPM", "CPU", "Radio listen", "Radio transmit" }) { { @@ -233,7 +392,7 @@ public class CollectServer { dataset.addValue(aggregator.getTransmitPower(), categories[3], nodeName); } }, - new BarChartPanel(this, "Radio Duty Cycle", "Average Radio Duty Cycle", + new BarChartPanel(this, POWER, "Radio Duty Cycle", "Average Radio Duty Cycle", "Nodes", "Duty Cycle (%)", new String[] { "Radio listen", "Radio transmit" }) { { @@ -250,7 +409,7 @@ public class CollectServer { categories[1], nodeName); } }, - new BarChartPanel(this, "Instantaneous Power", + new BarChartPanel(this, POWER, "Instantaneous Power", "Instantaneous Power Consumption", "Nodes", "Power (mW)", new String[] { "LPM", "CPU", "Radio listen", "Radio transmit" }) { { @@ -266,164 +425,30 @@ public class CollectServer { dataset.addValue(data.getTransmitPower(), categories[3], nodeName); } }, - new TimeChartPanel(this, "Power History", "Historical Power Consumption", "Time", "mW") { + new TimeChartPanel(this, POWER, "Power History", "Historical Power Consumption", "Time", "mW") { { - /* ValueAxis axis = chart.getCategoryPlot().getRangeAxis();*/ +// ValueAxis axis = chart.getCategoryPlot().getRangeAxis(); +// ((NumberAxis)axis).setAutoRangeIncludesZero(true); setMaxItemCount(defaultMaxItemCount); - /* ((NumberAxis)axis).setAutoRangeIncludesZero(true);*/ } protected double getSensorDataValue(SensorData data) { return data.getAveragePower(); } }, - new BarChartPanel(this, "Average Temperature", "Temperature", "Nodes", "Celsius", - new String[] { "Celsius" }) { - { - chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - } - protected void addSensorData(SensorData data) { - Node node = data.getNode(); - String nodeName = node.getName(); - SensorDataAggregator aggregator = node.getSensorDataAggregator(); - dataset.addValue(aggregator.getAverageTemperature(), categories[0], nodeName); - } - }, - new TimeChartPanel(this, "Temperature", "Temperature", "Time", "Celsius") { - { - chart.getXYPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - setRangeTick(5); - setRangeMinimumSize(10.0); - setGlobalRange(true); - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getTemperature(); - } - }, - new TimeChartPanel(this, "Battery Voltage", "Battery Voltage", - "Time", "Volt") { - { - setRangeTick(1); - setRangeMinimumSize(4.0); - setGlobalRange(true); - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getBatteryVoltage(); - } - }, - new TimeChartPanel(this, "Battery Indicator", "Battery Indicator", - "Time", "Indicator") { - { - chart.getXYPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - setRangeTick(5); - setRangeMinimumSize(10.0); - setGlobalRange(true); - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getBatteryIndicator(); - } - }, - new TimeChartPanel(this, "Relative Humidity", "Humidity", "Time", "%") { - { - setMaxItemCount(defaultMaxItemCount); - chart.getXYPlot().getRangeAxis().setRange(0.0, 100.0); - } - protected double getSensorDataValue(SensorData data) { - return data.getHumidity(); - } - }, - new TimeChartPanel(this, "Light 1", "Light 1", "Time", "-") { - { - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getLight1(); - } - }, - new TimeChartPanel(this, "Light 2", "Light 2", "Time", "-") { - { - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getLight2(); - } - }, - new TimeChartPanel(this, "Network Hops (Over Time)", "Network Hops", "Time", "Hops") { - { - ValueAxis axis = chart.getXYPlot().getRangeAxis(); - ((NumberAxis)axis).setAutoRangeIncludesZero(true); - axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getValue(SensorData.HOPS); - } - }, - new BarChartPanel(this, "Network Hops (Per Node)", "Network Hops", "Nodes", "Hops", - new String[] { "Last Hop", "Average Hops" }, false) { - { - chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - } - protected void addSensorData(SensorData data) { - dataset.addValue(data.getValue(SensorData.HOPS), categories[0], data.getNode().getName()); - dataset.addValue(data.getNode().getSensorDataAggregator().getAverageValue(SensorData.HOPS), categories[1], data.getNode().getName()); - } - }, - new TimeChartPanel(this, "Latency", "Latency", "Time", "Seconds") { - { - setMaxItemCount(defaultMaxItemCount); - } - protected double getSensorDataValue(SensorData data) { - return data.getLatency(); - } - }, - new PacketChartPanel(this, "Received (Over Time)", "Time", "Received Packets"), - new BarChartPanel(this, "Received (Per Node)", "Received Packets Per Node", "Nodes", "Packets", - new String[] { "Packets", "Duplicates" }) { - { - chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - } - protected void addSensorData(SensorData data) { - Node node = data.getNode(); - SensorDataAggregator sda = node.getSensorDataAggregator(); - dataset.addValue(sda.getDataCount(), categories[0], node.getName()); - dataset.addValue(sda.getDuplicateCount(), categories[1], node.getName()); - } - }, - new BarChartPanel(this, "Received (5 min)", "Received Packets (last 5 min)", "Nodes", "Packets", - new String[] { "Packets", "Duplicates" }) { - { - chart.getCategoryPlot().getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); - } - protected void addSensorData(SensorData data) { - Node node = data.getNode(); - int dataCount = node.getSensorDataCount(); - int packetCount = 0; - int duplicateCount = 0; - long earliestData = getNodeTime() - (5 * 60 * 1000); - for(int index = dataCount - 1; index >= 0; index--) { - SensorData sd = node.getSensorData(index); - if (sd.getNodeTime() < earliestData) { - break; - } - if (sd.isDuplicate()) { - duplicateCount++; - } else { - packetCount++; - } - } - dataset.addValue(packetCount, categories[0], node.getName()); - dataset.addValue(duplicateCount, categories[1], node.getName()); - } - }, -// new SeqnoChartPanel(this, "Received Packets", "Received Packets", "Seqno", "Received Packets"), - new NodeInfoPanel(this), + new NodeInfoPanel(this, MAIN), serialConsole }; for (int i = 0, n = visualizers.length; i < n; i++) { - mainPanel.add(visualizers[i].getTitle(), visualizers[i].getPanel()); + String category = visualizers[i].getCategory(); + JTabbedPane pane = categoryTable.get(category); + if (pane == null) { + pane = new JTabbedPane(); + pane.setBackground(nodeList.getBackground()); + pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); + categoryTable.put(category, pane); + mainPanel.add(category, pane); + } + pane.add(visualizers[i].getTitle(), visualizers[i].getPanel()); } window.getContentPane().add(mainPanel, BorderLayout.CENTER); @@ -546,20 +571,6 @@ public class CollectServer { }); toolsMenu.add(baseShapeItem); - final JCheckBoxMenuItem scrollItem = new JCheckBoxMenuItem("Scroll Layout"); - scrollItem.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent e) { - if (scrollItem.getState()) { - mainPanel.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); - } else { - mainPanel.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); - } - } - - }); - toolsMenu.add(scrollItem); - window.setJMenuBar(menuBar); window.pack(); @@ -797,7 +808,7 @@ public class CollectServer { SwingUtilities.invokeLater(new Runnable() { public void run() { boolean added = false; - for (int i = 0, n = nodeModel.size(); i < n; i++) { + for (int i = 1, n = nodeModel.size(); i < n; i++) { int cmp = newNode.compareTo((Node) nodeModel.get(i)); if (cmp < 0) { nodeModel.insertElementAt(newNode, i); @@ -973,10 +984,10 @@ public class CollectServer { private void handleSensorData(final SensorData sensorData) { System.out.println("SENSOR DATA: " + sensorData); + saveSensorData(sensorData); if (sensorData.getNode().addSensorData(sensorData)) { updateNodeTime(sensorData); sensorDataList.add(sensorData); - saveSensorData(sensorData); handleLinks(sensorData); if (visualizers != null) { SwingUtilities.invokeLater(new Runnable() { @@ -1062,7 +1073,9 @@ public class CollectServer { Node[] nodes = getNodes(); this.selectedNodes = null; nodeList.clearSelection(); - nodeModel.removeAllElements(); + if (nodeModel.size() > 1) { + nodeModel.removeRange(1, nodeModel.size() - 1); + } this.nodeTable.clear(); synchronized (this) { this.nodeCache = null; 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 3d73cf82b..f228ce09b 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.6 2010/09/14 14:23:58 adamdunkels Exp $ + * $Id: SensorDataAggregator.java,v 1.7 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 20 aug 2008 - * Updated : $Date: 2010/09/14 14:23:58 $ - * $Revision: 1.6 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.7 $ */ package se.sics.contiki.collect; @@ -52,6 +52,9 @@ public class SensorDataAggregator implements SensorInfo { private int seqnoDelta = 0; private int dataCount; private int duplicates = 0; + private int lost = 0; + private int nextHopChangeCount = 0; + private String lastNextHop = null; private long shortestPeriod = Long.MAX_VALUE; private long longestPeriod = 0; @@ -88,6 +91,12 @@ public class SensorDataAggregator implements SensorInfo { int seqn = data.getValue(SEQNO); int s = seqn + seqnoDelta; + String bestNeighbor = data.getBestNeighborID(); + if (lastNextHop != null && !lastNextHop.equals(bestNeighbor)) { + nextHopChangeCount++; + } + lastNextHop = bestNeighbor; + if (s <= maxSeqno) { // Check for duplicates among the last 5 packets for(int n = node.getSensorDataCount() - 1, i = n > 5 ? n - 5 : 0; i < n; i++) { @@ -142,9 +151,16 @@ public class SensorDataAggregator implements SensorInfo { } } // Handle wrapping sequence numbers - if (dataCount > 0 && maxSeqno - s > 2) { + if (dataCount == 0) { + // First packet from node. + } else if (maxSeqno - s > 2) { s += maxSeqno - seqnoDelta; seqnoDelta = maxSeqno; + if (seqn > 0) { + lost += seqn - 1; + } + } else if (s > maxSeqno + 1){ + lost += s - (maxSeqno + 1); } if (s < minSeqno) minSeqno = s; if (s > maxSeqno) maxSeqno = s; @@ -159,6 +175,9 @@ public class SensorDataAggregator implements SensorInfo { } dataCount = 0; duplicates = 0; + lost = 0; + nextHopChangeCount = 0; + lastNextHop = null; minSeqno = Integer.MAX_VALUE; maxSeqno = Integer.MIN_VALUE; seqnoDelta = 0; @@ -241,6 +260,14 @@ public class SensorDataAggregator implements SensorInfo { return node.getSensorDataCount(); } + public int getNextHopChangeCount() { + return nextHopChangeCount; + } + + public int getEstimatedLostCount() { + return lost; + } + public int getDuplicateCount() { return duplicates; } diff --git a/examples/sky-shell/src/se/sics/contiki/collect/Visualizer.java b/examples/sky-shell/src/se/sics/contiki/collect/Visualizer.java index 69cdd68ab..192cfedf6 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/Visualizer.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/Visualizer.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: Visualizer.java,v 1.1 2008/07/09 23:18:06 nifi Exp $ + * $Id: Visualizer.java,v 1.2 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2008/07/09 23:18:06 $ - * $Revision: 1.1 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.2 $ */ package se.sics.contiki.collect; @@ -47,6 +47,7 @@ import java.awt.Component; */ public interface Visualizer { + public String getCategory(); public String getTitle(); public Component getPanel(); public void nodesSelected(Node[] node); diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/BarChartPanel.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/BarChartPanel.java index a028675fd..7f5739f70 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/BarChartPanel.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/BarChartPanel.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: BarChartPanel.java,v 1.4 2010/09/15 15:52:28 nifi Exp $ + * $Id: BarChartPanel.java,v 1.5 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 5 jul 2008 - * Updated : $Date: 2010/09/15 15:52:28 $ - * $Revision: 1.4 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.5 $ */ package se.sics.contiki.collect.gui; @@ -67,6 +67,7 @@ public abstract class BarChartPanel extends JPanel implements Visualizer { private static final long serialVersionUID = 7664283678708048061L; protected final CollectServer server; + protected final String category; protected final String title; protected final String[] categories; protected final JFreeChart chart; @@ -76,17 +77,18 @@ public abstract class BarChartPanel extends JPanel implements Visualizer { private boolean isShowingAllNodes = false; private int categoryOrder = 0; - protected BarChartPanel(CollectServer server, String title, + protected BarChartPanel(CollectServer server, String category, String title, String chartTitle, String domainAxisLabel, String valueAxisLabel, String[] categories) { - this(server, title, chartTitle, domainAxisLabel, valueAxisLabel, categories, true); + this(server, category, title, chartTitle, domainAxisLabel, valueAxisLabel, categories, true); } - protected BarChartPanel(CollectServer server, String title, + protected BarChartPanel(CollectServer server, String category, String title, String chartTitle, String domainAxisLabel, String valueAxisLabel, String[] categories, boolean stackedChart) { super(new BorderLayout()); this.server = server; + this.category = category; this.title = title; this.categories = categories; @@ -137,6 +139,11 @@ public abstract class BarChartPanel extends JPanel implements Visualizer { add(chartPanel, BorderLayout.CENTER); } + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return title; diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/MapPanel.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/MapPanel.java index 5cbab6e14..3768b8a4c 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/MapPanel.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/MapPanel.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: MapPanel.java,v 1.2 2010/09/06 22:32:56 nifi Exp $ + * $Id: MapPanel.java,v 1.3 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2010/09/06 22:32:56 $ - * $Revision: 1.2 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.3 $ */ package se.sics.contiki.collect.gui; @@ -124,13 +124,14 @@ public class MapPanel extends JPanel implements Visualizer, ActionListener, Mous private String mapName; private final CollectServer server; + private final String category; private boolean hideNetwork = false; - - public MapPanel(CollectServer server) { + public MapPanel(CollectServer server, String category) { super(new BorderLayout()); this.server = server; + this.category = category; setPreferredSize(new Dimension(300, 200)); popupMenu = new JPopupMenu(getTitle()); @@ -221,6 +222,11 @@ public class MapPanel extends JPanel implements Visualizer, ActionListener, Mous // Visualizer // ------------------------------------------------------------------- + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return "Sensor Map"; diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/NodeInfoPanel.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/NodeInfoPanel.java index 51af419af..5c95afa5d 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/NodeInfoPanel.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/NodeInfoPanel.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: NodeInfoPanel.java,v 1.4 2010/09/14 23:04:51 nifi Exp $ + * $Id: NodeInfoPanel.java,v 1.5 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,13 +34,15 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 6 sep 2010 - * Updated : $Date: 2010/09/14 23:04:51 $ - * $Revision: 1.4 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.5 $ */ package se.sics.contiki.collect.gui; import java.awt.BorderLayout; import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.MouseEvent; import javax.swing.JLabel; import javax.swing.JPanel; @@ -48,6 +50,7 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.JTableHeader; import se.sics.contiki.collect.CollectServer; import se.sics.contiki.collect.Node; @@ -62,77 +65,36 @@ public class NodeInfoPanel extends JPanel implements Visualizer { private static final long serialVersionUID = -1060893468047793431L; private final CollectServer server; + private final String category; private final JTable nodeTable; - private final AbstractTableModel nodeModel; + private final NodeModel nodeModel; private Node[] nodes; - public NodeInfoPanel(CollectServer server) { + public NodeInfoPanel(CollectServer server, String category) { super(new BorderLayout()); this.server = server; + this.category = category; - nodeModel = new AbstractTableModel() { + nodeModel = new NodeModel(); + nodeTable = new JTable(nodeModel) { + private static final long serialVersionUID = 1L; - private static final long serialVersionUID = 1692207305977527004L; + public Dimension getPreferredScrollableViewportSize() { + return getPreferredSize(); + } - private final String[] COLUMN_NAMES = { - "Node", - "Packets Received", - "Duplicates Received", - "Average Inter-packet time", - "Shortest Inter-packet time", - "Longest Inter-packet time", - }; + protected JTableHeader createDefaultTableHeader() { + return new JTableHeader(columnModel) { + private static final long serialVersionUID = 1L; - public Object getValueAt(int row, int col) { - Node node = nodes[row]; - switch (col) { - case 0: - return node; - case 1: - return node.getSensorDataAggregator().getPacketCount(); - case 2: - return node.getSensorDataAggregator().getDuplicateCount(); - case 3: - return node.getSensorDataAggregator().getAveragePeriod(); - case 4: { - long time = node.getSensorDataAggregator().getShortestPeriod(); - return time < Long.MAX_VALUE ? time : 0; - } - case 5: - return node.getSensorDataAggregator().getLongestPeriod(); - default: - return null; - } + public String getToolTipText(MouseEvent e) { + int index = columnModel.getColumnIndexAtX(e.getPoint().x); + int realIndex = index < 0 ? index : columnModel.getColumn(index).getModelIndex(); + return realIndex < 0 ? null : nodeModel.getColumnToolTip(realIndex); + } + }; } - - public Class getColumnClass(int c) { - if (c == 0) { - return Node.class; - } - if (c < 3) { - return Integer.class; - } - if (c < 6) { - return Long.class; - } - return super.getColumnClass(c); - } - - public String getColumnName(int col) { - return COLUMN_NAMES[col]; - } - - public int getColumnCount() { - return COLUMN_NAMES.length; - } - - public int getRowCount() { - return nodes == null ? 0 : nodes.length; - } - }; - - nodeTable = new JTable(nodeModel); nodeTable.setFillsViewportHeight(true); nodeTable.setAutoCreateRowSorter(true); @@ -141,7 +103,7 @@ public class NodeInfoPanel extends JPanel implements Visualizer { renderer.setHorizontalAlignment(JLabel.RIGHT); nodeTable.setDefaultRenderer(Node.class, renderer); - // Add time renderer + // Add renderer for time renderer = new DefaultTableCellRenderer() { private static final long serialVersionUID = 1L; @@ -152,6 +114,22 @@ public class NodeInfoPanel extends JPanel implements Visualizer { }; nodeTable.setDefaultRenderer(Long.class, renderer); + // Add renderer for double + renderer = new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + + public void setValue(Object value) { + if (value == null) { + setText(null); + } + double v = (Double) value + 0.0005; + int dec = ((int)(v * 1000)) % 1000; + setText((long)v + "." + (dec > 99 ? "" : "0") + (dec > 9 ? "" : "0") + dec); + } + }; + renderer.setHorizontalAlignment(JLabel.RIGHT); + nodeTable.setDefaultRenderer(Double.class, renderer); + add(new JScrollPane(nodeTable), BorderLayout.CENTER); } @@ -160,6 +138,11 @@ public class NodeInfoPanel extends JPanel implements Visualizer { return this; } + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return "Node Info"; @@ -226,16 +209,92 @@ public class NodeInfoPanel extends JPanel implements Visualizer { time /= 1000; if (time > 24 * 60 * 60) { long days = time / (24 * 60 * 60); - sb.append(days).append(" days, "); + sb.append(days).append(days > 1 ? " days, " : " day, "); time -= days * 24 * 60 * 60; } if (time > 60 * 60) { long hours = time / (60 * 60); - sb.append(hours).append(" hours, "); + sb.append(hours).append(hours > 1 ? " hours, " : " hour, "); time -= hours * 60 * 60; } sb.append(time / 60).append(" min, ").append(time % 60).append(" sec"); return sb.toString(); } + private class NodeModel extends AbstractTableModel { + + private static final long serialVersionUID = 1692207305977527004L; + + private final String[] COLUMN_NAMES = { + "Node", "Node", + "Packets", "Packets Received", + "Duplicates", "Duplicate Packets Received", + "Estimated Lost", "Estimated Lost Packets", + "Average Hops", "Average Hops to Sink", + "Next Hop Changes", "Next Hop Change Count", + "Average Inter-packet time", "Average Inter-packet Time", + "Shortest Inter-packet Time", "Shortest Inter-packet Time", + "Longest Inter-packet Time", "Longest Inter-packet Time" + }; + private final Class[] COLUMN_TYPES = { + Node.class, + Integer.class, + Integer.class, + Integer.class, + Double.class, + Integer.class, + Long.class, + Long.class, + Long.class + }; + + public Object getValueAt(int row, int col) { + Node node = nodes[row]; + switch (col) { + case 0: + return node; + case 1: + return node.getSensorDataAggregator().getPacketCount(); + case 2: + return node.getSensorDataAggregator().getDuplicateCount(); + case 3: + return node.getSensorDataAggregator().getEstimatedLostCount(); + case 4: + return node.getSensorDataAggregator().getAverageValue(SensorData.HOPS); + case 5: + return node.getSensorDataAggregator().getNextHopChangeCount(); + case 6: + return node.getSensorDataAggregator().getAveragePeriod(); + case 7: { + long time = node.getSensorDataAggregator().getShortestPeriod(); + return time < Long.MAX_VALUE ? time : 0; + } + case 8: + return node.getSensorDataAggregator().getLongestPeriod(); + default: + return null; + } + } + + public Class getColumnClass(int c) { + return COLUMN_TYPES[c]; + } + + public String getColumnName(int col) { + return COLUMN_NAMES[col * 2]; + } + + public String getColumnToolTip(int col) { + return COLUMN_NAMES[col * 2 + 1]; + } + + public int getColumnCount() { + return COLUMN_NAMES.length / 2; + } + + public int getRowCount() { + return nodes == null ? 0 : nodes.length; + } + + } } diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/PacketChartPanel.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/PacketChartPanel.java index 55d8ae6c0..4f72776e7 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/PacketChartPanel.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/PacketChartPanel.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: PacketChartPanel.java,v 1.7 2010/09/15 15:20:47 nifi Exp $ + * $Id: PacketChartPanel.java,v 1.8 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 6 sep 2010 - * Updated : $Date: 2010/09/15 15:20:47 $ - * $Revision: 1.7 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.8 $ */ package se.sics.contiki.collect.gui; @@ -69,6 +69,7 @@ public class PacketChartPanel extends JPanel implements Visualizer { private static final long serialVersionUID = -607864439709540641L; protected final CollectServer server; + protected final String category; protected final String title; protected final TimeSeries series; @@ -78,10 +79,11 @@ public class PacketChartPanel extends JPanel implements Visualizer { private Node[] selectedNodes; private HashMap selectedMap = new HashMap(); - public PacketChartPanel(CollectServer server, String title, + public PacketChartPanel(CollectServer server, String category, String title, String timeAxisLabel, String valueAxisLabel) { super(new BorderLayout()); this.server = server; + this.category = category; this.title = title; this.series = new TimeSeries("Received Packets", Minute.class); TimeSeriesCollection timeSeries = new TimeSeriesCollection(series); @@ -97,6 +99,11 @@ public class PacketChartPanel extends JPanel implements Visualizer { add(chartPanel, BorderLayout.CENTER); } + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return title; 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 index 41a64d152..880be4779 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/SeqnoChartPanel.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/SeqnoChartPanel.java @@ -26,7 +26,7 @@ * 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 $ + * $Id: SeqnoChartPanel.java,v 1.2 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2010/08/31 13:05:40 $ - * $Revision: 1.1 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.2 $ */ package se.sics.contiki.collect.gui; @@ -66,6 +66,7 @@ public class SeqnoChartPanel extends JPanel implements Visualizer { private static final long serialVersionUID = 4302047079820959307L; protected final CollectServer server; + protected final String category; protected final String title; protected final XYSeriesCollection dataSet; protected final XYSeries series; @@ -74,10 +75,11 @@ public class SeqnoChartPanel extends JPanel implements Visualizer { private Node[] selectedNodes; - public SeqnoChartPanel(CollectServer server, String title, + public SeqnoChartPanel(CollectServer server, String category, String title, String chartTitle, String timeAxisLabel, String valueAxisLabel) { super(new BorderLayout()); this.server = server; + this.category = category; this.title = title; this.series = new XYSeries(chartTitle); this.dataSet = new XYSeriesCollection(this.series); @@ -90,6 +92,11 @@ public class SeqnoChartPanel extends JPanel implements Visualizer { add(chartPanel, BorderLayout.CENTER); } + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return title; diff --git a/examples/sky-shell/src/se/sics/contiki/collect/gui/SerialConsole.java b/examples/sky-shell/src/se/sics/contiki/collect/gui/SerialConsole.java index 57697d111..048e6aa79 100644 --- a/examples/sky-shell/src/se/sics/contiki/collect/gui/SerialConsole.java +++ b/examples/sky-shell/src/se/sics/contiki/collect/gui/SerialConsole.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: SerialConsole.java,v 1.1 2008/07/09 23:18:07 nifi Exp $ + * $Id: SerialConsole.java,v 1.2 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 4 jul 2008 - * Updated : $Date: 2008/07/09 23:18:07 $ - * $Revision: 1.1 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.2 $ */ package se.sics.contiki.collect.gui; @@ -64,6 +64,7 @@ import se.sics.contiki.collect.Visualizer; public class SerialConsole implements Visualizer { private final CollectServer server; + private final String category; private JPanel panel; private JTextArea logArea; private JTextField commandField; @@ -71,8 +72,9 @@ public class SerialConsole implements Visualizer { private int historyPos = 0; private int historyCount = 0; - public SerialConsole(CollectServer server) { + public SerialConsole(CollectServer server, String category) { this.server = server; + this.category = category; panel = new JPanel(new BorderLayout()); logArea = new JTextArea(4, 30); logArea.setEditable(false); @@ -168,6 +170,11 @@ public class SerialConsole implements Visualizer { return panel; } + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return "Serial Console"; 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 dbb9583fa..b9920de04 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.6 2010/09/15 15:16:49 nifi Exp $ + * $Id: TimeChartPanel.java,v 1.7 2010/09/15 16:15:10 nifi Exp $ * * ----------------------------------------------------------------- * @@ -34,8 +34,8 @@ * * Authors : Joakim Eriksson, Niclas Finne * Created : 3 jul 2008 - * Updated : $Date: 2010/09/15 15:16:49 $ - * $Revision: 1.6 $ + * Updated : $Date: 2010/09/15 16:15:10 $ + * $Revision: 1.7 $ */ package se.sics.contiki.collect.gui; @@ -64,6 +64,7 @@ public abstract class TimeChartPanel extends JPanel implements Visualizer { private static final long serialVersionUID = -607864439709540641L; protected final CollectServer server; + protected final String category; protected final String title; protected final TimeSeriesCollection timeSeries; protected final JFreeChart chart; @@ -76,11 +77,12 @@ public abstract class TimeChartPanel extends JPanel implements Visualizer { private int rangeTick = 0; private boolean hasGlobalRange; private int maxItemCount; - - public TimeChartPanel(CollectServer server, String title, + + public TimeChartPanel(CollectServer server, String category, String title, String chartTitle, String timeAxisLabel, String valueAxisLabel) { super(new BorderLayout()); this.server = server; + this.category = category; this.title = title; this.timeSeries = new TimeSeriesCollection(); this.chart = ChartFactory.createTimeSeriesChart( @@ -93,6 +95,11 @@ public abstract class TimeChartPanel extends JPanel implements Visualizer { add(chartPanel, BorderLayout.CENTER); } + @Override + public String getCategory() { + return category; + } + @Override public String getTitle() { return title;