From 188ce975ca05ea5c1876c14c93a2440a5c0a945d Mon Sep 17 00:00:00 2001 From: fros4943 Date: Wed, 1 Apr 2009 23:40:00 +0000 Subject: [PATCH] radio logger plugin facelift: display the original packet data instead of only the converted data. this allows viewing all bytes sent from for example sky motes, including radio/mac headers --- .../se/sics/cooja/plugins/RadioLogger.java | 633 ++++-------------- 1 file changed, 137 insertions(+), 496 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java b/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java index dd37d938b..0b40c5425 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java +++ b/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Swedish Institute of Computer Science. + * Copyright (c) 2009, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: RadioLogger.java,v 1.15 2009/04/01 13:53:37 fros4943 Exp $ + * $Id: RadioLogger.java,v 1.16 2009/04/01 23:40:00 fros4943 Exp $ */ package se.sics.cooja.plugins; @@ -45,38 +45,32 @@ import se.sics.cooja.interfaces.Radio; /** * Radio logger listens to the simulation radio medium and lists all transmitted - * data in a table. By overriding the transformDataToString method, protocol - * specific data can be interpreted. + * data in a table. * - * @see #transformDataToString(byte[]) * @author Fredrik Osterlind */ @ClassDescription("Radio Logger") @PluginType(PluginType.SIM_PLUGIN) public class RadioLogger extends VisPlugin { - private static final long serialVersionUID = 1L; - - private final int DATAPOS_TIME = 0; - private final int DATAPOS_CONNECTION = 1; - private final int DATAPOS_PACKET = 2; - - private final int COLUMN_TIME = 0; - private final int COLUMN_FROM = 1; - private final int COLUMN_TO = 2; - private final int COLUMN_DATA = 3; - private static Logger logger = Logger.getLogger(RadioLogger.class); + private final static int COLUMN_TIME = 0; + private final static int COLUMN_FROM = 1; + private final static int COLUMN_TO = 2; + private final static int COLUMN_DATA = 3; + + private final static String[] COLUMN_NAMES = { + "Time", + "From", + "To", + "Data" + }; + private Simulation simulation; - - private Vector columnNames = new Vector(); - - private Vector rowData = new Vector(); - + //private ArrayList rowData = new ArrayList(); + private ArrayList connections = new ArrayList(); private JTable dataTable = null; - private RadioMedium radioMedium; - private Observer radioMediumObserver; public RadioLogger(final Simulation simulationToControl, final GUI gui) { @@ -84,54 +78,50 @@ public class RadioLogger extends VisPlugin { simulation = simulationToControl; radioMedium = simulation.getRadioMedium(); - columnNames.add("Time"); - columnNames.add("From"); - columnNames.add("To"); - columnNames.add("Data"); - final AbstractTableModel model = new AbstractTableModel() { public String getColumnName(int col) { - return columnNames.get(col).toString(); + return COLUMN_NAMES[col]; } public int getRowCount() { - return rowData.size(); + return connections.size(); } public int getColumnCount() { - return columnNames.size(); + return COLUMN_NAMES.length; } public Object getValueAt(int row, int col) { + RadioConnectionLog conn = connections.get(row); if (col == COLUMN_TIME) { - return rowData.get(row)[DATAPOS_TIME]; + return conn.startTime; } else if (col == COLUMN_FROM) { - return ((RadioConnection)rowData.get(row)[DATAPOS_CONNECTION]).getSource().getMote(); + return conn.connection.getSource().getMote(); } else if (col == COLUMN_TO) { - return "[" + ((RadioConnection)rowData.get(row)[DATAPOS_CONNECTION]).getDestinations().length + " motes]"; - } else if (col == COLUMN_DATA) { - RadioPacket packet = (RadioPacket) rowData.get(row)[DATAPOS_PACKET]; - if (packet == null) { - return "[null]"; + Radio[] dests = conn.connection.getDestinations(); + if (dests.length == 1) { + return dests[0].getMote(); } - - return transformDataToString(packet.getPacketData()); - } else { - logger.fatal("Bad row/col: " + row + "/" + col); + return "[" + dests.length + " motes]"; + } else if (col == COLUMN_DATA) { + if (conn.data == null) { + prepareDataString(connections.get(row)); + } + return conn.data; } return null; } public boolean isCellEditable(int row, int col) { if (col == COLUMN_FROM) { - // Try to highligt selected mote - gui.signalMoteHighlight( - ((RadioConnection)rowData.get(row)[DATAPOS_CONNECTION]).getSource().getMote() - ); + /* Highlight source */ + gui.signalMoteHighlight(connections.get(row).connection.getSource().getMote()); + return false; } if (col == COLUMN_TO) { - Radio dests[] = ((RadioConnection)rowData.get(row)[DATAPOS_CONNECTION]).getDestinations(); + /* Highlight all destinations */ + Radio dests[] = connections.get(row).connection.getDestinations(); for (Radio dest: dests) { gui.signalMoteHighlight(dest.getMote()); } @@ -145,26 +135,26 @@ public class RadioLogger extends VisPlugin { } }; - final JComboBox comboBox = new JComboBox(); + final JComboBox destinationComboBox = new JComboBox(); dataTable = new JTable(model) { public TableCellEditor getCellEditor(int row, int column) { - // Populate combo box - comboBox.removeAllItems(); - if (row < 0 || row >= rowData.size()) { + /* Reset destination box */ + destinationComboBox.removeAllItems(); + if (row < 0 || row >= connections.size()) { return super.getCellEditor(row, column); } - RadioConnection conn = (RadioConnection) rowData.get(row)[DATAPOS_CONNECTION]; + RadioConnection conn = connections.get(row).connection; if (conn == null) { return super.getCellEditor(row, column); } for (Radio destRadio: conn.getDestinations()) { if (destRadio.getMote() != null) { - comboBox.addItem(destRadio.getMote()); + destinationComboBox.addItem(destRadio.getMote()); } else { - comboBox.addItem("[standalone radio]"); + destinationComboBox.addItem("[standalone radio]"); } } @@ -177,63 +167,72 @@ public class RadioLogger extends VisPlugin { int colIndex = columnAtPoint(p); int realColumnIndex = convertColumnIndexToModel(colIndex); - String tip = ""; - if (realColumnIndex == COLUMN_DATA) { - RadioPacket packet = (RadioPacket) rowData.get(rowIndex)[DATAPOS_PACKET]; - if (packet != null) { - byte[] data = packet.getPacketData(); - - LoggedPacket logPacket = analyzePacket(data); - if (logPacket != null) { - tip = logPacket.getToolTip(); - } + RadioConnectionLog conn = connections.get(rowIndex); + if (realColumnIndex == COLUMN_TIME) { + return + "" + + "Start time: " + conn.startTime + + "
" + + "End time: " + conn.endTime + + "

" + + "Duration: " + (conn.endTime - conn.startTime)+ + ""; + } else if (realColumnIndex == COLUMN_FROM) { + return conn.connection.getSource().getMote().toString(); + } else if (realColumnIndex == COLUMN_TO) { + String tip = ""; + Radio[] dests = conn.connection.getDestinations(); + for (Radio radio: dests) { + tip += radio.getMote() + "
"; } - - - } else { - tip = super.getToolTipText(e); + tip += ""; + return tip; + } else if (realColumnIndex == COLUMN_DATA) { + if (conn.tooltip == null) { + prepareTooltipString(conn); + } + return conn.tooltip; } - return tip; + return super.getToolTipText(e); } }; // Set data column width greedy dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); - dataTable.getColumnModel().getColumn(COLUMN_TIME).setPreferredWidth(55); - dataTable.getColumnModel().getColumn(COLUMN_FROM).setPreferredWidth(130); - dataTable.getColumnModel().getColumn(COLUMN_TO).setPreferredWidth(100); + dataTable.getColumnModel().getColumn(COLUMN_TIME).setPreferredWidth(150); + dataTable.getColumnModel().getColumn(COLUMN_TIME).setResizable(false); + dataTable.getColumnModel().getColumn(COLUMN_FROM).setPreferredWidth(250); + dataTable.getColumnModel().getColumn(COLUMN_TO).setPreferredWidth(250); + dataTable.getColumnModel().getColumn(COLUMN_DATA).setPreferredWidth(1500); dataTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); TableColumn destColumn = dataTable.getColumnModel().getColumn(COLUMN_TO); - destColumn.setCellEditor(new DefaultCellEditor(comboBox)); - - final JScrollPane scrollPane = new JScrollPane(dataTable); -// dataTable.setFillsViewportHeight(true); - - add(scrollPane); + destColumn.setCellEditor(new DefaultCellEditor(destinationComboBox)); simulation.getRadioMedium().addRadioMediumObserver(radioMediumObserver = new Observer() { public void update(Observable obs, Object obj) { - RadioConnection[] newConnections = radioMedium.getLastTickConnections(); - if (newConnections == null) { + RadioConnection[] conns = radioMedium.getLastTickConnections(); + if (conns == null) { return; } - for (RadioConnection newConnection: newConnections) { - Object[] data = new Object[3]; - data[DATAPOS_TIME] = new Long(simulation.getSimulationTime()); - data[DATAPOS_CONNECTION] = newConnection; - - data[DATAPOS_PACKET] = newConnection.getSource().getLastPacketTransmitted(); - - rowData.add(data); + for (RadioConnection conn : conns) { + RadioConnectionLog loggedConn = new RadioConnectionLog(); + loggedConn.startTime = conn.getStartTime(); + loggedConn.endTime = simulation.getSimulationTime(); + loggedConn.connection = conn; + loggedConn.packet = conn.getSource().getLastPacketTransmitted(); + connections.add(loggedConn); } - model.fireTableRowsInserted(rowData.size() - newConnections.length + 1, rowData.size()); - setTitle("Radio Logger: " + rowData.size() + " packets"); + model.fireTableRowsInserted(connections.size() - conns.length + 1, connections.size()); + setTitle("Radio Logger: " + connections.size() + " packets"); } }); + add(new JScrollPane(dataTable)); + + setSize(500, 300); try { setSelected(true); } catch (java.beans.PropertyVetoException e) { @@ -241,423 +240,56 @@ public class RadioLogger extends VisPlugin { } } - /** - * Transform transmitted data to representable object, such as a string. - * - * @param data Transmitted data - * @return Representable object - */ - public Object transformDataToString(byte[] data) { - if (data == null) { - return "[unknown data]"; - } - - LoggedPacket packet = analyzePacket(data); - if (packet == null) { - return "Unknown packet, size " + data.length; + private void prepareDataString(RadioConnectionLog conn) { + byte[] data; + if (conn.packet instanceof ConvertedRadioPacket) { + data = ((ConvertedRadioPacket)conn.packet).getOriginalPacketData(); } else { - return packet.getShortDescription(); + data = conn.packet.getPacketData(); + } + if (data == null) { + conn.data = "[unknown data]"; + return; + } + + conn.data = ""; + for (byte b: data) { + String hexB = "0" + Integer.toHexString(b); + hexB = hexB.substring(hexB.length() - 2); + conn.data += "0x" + hexB + " "; } } - static abstract class LoggedPacket { - public abstract String getShortDescription(); - public abstract String getToolTip(); - } - - static class PacketAODV_RREQ extends LoggedPacket { - public final static int SIZE = 52; - public final static int HEADER_SIZE = 24; - public final static int TYPE = 1; - - private byte[] data; - public PacketAODV_RREQ(byte[] packetData) { - this.data = new byte[HEADER_SIZE]; - System.arraycopy(packetData, packetData.length - HEADER_SIZE, data, 0, HEADER_SIZE); + private void prepareTooltipString(RadioConnectionLog conn) { + RadioPacket packet = conn.packet; + if (packet == null) { + conn.tooltip = ""; + return; } - public int getType() { - return data[0]; + byte[] data; + if (packet instanceof ConvertedRadioPacket) { + data = ((ConvertedRadioPacket)packet).getOriginalPacketData(); + } else { + data = packet.getPacketData(); } - public int getFlags() { - return data[1]; - } - - public int getReserved() { - return data[2]; - } - - public int getHopCount() { - return data[3]; - } - - public int getID() { - int id = - ((data[4] & 0xFF) << 24) + - ((data[5] & 0xFF) << 16) + - ((data[6] & 0xFF) << 8) + - ((data[7] & 0xFF) << 0); - return id; - } - - public String getDestAddr() { - return (0xff&data[8]) + "." + (0xff&data[9]) + "." + (0xff&data[10]) + "." + (0xff&data[11]); - } - - public int getDestSeqNo() { - int seqNo = - ((data[12] & 0xFF) << 24) + - ((data[13] & 0xFF) << 16) + - ((data[14] & 0xFF) << 8) + - ((data[15] & 0xFF) << 0); - return seqNo; - } - - public String getOrigAddr() { - return (0xff&data[16]) + "." + (0xff&data[17]) + "." + (0xff&data[18]) + "." + (0xff&data[19]); - } - - public int getOrigSeqNo() { - int seqNo = - ((data[20] & 0xFF) << 24) + - ((data[21] & 0xFF) << 16) + - ((data[22] & 0xFF) << 8) + - ((data[23] & 0xFF) << 0); - return seqNo; - } - - public String getShortDescription() { - return "AODV RREQ to " + getDestAddr() + " from " + getOrigAddr(); - } - - public String getToolTip() { - return "" + - "AODV RREQ type: " + getType() + "
" + - "AODV RREQ flags: " + getFlags() + "
" + - "AODV RREQ reserved: " + getReserved() + "
" + - "AODV RREQ hop_count: " + getHopCount() + "
" + - "AODV RREQ id: " + getID() + "
" + - "AODV RREQ dest_addr: " + getDestAddr() + "
" + - "AODV RREQ dest_seqno: " + getDestSeqNo() + "
" + - "AODV RREQ orig_addr: " + getOrigAddr() + "
" + - "AODV RREQ orig_seqno: " + getOrigSeqNo() + - ""; - } - - public static boolean dataFits(byte[] packetData) { - if (packetData.length != SIZE) { - return false; + conn.tooltip = "Packet data
"; + int byteCounter = 0; + for (byte b: data) { + String hexB = "0" + Integer.toHexString(b); + hexB = hexB.substring(hexB.length() - 2); + conn.tooltip += "0x" + hexB + " "; + if (byteCounter++ > 2) { + conn.tooltip += "
"; + byteCounter = 0; } - - byte[] dataNoHeader = new byte[HEADER_SIZE]; - System.arraycopy(packetData, packetData.length - HEADER_SIZE, dataNoHeader, 0, HEADER_SIZE); - - if (dataNoHeader[0] != TYPE) { - return false; - } - - return true; } - }; - - static class PacketAODV_RREP extends LoggedPacket { - public final static int SIZE = 56; - public final static int HEADER_SIZE = 20; - public final static int TYPE = 2; - - private byte[] data; - - public PacketAODV_RREP(byte[] packetData) { - this.data = new byte[HEADER_SIZE]; - System.arraycopy(packetData, packetData.length - HEADER_SIZE, data, 0, HEADER_SIZE); + conn.tooltip += "

"; + for (byte b: data) { + conn.tooltip += (char) b; } - - public int getType() { - return data[0]; - } - - public int getFlags() { - return data[1]; - } - - public int getPrefix() { - return data[2]; - } - - public int getHopCount() { - return data[3]; - } - - public String getDestAddr() { - return (0xff&data[4]) + "." + (0xff&data[5]) + "." + (0xff&data[6]) + "." + (0xff&data[7]); - } - - public int getDestSeqNo() { - int seqNo = - ((data[8] & 0xFF) << 24) + - ((data[9] & 0xFF) << 16) + - ((data[10] & 0xFF) << 8) + - ((data[11] & 0xFF) << 0); - return seqNo; - } - - public String getOrigAddr() { - return (0xff&data[12]) + "." + (0xff&data[13]) + "." + (0xff&data[14]) + "." + (0xff&data[15]); - } - - public int getLifetime() { - int seqNo = - ((data[16] & 0xFF) << 24) + - ((data[17] & 0xFF) << 16) + - ((data[18] & 0xFF) << 8) + - ((data[19] & 0xFF) << 0); - return seqNo; - } - - public String getShortDescription() { - return "AODV RREP to " + getDestAddr() + " from " + getOrigAddr(); - } - - public String getToolTip() { - return "" + - "AODV RREP type: " + getType() + "
" + - "AODV RREP flags: " + getFlags() + "
" + - "AODV RREP prefix: " + getPrefix() + "
" + - "AODV RREP hop_count: " + getHopCount() + "
" + - "AODV RREP dest_addr: " + getDestAddr() + "
" + - "AODV RREP dest_seqno: " + getDestSeqNo() + "
" + - "AODV RREP orig_addr: " + getOrigAddr() + "
" + - "AODV RREP lifetime: " + getLifetime() + "
" + - ""; - } - - public static boolean dataFits(byte[] packetData) { - if (packetData.length != SIZE) { - return false; - } - - byte[] dataNoHeader = new byte[HEADER_SIZE]; - System.arraycopy(packetData, packetData.length - HEADER_SIZE, dataNoHeader, 0, HEADER_SIZE); - - if (dataNoHeader[0] != TYPE) { - return false; - } - - return true; - } - }; - - static class PacketAODV_RERR extends LoggedPacket { - public final static int SIZE = 40; - public final static int HEADER_SIZE = 12; - public final static int TYPE = 3; - - private byte[] data; - public PacketAODV_RERR(byte[] packetData) { - this.data = new byte[HEADER_SIZE]; - System.arraycopy(packetData, packetData.length - HEADER_SIZE, data, 0, HEADER_SIZE); - } - - public int getType() { - return data[0]; - } - - public int getFlags() { - return data[1]; - } - - public int getReserved() { - return data[2]; - } - - public int getDestCount() { - return data[3]; - } - - public String getUnreachAddr() { - return (0xff&data[4]) + "." + (0xff&data[5]) + "." + (0xff&data[6]) + "." + (0xff&data[7]); - } - - public int getUnreachSeqNo() { - int seqNo = - ((data[8] & 0xFF) << 24) + - ((data[9] & 0xFF) << 16) + - ((data[10] & 0xFF) << 8) + - ((data[11] & 0xFF) << 0); - return seqNo; - } - - public String getShortDescription() { - return "AODV RERR for " + getUnreachAddr(); - } - - public String getToolTip() { - return "" + - "AODV RERR type: " + getType() + "
" + - "AODV RERR flags: " + getFlags() + "
" + - "AODV RERR reserved: " + getReserved() + "
" + - "AODV RERR dest_count: " + getDestCount() + "
" + - "AODV RERR unreach_addr: " + getUnreachAddr() + "
" + - "AODV RERR unreach_seqno: " + getUnreachSeqNo() + "
" + - ""; - } - - public static boolean dataFits(byte[] packetData) { - if (packetData.length != SIZE) { - return false; - } - - byte[] dataNoHeader = new byte[HEADER_SIZE]; - System.arraycopy(packetData, packetData.length - HEADER_SIZE, dataNoHeader, 0, HEADER_SIZE); - - if (dataNoHeader[0] != TYPE) { - return false; - } - - return true; - } - }; - - static class AckPacket extends LoggedPacket { - public final static int SIZE = 5; - - private byte[] data; - public AckPacket(byte[] packetData) { - this.data = packetData; - } - - public int getChecksum() { - int checksum = - ((data[3] & 0xFF) << 8) + - ((data[4] & 0xFF) << 0); - return checksum; - } - - public String getShortDescription() { - return "ACK"; - } - - public String getToolTip() { - return "" + - "ACK checksum: " + getChecksum() + "
" + - ""; - } - - public static boolean dataFits(byte[] packetData) { - if (packetData.length != SIZE) { - return false; - } - - if (packetData[0] != (byte) 'a') { - return false; - } - - if (packetData[1] != (byte) 'C') { - return false; - } - - if (packetData[2] != (byte) 'k') { - return false; - } - - return true; - } - }; - - static class ForwardedPacketUnknown extends PacketUnknown { - public final static int MINIMUM_SIZE = 4; - - public ForwardedPacketUnknown(byte[] data) { - super(data); - } - - public String getShortDescription() { - return "(FWD) " + super.getShortDescription(); - } - - public static boolean dataFits(byte[] packetData) { - if (packetData.length < ForwardedPacketUnknown.MINIMUM_SIZE) { - return false; - } - - if (packetData[0] != (byte) 'f') { - return false; - } - - if (packetData[1] != (byte) 'W') { - return false; - } - - if (packetData[2] != (byte) 'd') { - return false; - } - - if (packetData[3] != (byte) ':') { - return false; - } - - return true; - } - } - - static class PacketUnknown extends LoggedPacket { - private byte[] data = null; - - public PacketUnknown(byte[] data) { - this.data = data; - } - - public String getShortDescription() { - return "Data packet, size " + data.length; - } - - public String getToolTip() { - String toolTip = "Data packet
"; - - int byteCounter = 0; - for (byte b: data) { - String hexB = "0" + Integer.toHexString(b); - hexB = hexB.substring(hexB.length() - 2); - toolTip += "0x" + hexB + " "; - if (byteCounter++ > 2) { - toolTip += "
"; - byteCounter = 0; - } - } - toolTip += "

"; - for (byte b: data) { - toolTip += (char) b; - } - toolTip += ""; - return toolTip; - } - - } - - private LoggedPacket analyzePacket(byte[] data) { - - if (PacketAODV_RREQ.dataFits(data)) { - return new PacketAODV_RREQ(data); - } - - if (PacketAODV_RREP.dataFits(data)) { - return new PacketAODV_RREP(data); - } - - if (PacketAODV_RERR.dataFits(data)) { - return new PacketAODV_RERR(data); - } - - if (ForwardedPacketUnknown.dataFits(data)) { - return new ForwardedPacketUnknown(data); - } - - if (AckPacket.dataFits(data)) { - return new AckPacket(data); - } - - return new PacketUnknown(data); + conn.tooltip += ""; } public void closePlugin() { @@ -675,4 +307,13 @@ public class RadioLogger extends VisPlugin { return true; } + private class RadioConnectionLog { + long startTime; + long endTime; + RadioConnection connection; + RadioPacket packet; + + String data = null; + String tooltip = null; + } }