new feature: ability to show log listener's output in the timeline, using the mote output plugin's currently
active filter
This commit is contained in:
parent
4811d7f378
commit
eb1a147d7d
1 changed files with 230 additions and 297 deletions
|
@ -31,7 +31,6 @@
|
|||
package se.sics.cooja.plugins;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
|
@ -55,7 +54,6 @@ import java.util.Observer;
|
|||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JComboBox;
|
||||
|
@ -70,7 +68,6 @@ import javax.swing.JPanel;
|
|||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.Popup;
|
||||
|
@ -89,7 +86,8 @@ import se.sics.cooja.HasQuickHelp;
|
|||
import se.sics.cooja.Mote;
|
||||
import se.sics.cooja.Plugin;
|
||||
import se.sics.cooja.PluginType;
|
||||
import se.sics.cooja.SimEventCentral.MoteCountListener;
|
||||
import se.sics.cooja.SimEventCentral.LogOutputEvent;
|
||||
import se.sics.cooja.SimEventCentral.LogOutputListener;
|
||||
import se.sics.cooja.Simulation;
|
||||
import se.sics.cooja.VisPlugin;
|
||||
import se.sics.cooja.Watchpoint;
|
||||
|
@ -132,13 +130,14 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
private int paintedMoteHeight = EVENT_PIXEL_HEIGHT;
|
||||
|
||||
private Simulation simulation;
|
||||
private MoteCountListener newMotesListener;
|
||||
private LogOutputListener newMotesListener;
|
||||
|
||||
/* Expermental features: Use currently active plugin to filter Timeline Log outputs */
|
||||
private LogListener logEventFilterPlugin = null;
|
||||
|
||||
private JScrollPane timelineScrollPane;
|
||||
private MoteRuler timelineMoteRuler;
|
||||
private JComponent timeline;
|
||||
private Box eventCheckboxes;
|
||||
private JSplitPane splitPane;
|
||||
|
||||
private Observer moteHighlightObserver = null;
|
||||
private ArrayList<Mote> highlightedMotes = new ArrayList<Mote>();
|
||||
|
@ -150,13 +149,20 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
|
||||
private boolean showRadioRXTX = true;
|
||||
private boolean showRadioChannels = false;
|
||||
private boolean showRadioHW = true;
|
||||
private boolean showLEDs = true;
|
||||
private boolean showRadioOnoff = true;
|
||||
private boolean showLeds = true;
|
||||
private boolean showLogOutputs = false;
|
||||
private boolean showWatchpoints = false;
|
||||
|
||||
private Point popupLocation = null;
|
||||
|
||||
private JCheckBox showWatchpointsCheckBox;
|
||||
private JCheckBox showLogsCheckBox;
|
||||
private JCheckBox showLedsCheckBox;
|
||||
private JCheckBox showRadioOnoffCheckbox;
|
||||
private JCheckBox showRadioChannelsCheckbox;
|
||||
private JCheckBox showRadioTXRXCheckbox;
|
||||
|
||||
/**
|
||||
* @param simulation Simulation
|
||||
* @param gui GUI
|
||||
|
@ -195,149 +201,85 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
return executionDetails;
|
||||
}
|
||||
});
|
||||
viewMenu.add(new JCheckBoxMenuItem(radioChannelsAction) {
|
||||
private static final long serialVersionUID = 6830282466652559714L;
|
||||
public boolean isSelected() {
|
||||
return radioChannels;
|
||||
}
|
||||
});
|
||||
|
||||
fileMenu.add(new JMenuItem(saveDataAction));
|
||||
fileMenu.add(new JMenuItem(statisticsAction));
|
||||
editMenu.add(new JMenuItem(clearAction));
|
||||
|
||||
JCheckBox eventCheckBox;
|
||||
eventCheckBox = createEventCheckbox("Radio traffic", "Show radio transmissions, receptions, and collisions");
|
||||
eventCheckBox.setSelected(showRadioRXTX);
|
||||
eventCheckBox.setName("showRadioRXTX");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
showRadioTXRXCheckbox = createEventCheckbox("Radio traffic", "Show radio transmissions, receptions, and collisions");
|
||||
showRadioTXRXCheckbox.setName("showRadioRXTX");
|
||||
showRadioTXRXCheckbox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioRXTX = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventsMenu.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("Radio channel", "Show different radio channels");
|
||||
eventCheckBox.setSelected(showRadioChannels);
|
||||
eventCheckBox.setName("showRadioChannels");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
eventsMenu.add(showRadioTXRXCheckbox);
|
||||
showRadioOnoffCheckbox = createEventCheckbox("Radio on/off", "Show radio hardware state");
|
||||
showRadioOnoffCheckbox.setSelected(showRadioOnoff);
|
||||
showRadioOnoffCheckbox.setName("showRadioHW");
|
||||
showRadioOnoffCheckbox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioOnoff = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventsMenu.add(showRadioOnoffCheckbox);
|
||||
showRadioChannelsCheckbox = createEventCheckbox("Radio channel", "Show different radio channels");
|
||||
showRadioChannelsCheckbox.setSelected(showRadioChannels);
|
||||
showRadioChannelsCheckbox.setName("showRadioChannels");
|
||||
showRadioChannelsCheckbox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioChannels = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
/*eventCheckboxes.add(eventCheckBox);*/
|
||||
eventsMenu.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("Radio state", "Show radio hardware state");
|
||||
eventCheckBox.setSelected(showRadioHW);
|
||||
eventCheckBox.setName("showRadioHW");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
eventsMenu.add(showRadioChannelsCheckbox);
|
||||
showLedsCheckBox = createEventCheckbox("LEDs", "Show LED state");
|
||||
showLedsCheckBox.setSelected(showLeds);
|
||||
showLedsCheckBox.setName("showLEDs");
|
||||
showLedsCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioHW = ((JCheckBox) e.getSource()).isSelected();
|
||||
showLeds = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventsMenu.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("LEDs", "Show LED state");
|
||||
eventCheckBox.setSelected(showLEDs);
|
||||
eventCheckBox.setName("showLEDs");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showLEDs = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventsMenu.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("Log output", "Show mote log output, such as by printf()'s");
|
||||
eventCheckBox.setSelected(showLogOutputs);
|
||||
eventCheckBox.setName("showLogOutput");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
eventsMenu.add(showLedsCheckBox);
|
||||
showLogsCheckBox = createEventCheckbox("Log output", "Show mote log output, such as printf()'s");
|
||||
showLogsCheckBox.setSelected(showLogOutputs);
|
||||
showLogsCheckBox.setName("showLogOutput");
|
||||
showLogsCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showLogOutputs = ((JCheckBox) e.getSource()).isSelected();
|
||||
|
||||
/* Check whether there is an active log listener that is used to filter logs */
|
||||
logEventFilterPlugin = (LogListener) simulation.getGUI().getPlugin(
|
||||
LogListener.class.getName());
|
||||
if (showLogOutputs) {
|
||||
if (logEventFilterPlugin != null) {
|
||||
logger.info("Filtering shown log outputs by use of " + GUI.getDescriptionOf(LogListener.class) + " plugin");
|
||||
} else {
|
||||
logger.info("No active " + GUI.getDescriptionOf(LogListener.class) + " plugin, not filtering log outputs");
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
/*eventCheckboxes.add(eventCheckBox);*/
|
||||
eventCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for MSPSim-based motes)");
|
||||
eventCheckBox.setSelected(showWatchpoints);
|
||||
eventCheckBox.setName("showWatchpoints");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
eventsMenu.add(showLogsCheckBox);
|
||||
showWatchpointsCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for emulated motes)");
|
||||
showWatchpointsCheckBox.setSelected(showWatchpoints);
|
||||
showWatchpointsCheckBox.setName("showWatchpoints");
|
||||
showWatchpointsCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showWatchpoints = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventsMenu.add(eventCheckBox);
|
||||
eventsMenu.add(showWatchpointsCheckBox);
|
||||
|
||||
/* Box: events to observe */
|
||||
|
||||
eventCheckboxes = Box.createVerticalBox();
|
||||
/*
|
||||
eventCheckboxes.add(new JButton(addMoteAction));
|
||||
eventCheckboxes.add(new JSeparator());
|
||||
|
||||
JCheckBox eventCheckBox;
|
||||
eventCheckBox = createEventCheckbox("Radio RX/TX", "Show radio transmissions, receptions, and collisions");
|
||||
eventCheckBox.setSelected(showRadioRXTX);
|
||||
eventCheckBox.setName("showRadioRXTX");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioRXTX = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventCheckboxes.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("Radio channels", "Show different radio channels");
|
||||
eventCheckBox.setSelected(showRadioChannels);
|
||||
eventCheckBox.setName("showRadioChannels");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioChannels = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
|
||||
eventCheckBox = createEventCheckbox("Radio ON/OFF", "Show radio hardware state");
|
||||
eventCheckBox.setSelected(showRadioHW);
|
||||
eventCheckBox.setName("showRadioHW");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showRadioHW = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventCheckboxes.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("LEDs", "Show LED state");
|
||||
eventCheckBox.setSelected(showLEDs);
|
||||
eventCheckBox.setName("showLEDs");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showLEDs = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventCheckboxes.add(eventCheckBox);
|
||||
eventCheckBox = createEventCheckbox("Log output", "Show mote log output, such as by printf()'s");
|
||||
eventCheckBox.setSelected(showLogOutputs);
|
||||
eventCheckBox.setName("showLogOutput");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showLogOutputs = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
|
||||
eventCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for MSPSim-based motes)");
|
||||
eventCheckBox.setSelected(showWatchpoints);
|
||||
eventCheckBox.setName("showWatchpoints");
|
||||
eventCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showWatchpoints = ((JCheckBox) e.getSource()).isSelected();
|
||||
recalculateMoteHeight();
|
||||
}
|
||||
});
|
||||
eventCheckboxes.add(eventCheckBox);
|
||||
*/
|
||||
/* Panel: timeline canvas w. scroll pane and add mote button */
|
||||
timeline = new Timeline();
|
||||
timelineScrollPane = new JScrollPane(
|
||||
|
@ -350,13 +292,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
timelineScrollPane.setRowHeaderView(timelineMoteRuler);
|
||||
timelineScrollPane.setBackground(Color.WHITE);
|
||||
|
||||
splitPane = new JSplitPane(
|
||||
JSplitPane.HORIZONTAL_SPLIT,
|
||||
new JScrollPane(eventCheckboxes),
|
||||
timelineScrollPane
|
||||
);
|
||||
splitPane.setOneTouchExpandable(true);
|
||||
|
||||
/* Zoom in/out via keyboard*/
|
||||
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyEvent.CTRL_DOWN_MASK), "zoomIn");
|
||||
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK), "zoomIn");
|
||||
|
@ -374,14 +309,30 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
|
||||
numberMotesWasUpdated();
|
||||
|
||||
/* Automatically add/delete motes */
|
||||
simulation.getEventCentral().addMoteCountListener(newMotesListener = new MoteCountListener() {
|
||||
/* Automatically add/delete motes.
|
||||
* This listener also observes mote log outputs. */
|
||||
simulation.getEventCentral().addLogOutputListener(newMotesListener = new LogOutputListener() {
|
||||
public void moteWasAdded(Mote mote) {
|
||||
addMote(mote);
|
||||
}
|
||||
public void moteWasRemoved(Mote mote) {
|
||||
removeMote(mote);
|
||||
}
|
||||
public void removedLogOutput(LogOutputEvent ev) {
|
||||
}
|
||||
public void newLogOutput(LogOutputEvent ev) {
|
||||
/* Log output */
|
||||
Mote mote = ev.getMote();
|
||||
LogEvent logEvent = new LogEvent(ev);
|
||||
|
||||
/* TODO Optimize */
|
||||
for (MoteEvents moteEvents: allMoteEvents) {
|
||||
if (moteEvents.mote == mote) {
|
||||
moteEvents.addLog(logEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
for (Mote m: simulation.getMotes()) {
|
||||
addMote(m);
|
||||
|
@ -427,6 +378,17 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
this.setSize(gui.getDesktopPane().getWidth(), 166);
|
||||
}
|
||||
|
||||
public void startPlugin() {
|
||||
super.startPlugin();
|
||||
|
||||
showWatchpointsCheckBox.setSelected(showWatchpoints);
|
||||
showLogsCheckBox.setSelected(showLogOutputs);
|
||||
showLedsCheckBox.setSelected(showLeds);
|
||||
showRadioOnoffCheckbox.setSelected(showRadioOnoff);
|
||||
showRadioChannelsCheckbox.setSelected(showRadioChannels);
|
||||
showRadioTXRXCheckbox.setSelected(showRadioRXTX);
|
||||
}
|
||||
|
||||
private JCheckBox createEventCheckbox(String text, String tooltip) {
|
||||
JCheckBox checkBox = new JCheckBox(text, true);
|
||||
checkBox.setToolTipText(tooltip);
|
||||
|
@ -503,7 +465,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
private static final long serialVersionUID = 7546685285707302865L;
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
JComboBox source = new JComboBox();
|
||||
JComboBox<Object> source = new JComboBox<Object>();
|
||||
source.addItem("All motes");
|
||||
for (Mote m: simulation.getMotes()) {
|
||||
source.addItem(m);
|
||||
|
@ -876,8 +838,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO Radio channels */
|
||||
|
||||
if (radioHW) {
|
||||
for (MoteEvent ev: moteEvents.radioHWEvents) {
|
||||
if (!(ev instanceof RadioHWEvent)) continue;
|
||||
|
@ -923,8 +883,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO Watchpoints */
|
||||
|
||||
output.append(stats.toString(logs, leds, radioHW, radioRXTX));
|
||||
}
|
||||
|
||||
|
@ -976,7 +934,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
});
|
||||
}
|
||||
|
||||
private Action radioLoggerAction = new AbstractAction("Show in Radio Logger") {
|
||||
private Action radioLoggerAction = new AbstractAction("Show in " + GUI.getDescriptionOf(RadioLogger.class)) {
|
||||
private static final long serialVersionUID = 7690116136861949864L;
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (popupLocation == null) {
|
||||
|
@ -996,7 +954,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
}
|
||||
};
|
||||
private Action logListenerAction = new AbstractAction("Show in Log Listener") {
|
||||
private Action logListenerAction = new AbstractAction("Show in " + GUI.getDescriptionOf(LogListener.class)) {
|
||||
private static final long serialVersionUID = -8626118368774023257L;
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (popupLocation == null) {
|
||||
|
@ -1017,7 +975,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
};
|
||||
|
||||
private Action showInAllAction = new AbstractAction("Show in log listener and radio logger") {
|
||||
private Action showInAllAction = new AbstractAction("Show in " + GUI.getDescriptionOf(LogListener.class) + " and " + GUI.getDescriptionOf(RadioLogger.class)) {
|
||||
private static final long serialVersionUID = -2458733078524773995L;
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
logListenerAction.actionPerformed(null);
|
||||
|
@ -1026,20 +984,12 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
};
|
||||
|
||||
private boolean executionDetails = false;
|
||||
private boolean radioChannels = false;
|
||||
private Action executionDetailsAction = new AbstractAction("Show execution details in tooltips") {
|
||||
private static final long serialVersionUID = -8626118368774023257L;
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
executionDetails = !executionDetails;
|
||||
}
|
||||
};
|
||||
private Action radioChannelsAction = new AbstractAction("Color radio state by active radio channel") {
|
||||
private static final long serialVersionUID = -8626118368774023257L;
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
radioChannels = !radioChannels;
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
private void numberMotesWasUpdated() {
|
||||
/* Plugin title */
|
||||
|
@ -1101,9 +1051,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
|
||||
private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) {
|
||||
/* TODO Log: final Log moteLog = mote.getInterfaces().getLog(); */
|
||||
/* TODO Unknown state event */
|
||||
|
||||
/* LEDs */
|
||||
final LED moteLEDs = mote.getInterfaces().getLED();
|
||||
if (moteLEDs != null) {
|
||||
|
@ -1131,69 +1078,59 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
activeMoteObservers.add(new MoteObservation(mote, moteLEDs, observer));
|
||||
}
|
||||
|
||||
/* Radio HW, RXTX */
|
||||
/* Radio OnOff, RXTX, and channels */
|
||||
final Radio moteRadio = mote.getInterfaces().getRadio();
|
||||
if (moteRadio != null) {
|
||||
RadioChannelEvent startupChannel = new RadioChannelEvent(
|
||||
simulation.getSimulationTime(), moteRadio.getChannel(), moteRadio.isRadioOn());
|
||||
moteEvents.addRadioChannel(startupChannel);
|
||||
RadioHWEvent startupHW = new RadioHWEvent(
|
||||
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
||||
if (radioChannels) {
|
||||
startupHW.channel = moteRadio.getChannel();
|
||||
}
|
||||
moteEvents.addRadioHW(startupHW);
|
||||
RadioRXTXEvent startupRXTX = new RadioRXTXEvent(
|
||||
simulation.getSimulationTime(), RXTXRadioEvent.IDLE);
|
||||
moteEvents.addRadioRXTX(startupRXTX);
|
||||
Observer observer = new Observer() {
|
||||
int lastChannel = -1;
|
||||
public void update(Observable o, Object arg) {
|
||||
/* Radio HW events */
|
||||
if (radioChannels && moteRadio.getLastEvent() == RadioEvent.UNKNOWN) {
|
||||
int nowChannel = moteRadio.getChannel();
|
||||
if (nowChannel == lastChannel) {
|
||||
return;
|
||||
}
|
||||
lastChannel = nowChannel;
|
||||
int lastChannel = -1;
|
||||
public void update(Observable o, Object arg) {
|
||||
RadioEvent radioEv = moteRadio.getLastEvent();
|
||||
|
||||
String details = null;
|
||||
if (executionDetails && mote instanceof AbstractEmulatedMote) {
|
||||
details = ((AbstractEmulatedMote) mote).getExecutionDetails();
|
||||
if (details != null) {
|
||||
details = "<br>" + details.replace("\n", "<br>");
|
||||
}
|
||||
}
|
||||
|
||||
/* Radio channel */
|
||||
int nowChannel = moteRadio.getChannel();
|
||||
if (nowChannel != lastChannel) {
|
||||
lastChannel = nowChannel;
|
||||
RadioChannelEvent ev = new RadioChannelEvent(
|
||||
simulation.getSimulationTime(), nowChannel, moteRadio.isRadioOn());
|
||||
moteEvents.addRadioChannel(ev);
|
||||
|
||||
ev.details = details;
|
||||
}
|
||||
|
||||
if (radioEv == RadioEvent.HW_ON ||
|
||||
radioEv == RadioEvent.HW_OFF) {
|
||||
RadioHWEvent ev = new RadioHWEvent(
|
||||
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
||||
if (radioChannels) {
|
||||
ev.channel = moteRadio.getChannel();
|
||||
}
|
||||
|
||||
moteEvents.addRadioHW(ev);
|
||||
|
||||
if (executionDetails && mote instanceof AbstractEmulatedMote) {
|
||||
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
|
||||
if (details != null) {
|
||||
details = "<br>" + details.replace("\n", "<br>");
|
||||
ev.details = details;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
ev.details = details;
|
||||
|
||||
if (moteRadio.getLastEvent() == RadioEvent.HW_ON ||
|
||||
moteRadio.getLastEvent() == RadioEvent.HW_OFF) {
|
||||
RadioHWEvent ev = new RadioHWEvent(
|
||||
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
||||
if (radioChannels) {
|
||||
ev.channel = moteRadio.getChannel();
|
||||
}
|
||||
|
||||
moteEvents.addRadioHW(ev);
|
||||
|
||||
if (executionDetails && mote instanceof AbstractEmulatedMote) {
|
||||
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
|
||||
if (details != null) {
|
||||
details = "<br>" + details.replace("\n", "<br>");
|
||||
ev.details = details;
|
||||
}
|
||||
}
|
||||
return;
|
||||
/* Also create another channel event here */
|
||||
lastChannel = nowChannel;
|
||||
RadioChannelEvent ev2 = new RadioChannelEvent(
|
||||
simulation.getSimulationTime(), nowChannel, moteRadio.isRadioOn());
|
||||
ev2.details = details;
|
||||
moteEvents.addRadioChannel(ev2);
|
||||
}
|
||||
|
||||
/* Radio RXTX events */
|
||||
RadioEvent radioEv = moteRadio.getLastEvent();
|
||||
if (radioEv == RadioEvent.TRANSMISSION_STARTED ||
|
||||
radioEv == RadioEvent.TRANSMISSION_FINISHED ||
|
||||
radioEv == RadioEvent.RECEPTION_STARTED ||
|
||||
|
@ -1221,15 +1158,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
|
||||
moteEvents.addRadioRXTX(ev);
|
||||
|
||||
if (executionDetails && mote instanceof AbstractEmulatedMote) {
|
||||
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
|
||||
if (details != null) {
|
||||
details = "<br>" + details.replace("\n", "<br>");
|
||||
ev.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
ev.details = details;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1239,7 +1168,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer));
|
||||
}
|
||||
|
||||
/* XXX Experimental: Watchpoints */
|
||||
/* Watchpoints */
|
||||
if (mote instanceof WatchpointMote) {
|
||||
final WatchpointMote watchpointMote = ((WatchpointMote)mote);
|
||||
WatchpointListener listener = new WatchpointListener() {
|
||||
|
@ -1317,10 +1246,10 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
if (showRadioChannels) {
|
||||
h += EVENT_PIXEL_HEIGHT;
|
||||
}
|
||||
if (showRadioHW) {
|
||||
if (showRadioOnoff) {
|
||||
h += EVENT_PIXEL_HEIGHT;
|
||||
}
|
||||
if (showLEDs) {
|
||||
if (showLeds) {
|
||||
h += 3*LED_PIXEL_HEIGHT;
|
||||
}
|
||||
if (showLogOutputs) {
|
||||
|
@ -1378,11 +1307,11 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
element = new Element("showRadioChannels");
|
||||
config.add(element);
|
||||
}
|
||||
if (showRadioHW) {
|
||||
if (showRadioOnoff) {
|
||||
element = new Element("showRadioHW");
|
||||
config.add(element);
|
||||
}
|
||||
if (showLEDs) {
|
||||
if (showLeds) {
|
||||
element = new Element("showLEDs");
|
||||
config.add(element);
|
||||
}
|
||||
|
@ -1399,14 +1328,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
element = new Element("executionDetails");
|
||||
config.add(element);
|
||||
}
|
||||
if (radioChannels) {
|
||||
element = new Element("radioChannels");
|
||||
config.add(element);
|
||||
}
|
||||
|
||||
element = new Element("split");
|
||||
element.addContent("" + splitPane.getDividerLocation());
|
||||
config.add(element);
|
||||
|
||||
element = new Element("zoomfactor");
|
||||
element.addContent("" + currentPixelDivisor);
|
||||
|
@ -1418,13 +1339,12 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
||||
showRadioRXTX = false;
|
||||
showRadioChannels = false;
|
||||
showRadioHW = false;
|
||||
showLEDs = false;
|
||||
showRadioOnoff = false;
|
||||
showLeds = false;
|
||||
showLogOutputs = false;
|
||||
showWatchpoints = false;
|
||||
|
||||
executionDetails = false;
|
||||
radioChannels = false;
|
||||
|
||||
/* Remove already registered motes */
|
||||
MoteEvents[] allMoteEventsArr = allMoteEvents.toArray(new MoteEvents[0]);
|
||||
|
@ -1442,19 +1362,16 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
} else if ("showRadioChannels".equals(name)) {
|
||||
showRadioChannels = true;
|
||||
} else if ("showRadioHW".equals(name)) {
|
||||
showRadioHW = true;
|
||||
showRadioOnoff = true;
|
||||
} else if ("showLEDs".equals(name)) {
|
||||
showLEDs = true;
|
||||
showLeds = true;
|
||||
} else if ("showLogOutput".equals(name)) {
|
||||
showLogOutputs = true;
|
||||
} else if ("showWatchpoints".equals(name)) {
|
||||
showWatchpoints = true;
|
||||
|
||||
} else if ("executionDetails".equals(name)) {
|
||||
executionDetails = true;
|
||||
} else if ("radioChannels".equals(name)) {
|
||||
radioChannels = true;
|
||||
} else if ("split".equals(name)) {
|
||||
splitPane.setDividerLocation(Integer.parseInt(element.getText()));
|
||||
} else if ("zoom".equals(name)) {
|
||||
/* NB: Historically this is a one-based not zero-based index */
|
||||
final int zl = Integer.parseInt(element.getText())-1;
|
||||
|
@ -1466,22 +1383,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
}
|
||||
|
||||
/* XXX HACK: Update checkboxes according to config */
|
||||
for (Component c: eventCheckboxes.getComponents()) {
|
||||
if (c.getName() == "showRadioRXTX") {
|
||||
((JCheckBox)c).setSelected(showRadioRXTX);
|
||||
} else if (c.getName() == "showRadioChannels") {
|
||||
((JCheckBox)c).setSelected(showRadioChannels);
|
||||
} else if (c.getName() == "showRadioHW") {
|
||||
((JCheckBox)c).setSelected(showRadioHW);
|
||||
} else if (c.getName() == "showLEDs") {
|
||||
((JCheckBox)c).setSelected(showLEDs);
|
||||
} else if (c.getName() == "showLogOutput") {
|
||||
((JCheckBox)c).setSelected(showLogOutputs);
|
||||
} else if (c.getName() == "showWatchpoints") {
|
||||
((JCheckBox)c).setSelected(showWatchpoints);
|
||||
}
|
||||
}
|
||||
recalculateMoteHeight();
|
||||
|
||||
return true;
|
||||
|
@ -1505,28 +1406,9 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
/* Popup menu */
|
||||
final JPopupMenu popupMenu = new JPopupMenu();
|
||||
|
||||
/* popupMenu.add(new JMenuItem(addMoteAction));
|
||||
|
||||
popupMenu.addSeparator();
|
||||
|
||||
popupMenu.add(new JMenuItem(zoomInAction));
|
||||
popupMenu.add(new JMenuItem(zoomOutAction));
|
||||
popupMenu.add(new JMenuItem(zoomSliderAction));
|
||||
|
||||
popupMenu.addSeparator();
|
||||
|
||||
popupMenu.add(new JMenuItem(saveDataAction));
|
||||
popupMenu.add(new JMenuItem(statisticsAction));
|
||||
popupMenu.add(new JMenuItem(clearAction));
|
||||
|
||||
popupMenu.addSeparator();
|
||||
*/
|
||||
/* JMenu focusMenu = new JMenu("Show in");*/
|
||||
popupMenu.add(new JMenuItem(showInAllAction));
|
||||
/* focusMenu.addSeparator(); */
|
||||
popupMenu.add(new JMenuItem(logListenerAction));
|
||||
popupMenu.add(new JMenuItem(radioLoggerAction));
|
||||
/* popupMenu.add(focusMenu);*/
|
||||
|
||||
JMenu advancedMenu = new JMenu("Advanced");
|
||||
advancedMenu.add(new JCheckBoxMenuItem(executionDetailsAction) {
|
||||
|
@ -1535,13 +1417,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
return executionDetails;
|
||||
}
|
||||
});
|
||||
advancedMenu.add(new JCheckBoxMenuItem(radioChannelsAction) {
|
||||
private static final long serialVersionUID = 6830282466652559714L;
|
||||
public boolean isSelected() {
|
||||
return radioChannels;
|
||||
}
|
||||
});
|
||||
/* popupMenu.add(advancedMenu);*/
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
long lastClick = -1;
|
||||
|
@ -1741,7 +1616,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
|
||||
/*logger.info("Painting interval: " + intervalStart + " -> " + intervalEnd);*/
|
||||
if (bounds.x > Integer.MAX_VALUE - 1000) {
|
||||
/* TODO Strange bounds */
|
||||
/* Strange bounds */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1779,14 +1654,14 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
lineHeightOffset += EVENT_PIXEL_HEIGHT;
|
||||
}
|
||||
if (showRadioHW) {
|
||||
if (showRadioOnoff) {
|
||||
MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).radioHWEvents, intervalStart);
|
||||
if (firstEvent != null) {
|
||||
firstEvent.paintInterval(g, lineHeightOffset, intervalEnd);
|
||||
}
|
||||
lineHeightOffset += EVENT_PIXEL_HEIGHT;
|
||||
}
|
||||
if (showLEDs) {
|
||||
if (showLeds) {
|
||||
MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).ledEvents, intervalStart);
|
||||
if (firstEvent != null) {
|
||||
firstEvent.paintInterval(g, lineHeightOffset, intervalEnd);
|
||||
|
@ -1931,13 +1806,13 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
evMatched++;
|
||||
}
|
||||
if (showRadioHW) {
|
||||
if (showRadioOnoff) {
|
||||
if (evMatched == evMouse) {
|
||||
events = allMoteEvents.get(mote).radioHWEvents;
|
||||
}
|
||||
evMatched++;
|
||||
}
|
||||
if (showLEDs) {
|
||||
if (showLeds) {
|
||||
if (evMatched == evMouse) {
|
||||
events = allMoteEvents.get(mote).ledEvents;
|
||||
}
|
||||
|
@ -2167,16 +2042,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
}
|
||||
}
|
||||
class RadioChannelEvent extends MoteEvent {
|
||||
public RadioChannelEvent(long time) {
|
||||
super(time);
|
||||
}
|
||||
public Color getEventColor() {
|
||||
return Color.GRAY; /* TODO Implement me */
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO Which colors? */
|
||||
private final static Color[] CHANNEL_COLORS = new Color[] {
|
||||
Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"),
|
||||
Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"),
|
||||
|
@ -2190,28 +2056,47 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
Color.decode("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"),
|
||||
Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"),
|
||||
};
|
||||
class RadioChannelEvent extends MoteEvent {
|
||||
int channel;
|
||||
boolean radioOn;
|
||||
public RadioChannelEvent(long time, int channel, boolean radioOn) {
|
||||
super(time);
|
||||
this.channel = channel;
|
||||
this.radioOn = radioOn;
|
||||
}
|
||||
public Color getEventColor() {
|
||||
if (channel >= 0) {
|
||||
if (!radioOn) {
|
||||
return null;
|
||||
}
|
||||
Color c = CHANNEL_COLORS[channel % CHANNEL_COLORS.length];
|
||||
return c;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public String toString() {
|
||||
String str = "Radio channel " + channel + "<br>";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
class RadioHWEvent extends MoteEvent {
|
||||
boolean on;
|
||||
int channel = -1;
|
||||
public RadioHWEvent(long time, boolean on) {
|
||||
super(time);
|
||||
this.on = on;
|
||||
}
|
||||
public RadioHWEvent(long time, boolean on, int channel) {
|
||||
this(time, on);
|
||||
this.channel = channel;
|
||||
}
|
||||
public Color getEventColor() {
|
||||
if (on && radioChannels && channel >= 0 && channel < CHANNEL_COLORS.length) {
|
||||
return CHANNEL_COLORS[channel];
|
||||
if (on) {
|
||||
return Color.GRAY;
|
||||
}
|
||||
return on?Color.GRAY:null;
|
||||
return null;
|
||||
}
|
||||
public String toString() {
|
||||
String str = "Radio HW was turned " + (on?"on":"off") + " at time " + time + "<br>";
|
||||
if (channel > 0) {
|
||||
str += "Radio channel: " + channel;
|
||||
}
|
||||
String str = "Radio HW was turned " + (on?"on":"off") + "<br>";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
@ -2298,11 +2183,56 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
}
|
||||
class LogEvent extends MoteEvent {
|
||||
public LogEvent(long time) {
|
||||
super(time);
|
||||
LogOutputEvent logEvent;
|
||||
public LogEvent(LogOutputEvent ev) {
|
||||
super(ev.getTime());
|
||||
this.logEvent = ev;
|
||||
}
|
||||
public Color getEventColor() {
|
||||
return Color.GRAY; /* TODO Implement me */
|
||||
if (logEventFilterPlugin != null) {
|
||||
/* Ask log listener for event color to use */
|
||||
return logEventFilterPlugin.getColorOfEntry(logEvent);
|
||||
}
|
||||
return Color.GRAY;
|
||||
}
|
||||
/* Default paint method */
|
||||
public void paintInterval(Graphics g, int lineHeightOffset, long end) {
|
||||
LogEvent ev = this;
|
||||
while (ev != null && ev.time < end) {
|
||||
/* Ask active log listener whether this should be filtered */
|
||||
|
||||
if (logEventFilterPlugin != null) {
|
||||
boolean show = logEventFilterPlugin.filterWouldAccept(ev.logEvent);
|
||||
if (!show) {
|
||||
/* Skip painting event */
|
||||
ev = (LogEvent) ev.next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Color color = ev.getEventColor();
|
||||
if (color == null) {
|
||||
/* Skip painting event */
|
||||
ev = (LogEvent) ev.next;
|
||||
continue;
|
||||
}
|
||||
|
||||
g.setColor(color);
|
||||
g.fillRect(
|
||||
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
|
||||
4, EVENT_PIXEL_HEIGHT
|
||||
);
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(
|
||||
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
|
||||
1, EVENT_PIXEL_HEIGHT
|
||||
);
|
||||
|
||||
ev = (LogEvent) ev.next;
|
||||
}
|
||||
}
|
||||
public String toString() {
|
||||
return "Mote " + logEvent.getMote() + " says:<br>" + logEvent.getMessage() + "<br>";
|
||||
}
|
||||
}
|
||||
class WatchpointEvent extends MoteEvent {
|
||||
|
@ -2434,7 +2364,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
}
|
||||
lastRadioChannelEvent = ev;
|
||||
|
||||
/* TODO XXX Requires MSPSim changes */
|
||||
radioChannelEvents.add(ev);
|
||||
}
|
||||
public void addRadioHW(RadioHWEvent ev) {
|
||||
|
@ -2530,19 +2459,23 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
|||
"<b>Timeline</b>" +
|
||||
"<p>The timeline shows simulation events over time. " +
|
||||
"The timeline can be used to inspect activities of individual nodes as well as interactions between nodes." +
|
||||
"<p>For each mote, simulation events are shown on a colored line. Different colors correspond to different events. For more information about a particular event, hover the mouse above it." +
|
||||
"<p>For each mote, simulation events are shown on a colored line. Different colors correspond to different events. For more information about a particular event, mouse click it." +
|
||||
"<p>The <i>Events</i> menu control what event types are shown in the timeline. " +
|
||||
"Currently, four event types are supported (see below). " +
|
||||
"Currently, six event types are supported (see below). " +
|
||||
"<p>All motes are by default shown in the timeline. Motes can be removed from the timeline by right-clicking the node ID on the left." +
|
||||
"<p>To display a vertical time marker on the timeline, press and hold the mouse on the time ruler (top)." +
|
||||
"<p>For more options for a given event, right-click the mouse for a popup menu." +
|
||||
"<p><b>Radio traffic</b>" +
|
||||
"<br>Shows radio traffic events. Transmissions are painted blue, receptions are green, and interfered radios are red." +
|
||||
"<p><b>Radio state</b>" +
|
||||
"<p><b>Radio channel</b>" +
|
||||
"<br>Shows the current radio channel by colors." +
|
||||
"<p><b>Radio on/off</b>" +
|
||||
"<br>Shows whether the mote radio is on or off. When gray, the radio is on." +
|
||||
"<p><b>LEDs</b>" +
|
||||
"<br>Shows LED state: red, green, and blue. (Assumes all mote types have exactly three LEDs.)" +
|
||||
"<p><b>Log outputs</b>" +
|
||||
"<br>Shows log outputs, as also shown in " + GUI.getDescriptionOf(LogListener.class) +
|
||||
"<p><b>Watchpoints</b>" +
|
||||
"<br>Shows triggered watchpoints, currently only supported by MSPSim-based motes. To add watchpoints, use the Msp Code Watcher plugin.";
|
||||
"<br>Shows triggered watchpoints, currently only supported by emulated motes. To add watchpoints, use the Msp Code Watcher plugin.";
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue