added initial 802.15.4 packet analyzer to COOJA radio logger

This commit is contained in:
joxe 2010-02-23 22:32:57 +00:00
parent cd8047bc77
commit 588d0374fa
2 changed files with 105 additions and 11 deletions

View file

@ -26,12 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: RadioLogger.java,v 1.26 2009/12/14 13:25:04 fros4943 Exp $ * $Id: RadioLogger.java,v 1.27 2010/02/23 22:32:57 joxe Exp $
*/ */
package se.sics.cooja.plugins; package se.sics.cooja.plugins;
import java.awt.Color;
import java.awt.Font; import java.awt.Font;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Toolkit; import java.awt.Toolkit;
@ -41,24 +40,26 @@ import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Properties; import java.util.Properties;
import java.util.Vector;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.Icon; import javax.swing.ButtonGroup;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.JTextPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -75,6 +76,9 @@ import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin; import se.sics.cooja.VisPlugin;
import se.sics.cooja.dialogs.TableColumnAdjuster; import se.sics.cooja.dialogs.TableColumnAdjuster;
import se.sics.cooja.interfaces.Radio; import se.sics.cooja.interfaces.Radio;
import se.sics.cooja.plugins.analyzers.IEEE802154Analyzer;
import se.sics.cooja.plugins.analyzers.IPHCPacketAnalyzer;
import se.sics.cooja.plugins.analyzers.PacketAnalyzer;
import se.sics.cooja.util.StringUtils; import se.sics.cooja.util.StringUtils;
/** /**
@ -94,6 +98,8 @@ public class RadioLogger extends VisPlugin {
private final static int COLUMN_TO = 2; private final static int COLUMN_TO = 2;
private final static int COLUMN_DATA = 3; private final static int COLUMN_DATA = 3;
private JTextPane verboseBox = null;
private final static String[] COLUMN_NAMES = { private final static String[] COLUMN_NAMES = {
"Time", "Time",
"From", "From",
@ -108,11 +114,16 @@ public class RadioLogger extends VisPlugin {
private Observer radioMediumObserver; private Observer radioMediumObserver;
private AbstractTableModel model; private AbstractTableModel model;
private ArrayList<PacketAnalyzer> analyzers = null;
private ArrayList<PacketAnalyzer> lowpanAnalyzers = new ArrayList<PacketAnalyzer>();
public RadioLogger(final Simulation simulationToControl, final GUI gui) { public RadioLogger(final Simulation simulationToControl, final GUI gui) {
super("Radio Logger", gui); super("Radio Logger", gui);
simulation = simulationToControl; simulation = simulationToControl;
radioMedium = simulation.getRadioMedium(); radioMedium = simulation.getRadioMedium();
lowpanAnalyzers.add(new IEEE802154Analyzer());
lowpanAnalyzers.add(new IPHCPacketAnalyzer());
model = new AbstractTableModel() { model = new AbstractTableModel() {
private static final long serialVersionUID = 1692207305977527004L; private static final long serialVersionUID = 1692207305977527004L;
@ -238,6 +249,18 @@ public class RadioLogger extends VisPlugin {
} }
}; };
dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
int row = dataTable.getSelectedRow();
if (row >= 0) {
RadioConnectionLog conn = connections.get(row);
if (conn.tooltip == null) {
prepareTooltipString(conn);
}
verboseBox.setText(conn.tooltip);
}
}
});
// Set data column width greedy // Set data column width greedy
dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
@ -254,10 +277,29 @@ public class RadioLogger extends VisPlugin {
popupMenu.addSeparator(); popupMenu.addSeparator();
popupMenu.add(new JMenuItem(timeLineAction)); popupMenu.add(new JMenuItem(timeLineAction));
popupMenu.add(new JMenuItem(logListenerAction)); popupMenu.add(new JMenuItem(logListenerAction));
//a group of radio button menu items
popupMenu.addSeparator();
ButtonGroup group = new ButtonGroup();
JRadioButtonMenuItem rbMenuItem = new JRadioButtonMenuItem(noAnalyzer);
rbMenuItem.setSelected(true);
group.add(rbMenuItem);
popupMenu.add(rbMenuItem);
rbMenuItem = new JRadioButtonMenuItem(lowpanAnalyzer);
group.add(rbMenuItem);
popupMenu.add(rbMenuItem);
dataTable.setComponentPopupMenu(popupMenu); dataTable.setComponentPopupMenu(popupMenu);
add(new JScrollPane(dataTable)); verboseBox = new JTextPane();
verboseBox.setContentType("text/html");
verboseBox.setEditable(false);
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
new JScrollPane(dataTable), new JScrollPane(verboseBox));
split.setDividerLocation(150);
add(split);
TableColumnAdjuster adjuster = new TableColumnAdjuster(dataTable); TableColumnAdjuster adjuster = new TableColumnAdjuster(dataTable);
adjuster.setDynamicAdjustment(true); adjuster.setDynamicAdjustment(true);
adjuster.packColumns(); adjuster.packColumns();
@ -338,7 +380,43 @@ public class RadioLogger extends VisPlugin {
conn.data = "[unknown data]"; conn.data = "[unknown data]";
return; return;
} }
conn.data = data.length + ": 0x" + StringUtils.toHex(data, 4);
StringBuffer brief = new StringBuffer();
StringBuffer verbose = new StringBuffer();
/* default anlayzer */
PacketAnalyzer.Packet packet = new PacketAnalyzer.Packet(data, PacketAnalyzer.MAC_LEVEL);
if (analyzePacket(packet, brief, verbose)) {
conn.data = (data.length < 10 ? " " : "") + data.length + ": " + brief;
if (packet.hasMoreData()) {
conn.data += ": " + StringUtils.toHex(packet.getPayload(), 4);
}
if (verbose.length() > 0) {
conn.tooltip = verbose.toString();
}
} else {
conn.data = data.length + ": 0x" + StringUtils.toHex(data, 4);
}
}
private boolean analyzePacket(PacketAnalyzer.Packet packet, StringBuffer brief, StringBuffer verbose) {
if (analyzers == null) return false;
boolean analyze = true;
while (analyze) {
analyze = false;
for (int i = 0; i < analyzers.size(); i++) {
PacketAnalyzer analyzer = analyzers.get(i);
if (analyzer.matchPacket(packet)) {
analyzer.analyzePacket(packet, brief, verbose);
/* continue another round if more bytes left */
analyze = packet.hasMoreData();
brief.append("|");
break;
}
}
}
return brief.length() > 0;
} }
private void prepareTooltipString(RadioConnectionLog conn) { private void prepareTooltipString(RadioConnectionLog conn) {
@ -373,7 +451,6 @@ public class RadioLogger extends VisPlugin {
"<pre>" + StringUtils.hexDump(data) + "</pre>" + "<pre>" + StringUtils.hexDump(data) + "</pre>" +
"</font></html>"; "</font></html>";
} }
} }
public void closePlugin() { public void closePlugin() {
@ -549,6 +626,19 @@ public class RadioLogger extends VisPlugin {
} }
}; };
private Action lowpanAnalyzer = new AbstractAction("6LoWPAN Analyzer") {
public void actionPerformed(ActionEvent arg0) {
analyzers = lowpanAnalyzers;
}
};
private Action noAnalyzer = new AbstractAction("No Analyzer") {
public void actionPerformed(ActionEvent arg0) {
analyzers = null;
}
};
private Action logListenerAction = new AbstractAction("to Log Listener") { private Action logListenerAction = new AbstractAction("to Log Listener") {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
LogListener plugin = (LogListener) simulation.getGUI().getStartedPlugin(LogListener.class.getName()); LogListener plugin = (LogListener) simulation.getGUI().getStartedPlugin(LogListener.class.getName());

View file

@ -24,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* $Id: StringUtils.java,v 1.3 2009/10/29 10:10:22 fros4943 Exp $ * $Id: StringUtils.java,v 1.4 2010/02/23 22:32:57 joxe Exp $
*/ */
package se.sics.cooja.util; package se.sics.cooja.util;
@ -52,6 +52,10 @@ public class StringUtils {
// Prevent instances of this class // Prevent instances of this class
} }
public static String toHex(byte data) {
return "" + HEX[(data >> 4) & 0xf] + HEX[data & 0xf];
}
public static String toHex(byte[] data) { public static String toHex(byte[] data) {
char[] buf = new char[data.length * 2]; char[] buf = new char[data.length * 2];
for (int i = 0, j = 0, n = data.length; i < n; i++, j += 2) { for (int i = 0, j = 0, n = data.length; i < n; i++, j += 2) {