added new radio medium: directed graph radio medium (short: dgrm).
this radio medium will likely later be used to implement other more complex radio mediums such as udgm and mrm. currently the user interface (dgrm config plugin) for defining radio links is very limited. experimental: the new radio medium supports propagation delays, configurable via the plugin.
This commit is contained in:
parent
e87d94439e
commit
ab01f2b901
|
@ -2,4 +2,4 @@ se.sics.cooja.GUI.MOTETYPES = se.sics.cooja.motes.DisturberMoteType se.sics.cooj
|
|||
se.sics.cooja.GUI.PLUGINS = se.sics.cooja.plugins.VisState se.sics.cooja.plugins.VisTraffic se.sics.cooja.plugins.LogListener se.sics.cooja.plugins.MoteInformation se.sics.cooja.plugins.MoteInterfaceViewer se.sics.cooja.plugins.VariableWatcher se.sics.cooja.plugins.EventListener se.sics.cooja.plugins.RadioLogger se.sics.cooja.mspmote.plugins.MspCodeWatcher se.sics.cooja.mspmote.plugins.MspStackWatcher se.sics.cooja.mspmote.plugins.MspCycleWatcher
|
||||
se.sics.cooja.GUI.IP_DISTRIBUTORS = se.sics.cooja.ipdistributors.RandomIPDistributor se.sics.cooja.ipdistributors.SpatialIPDistributor se.sics.cooja.ipdistributors.IdIPDistributor
|
||||
se.sics.cooja.GUI.POSITIONERS = se.sics.cooja.positioners.RandomPositioner se.sics.cooja.positioners.LinearPositioner se.sics.cooja.positioners.EllipsePositioner se.sics.cooja.positioners.ManualPositioner
|
||||
se.sics.cooja.GUI.RADIOMEDIUMS = se.sics.cooja.radiomediums.UDGM se.sics.cooja.radiomediums.SilentRadioMedium se.sics.mrm.MRM
|
||||
se.sics.cooja.GUI.RADIOMEDIUMS = se.sics.cooja.radiomediums.UDGM se.sics.cooja.radiomediums.DirectedGraphMedium se.sics.mrm.MRM se.sics.cooja.radiomediums.SilentRadioMedium
|
||||
|
|
|
@ -34,4 +34,4 @@ se.sics.cooja.GUI.MOTETYPES = se.sics.cooja.motes.DisturberMoteType se.sics.cooj
|
|||
se.sics.cooja.GUI.PLUGINS = se.sics.cooja.plugins.VisState se.sics.cooja.plugins.VisBattery se.sics.cooja.plugins.VisTraffic se.sics.cooja.plugins.LogListener se.sics.cooja.plugins.MoteInformation se.sics.cooja.plugins.MoteInterfaceViewer se.sics.cooja.plugins.VariableWatcher se.sics.cooja.plugins.EventListener se.sics.cooja.plugins.RadioLogger se.sics.cooja.plugins.ScriptRunner
|
||||
se.sics.cooja.GUI.IP_DISTRIBUTORS = se.sics.cooja.ipdistributors.RandomIPDistributor se.sics.cooja.ipdistributors.SpatialIPDistributor se.sics.cooja.ipdistributors.IdIPDistributor
|
||||
se.sics.cooja.GUI.POSITIONERS = se.sics.cooja.positioners.RandomPositioner se.sics.cooja.positioners.LinearPositioner se.sics.cooja.positioners.EllipsePositioner se.sics.cooja.positioners.ManualPositioner
|
||||
se.sics.cooja.GUI.RADIOMEDIUMS = se.sics.cooja.radiomediums.UDGM se.sics.cooja.radiomediums.SilentRadioMedium
|
||||
se.sics.cooja.GUI.RADIOMEDIUMS = se.sics.cooja.radiomediums.UDGM se.sics.cooja.radiomediums.DirectedGraphMedium se.sics.cooja.radiomediums.SilentRadioMedium
|
||||
|
|
335
tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java
Normal file
335
tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java
Normal file
|
@ -0,0 +1,335 @@
|
|||
package se.sics.cooja.plugins;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import javax.swing.DefaultCellEditor;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.cooja.ClassDescription;
|
||||
import se.sics.cooja.GUI;
|
||||
import se.sics.cooja.Mote;
|
||||
import se.sics.cooja.PluginType;
|
||||
import se.sics.cooja.Simulation;
|
||||
import se.sics.cooja.VisPlugin;
|
||||
import se.sics.cooja.radiomediums.DirectedGraphMedium;
|
||||
|
||||
/**
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
@ClassDescription("DGRM Configurator")
|
||||
@PluginType(PluginType.SIM_PLUGIN)
|
||||
public class DGRMConfigurator extends VisPlugin {
|
||||
private static Logger logger = Logger.getLogger(DGRMConfigurator.class);
|
||||
|
||||
private final static int IDX_SRC = 0;
|
||||
private final static int IDX_DST = 1;
|
||||
private final static int IDX_RATIO = 2;
|
||||
private final static int IDX_DELAY = 3;
|
||||
private final static int IDX_DEL = 4;
|
||||
private final static String[] columns = new String[] {
|
||||
"Source", "Destination", "Success Ratio (%)", "Delay (ms)", "Delete"
|
||||
};
|
||||
|
||||
private GUI gui = null;
|
||||
private DirectedGraphMedium radioMedium = null;
|
||||
private Observer radioMediumObserver;
|
||||
private JTable graphTable = null;
|
||||
private JComboBox combo = new JComboBox();
|
||||
|
||||
public DGRMConfigurator(Simulation sim, GUI gui) {
|
||||
super("DGRM Configurator", gui);
|
||||
|
||||
this.gui = gui;
|
||||
|
||||
radioMedium = (DirectedGraphMedium) sim.getRadioMedium();
|
||||
|
||||
/* Listen for graph updates */
|
||||
radioMedium.addRadioMediumObserver(radioMediumObserver = new Observer() {
|
||||
public void update(Observable obs, Object obj) {
|
||||
model.fireTableDataChanged();
|
||||
}
|
||||
});
|
||||
|
||||
/* Represent directed graph by table */
|
||||
graphTable = new JTable(model) {
|
||||
public TableCellEditor getCellEditor(int row, int column) {
|
||||
if (column == IDX_RATIO) {
|
||||
combo.removeAllItems();
|
||||
combo.addItem(1.0);
|
||||
combo.addItem(0.9);
|
||||
combo.addItem(0.8);
|
||||
combo.addItem(0.7);
|
||||
combo.addItem(0.6);
|
||||
combo.addItem(0.5);
|
||||
combo.addItem(0.4);
|
||||
combo.addItem(0.3);
|
||||
combo.addItem(0.2);
|
||||
combo.addItem(0.1);
|
||||
combo.addItem(0.1);
|
||||
combo.addItem(0.0);
|
||||
}
|
||||
if (column == IDX_DELAY) {
|
||||
combo.removeAllItems();
|
||||
combo.addItem(1);
|
||||
combo.addItem(2);
|
||||
combo.addItem(3);
|
||||
combo.addItem(4);
|
||||
combo.addItem(5);
|
||||
}
|
||||
|
||||
return super.getCellEditor(row, column);
|
||||
}
|
||||
public String getToolTipText(MouseEvent e) {
|
||||
java.awt.Point p = e.getPoint();
|
||||
int row = rowAtPoint(p);
|
||||
int col = convertColumnIndexToModel(columnAtPoint(p));
|
||||
|
||||
/* TODO */
|
||||
return super.getToolTipText();
|
||||
}
|
||||
};
|
||||
combo.setEditable(true);
|
||||
graphTable.getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
|
||||
public void setValue(Object value) {
|
||||
if (!(value instanceof Double)) {
|
||||
setText(value.toString());
|
||||
return;
|
||||
}
|
||||
double v = ((Double) value).doubleValue();
|
||||
setText((Math.round(v*1000.0) / 10.0) + "%");
|
||||
}
|
||||
});
|
||||
graphTable.getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() {
|
||||
public void setValue(Object value) {
|
||||
if (!(value instanceof Long)) {
|
||||
setText(value.toString());
|
||||
return;
|
||||
}
|
||||
long v = ((Long) value).longValue();
|
||||
setText(v + " ms");
|
||||
}
|
||||
});
|
||||
graphTable.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(combo));
|
||||
graphTable.getColumnModel().getColumn(3).setCellEditor(new DefaultCellEditor(combo));
|
||||
|
||||
graphTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
|
||||
graphTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
JButton button = new JButton("Add");
|
||||
button.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
doAddLink();
|
||||
}
|
||||
});
|
||||
final JScrollPane scrollPane = new JScrollPane(graphTable);
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
add(BorderLayout.CENTER, scrollPane);
|
||||
add(BorderLayout.SOUTH, button);
|
||||
|
||||
model.fireTableDataChanged();
|
||||
}
|
||||
|
||||
private void doAddLink() {
|
||||
JComboBox source = new JComboBox();
|
||||
for (int i=0; i < gui.getSimulation().getMotesCount(); i++) {
|
||||
source.addItem(gui.getSimulation().getMote(i));
|
||||
}
|
||||
|
||||
JComboBox dest = new JComboBox();
|
||||
for (int i=0; i < gui.getSimulation().getMotesCount(); i++) {
|
||||
dest.addItem(gui.getSimulation().getMote(i));
|
||||
}
|
||||
dest.addItem("ALL");
|
||||
|
||||
JSpinner ratio = new JSpinner(new SpinnerNumberModel(1.0, 0.0, 1.0, 0.01));
|
||||
JSpinner delay = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1));
|
||||
|
||||
/* User input */
|
||||
Object description[] = {
|
||||
columns[0],
|
||||
source,
|
||||
columns[1],
|
||||
dest,
|
||||
columns[2],
|
||||
ratio,
|
||||
columns[3],
|
||||
delay
|
||||
};
|
||||
JOptionPane optionPane = new JOptionPane();
|
||||
optionPane.setMessage(description);
|
||||
optionPane.setMessageType(JOptionPane.QUESTION_MESSAGE);
|
||||
String options[] = new String[] {"Cancel", "Add"};
|
||||
optionPane.setOptions(options);
|
||||
optionPane.setInitialValue(options[1]);
|
||||
JDialog dialog = optionPane.createDialog(gui.getTopParentContainer(), title);
|
||||
dialog.setTitle("Add new link");
|
||||
dialog.setVisible(true);
|
||||
if (optionPane.getValue() == null || !optionPane.getValue().equals("Add")) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register new edge with radio medium */
|
||||
DirectedGraphMedium.Edge newEdge;
|
||||
if (dest.getSelectedItem() instanceof Mote) {
|
||||
newEdge = new DirectedGraphMedium.Edge(
|
||||
(Mote) source.getSelectedItem(),
|
||||
(Mote) dest.getSelectedItem(),
|
||||
((Number)ratio.getValue()).doubleValue(),
|
||||
((Number)delay.getValue()).longValue()
|
||||
);
|
||||
} else {
|
||||
newEdge = new DirectedGraphMedium.Edge(
|
||||
(Mote) source.getSelectedItem(),
|
||||
((Number)ratio.getValue()).doubleValue(),
|
||||
((Number)delay.getValue()).longValue()
|
||||
);
|
||||
}
|
||||
radioMedium.addEdge(newEdge);
|
||||
model.fireTableDataChanged();
|
||||
}
|
||||
|
||||
private void doRemoveLink(DirectedGraphMedium.Edge edge) {
|
||||
radioMedium.removeEdge(edge);
|
||||
model.fireTableDataChanged();
|
||||
}
|
||||
|
||||
final AbstractTableModel model = new AbstractTableModel() {
|
||||
public String getColumnName(int column) {
|
||||
if (column < 0 || column >= columns.length) {
|
||||
logger.fatal("Unknown column: " + column);
|
||||
return "";
|
||||
}
|
||||
return columns[column];
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return radioMedium.getEdges().length;
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return columns.length;
|
||||
}
|
||||
|
||||
public Object getValueAt(int row, int column) {
|
||||
if (row < 0 || row >= radioMedium.getEdges().length) {
|
||||
logger.fatal("Unknown row: " + row);
|
||||
return "";
|
||||
}
|
||||
if (column < 0 || column >= columns.length) {
|
||||
logger.fatal("Unknown column: " + column);
|
||||
return "";
|
||||
}
|
||||
|
||||
DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row];
|
||||
if (column == IDX_SRC) {
|
||||
if (edge.source == null) {
|
||||
return "?";
|
||||
}
|
||||
return edge.source;
|
||||
}
|
||||
if (column == IDX_DST) {
|
||||
if (edge.dest == null) {
|
||||
return "ALL";
|
||||
}
|
||||
return edge.dest;
|
||||
}
|
||||
if (column == IDX_RATIO) {
|
||||
return edge.successRatio;
|
||||
}
|
||||
if (column == IDX_DELAY) {
|
||||
return edge.delay;
|
||||
}
|
||||
if (column == IDX_DEL) {
|
||||
return new Boolean(false);
|
||||
}
|
||||
|
||||
logger.debug("Column data not implemented: " + column);
|
||||
return "?";
|
||||
}
|
||||
|
||||
public void setValueAt(Object value, int row, int column) {
|
||||
if (row < 0 || row >= radioMedium.getEdges().length) {
|
||||
logger.fatal("Unknown row: " + row);
|
||||
return;
|
||||
}
|
||||
if (column < 0 || column >= columns.length) {
|
||||
logger.fatal("Unknown column: " + column);
|
||||
return;
|
||||
}
|
||||
|
||||
DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row];
|
||||
if (column == IDX_RATIO) {
|
||||
/* Success ratio */
|
||||
edge.successRatio = ((Number)value).doubleValue();
|
||||
radioMedium.setEdgesDirty();
|
||||
return;
|
||||
}
|
||||
if (column == IDX_DELAY) {
|
||||
/* Propagation delay */
|
||||
edge.delay = ((Number)value).longValue();
|
||||
radioMedium.setEdgesDirty();
|
||||
return;
|
||||
}
|
||||
if (column == IDX_DEL) {
|
||||
/* Delete link */
|
||||
doRemoveLink(edge);
|
||||
return;
|
||||
}
|
||||
super.setValueAt(value, row, column);
|
||||
}
|
||||
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
if (row < 0 || row >= radioMedium.getEdges().length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Mote sourceMote = radioMedium.getEdges()[row].source;
|
||||
if (column == IDX_SRC) {
|
||||
gui.signalMoteHighlight(sourceMote);
|
||||
return false;
|
||||
}
|
||||
if (column == IDX_DST) {
|
||||
if (radioMedium.getEdges()[row].dest != null) {
|
||||
gui.signalMoteHighlight(radioMedium.getEdges()[row].dest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (column == IDX_RATIO) {
|
||||
return true;
|
||||
}
|
||||
if (column == IDX_DELAY) {
|
||||
return true;
|
||||
}
|
||||
if (column == IDX_DEL) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Class getColumnClass(int c) {
|
||||
return getValueAt(0, c).getClass();
|
||||
}
|
||||
};
|
||||
|
||||
public void closePlugin() {
|
||||
radioMedium.deleteRadioMediumObserver(radioMediumObserver);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: DirectedGraphMedium.java,v 1.1 2009/02/24 15:29:52 fros4943 Exp $
|
||||
*/
|
||||
|
||||
package se.sics.cooja.radiomediums;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jdom.Element;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.cooja.*;
|
||||
import se.sics.cooja.interfaces.*;
|
||||
import se.sics.cooja.plugins.DGRMConfigurator;
|
||||
|
||||
/**
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
@ClassDescription("Directed Graph Radio Medium (DGRM)")
|
||||
public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||
private static Logger logger = Logger.getLogger(DirectedGraphMedium.class);
|
||||
|
||||
/* Signal strengths in dBm.
|
||||
* Approx. values measured on TmoteSky */
|
||||
public static final double SS_NOTHING = -100;
|
||||
public static final double SS_STRONG = -10;
|
||||
public static final double SS_WEAK = -95;
|
||||
|
||||
private Simulation simulation;
|
||||
private boolean edgesDirty = false;
|
||||
private Random random = null;
|
||||
|
||||
private DirectedGraphMedium.Edge edges[] = new DirectedGraphMedium.Edge[0];
|
||||
|
||||
public DirectedGraphMedium(Simulation simulation) {
|
||||
super(simulation);
|
||||
random = simulation.getRandomGenerator();
|
||||
|
||||
setEdgesDirty();
|
||||
|
||||
/* Register visualizer plugin */
|
||||
simulation.getGUI().registerTemporaryPlugin(DGRMConfigurator.class);
|
||||
|
||||
this.simulation = simulation;
|
||||
}
|
||||
|
||||
public void addEdge(Edge e) {
|
||||
DirectedGraphMedium.Edge newEdges[] = new DirectedGraphMedium.Edge[edges.length+1];
|
||||
System.arraycopy(edges, 0, newEdges, 0, edges.length);
|
||||
|
||||
newEdges[newEdges.length-1] = e;
|
||||
edges = newEdges;
|
||||
setEdgesDirty();
|
||||
|
||||
((AbstractRadioMedium.RadioMediumObservable)
|
||||
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||
}
|
||||
|
||||
public void removeEdge(Edge edge) {
|
||||
ArrayList<Edge> list = new ArrayList<Edge>();
|
||||
for (DirectedGraphMedium.Edge e: edges) {
|
||||
list.add(e);
|
||||
}
|
||||
if (!list.contains(edge)) {
|
||||
logger.fatal("Cannot remove edge: " + edge);
|
||||
return;
|
||||
}
|
||||
list.remove(edge);
|
||||
DirectedGraphMedium.Edge newEdges[] = new DirectedGraphMedium.Edge[list.size()];
|
||||
list.toArray(newEdges);
|
||||
edges = newEdges;
|
||||
setEdgesDirty();
|
||||
|
||||
((AbstractRadioMedium.RadioMediumObservable)
|
||||
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||
}
|
||||
|
||||
public void setEdgesDirty() {
|
||||
edgesDirty = true;
|
||||
}
|
||||
|
||||
public Edge[] getEdges() {
|
||||
return edges;
|
||||
}
|
||||
|
||||
public void registerMote(Mote mote, Simulation sim) {
|
||||
super.registerMote(mote, sim);
|
||||
|
||||
for (Edge edge: edges) {
|
||||
if (edge.delayedLoadConfig != null) {
|
||||
boolean ok = edge.setConfigXML(edge.delayedLoadConfig, sim);
|
||||
if (ok) {
|
||||
edge.delayedLoadConfig = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setEdgesDirty();
|
||||
}
|
||||
|
||||
public void unregisterMote(Mote mote, Simulation sim) {
|
||||
super.unregisterMote(mote, sim);
|
||||
|
||||
for (Edge edge: edges) {
|
||||
if (edge.source == mote || edge.dest == mote) {
|
||||
removeEdge(edge);
|
||||
}
|
||||
}
|
||||
|
||||
setEdgesDirty();
|
||||
}
|
||||
|
||||
private class DestinationRadio {
|
||||
Radio radio;
|
||||
double ratio;
|
||||
long delay;
|
||||
|
||||
public DestinationRadio(Radio dest, double ratio, long delay) {
|
||||
this.radio = dest;
|
||||
|
||||
this.ratio = ratio;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return radio.getMote().toString();
|
||||
}
|
||||
}
|
||||
|
||||
/* Used for optimizing lookup time */
|
||||
private Hashtable<Radio,DestinationRadio[]> edgesTable = new Hashtable<Radio,DestinationRadio[]>();
|
||||
|
||||
private void analyzeEdges() {
|
||||
Hashtable<Radio,ArrayList<DestinationRadio>> newTable =
|
||||
new Hashtable<Radio,ArrayList<DestinationRadio>>();
|
||||
|
||||
/* Fill edge hash table with all edges */
|
||||
for (Edge edge: edges) {
|
||||
if (edge.source == null) {
|
||||
return; /* Still dirty, wait until all edges are loaded */
|
||||
}
|
||||
|
||||
ArrayList<DestinationRadio> destRadios;
|
||||
if (!newTable.containsKey(edge.source.getInterfaces().getRadio())) {
|
||||
/* Create new source */
|
||||
destRadios = new ArrayList<DestinationRadio>();
|
||||
} else {
|
||||
/* Extend source radio with another destination */
|
||||
destRadios = newTable.get(edge.source.getInterfaces().getRadio());
|
||||
}
|
||||
|
||||
DestinationRadio destRadio;
|
||||
if (edge.dest == null) {
|
||||
/* All radios */
|
||||
Vector<Radio> allRadios = getRegisteredRadios();
|
||||
for (Radio r: allRadios) {
|
||||
destRadio = new DestinationRadio(r, edge.successRatio, edge.delay);
|
||||
destRadios.add(destRadio);
|
||||
}
|
||||
} else {
|
||||
destRadio = new DestinationRadio(edge.dest.getInterfaces().getRadio(), edge.successRatio, edge.delay);
|
||||
destRadios.add(destRadio);
|
||||
}
|
||||
|
||||
newTable.put(edge.source.getInterfaces().getRadio(), destRadios);
|
||||
}
|
||||
|
||||
/* Convert to arrays */
|
||||
Hashtable<Radio,DestinationRadio[]> newTable2 = new Hashtable<Radio,DestinationRadio[]>();
|
||||
Enumeration<Radio> sources = newTable.keys();
|
||||
while (sources.hasMoreElements()) {
|
||||
Radio source = sources.nextElement();
|
||||
ArrayList<DestinationRadio> list = newTable.get(source);
|
||||
DestinationRadio[] arr = new DestinationRadio[list.size()];
|
||||
list.toArray(arr);
|
||||
newTable2.put(source, arr);
|
||||
}
|
||||
|
||||
this.edgesTable = newTable2;
|
||||
edgesDirty = false;
|
||||
}
|
||||
|
||||
public RadioConnection createConnections(Radio source) {
|
||||
if (edgesDirty) {
|
||||
analyzeEdges();
|
||||
}
|
||||
|
||||
/* Create new radio connection using edge hash table */
|
||||
DestinationRadio[] destinations = edgesTable.get(source);
|
||||
if (destinations == null || destinations.length == 0) {
|
||||
/* No destinations */
|
||||
/*logger.info(sendingRadio + ": No dest");*/
|
||||
return new RadioConnection(source);
|
||||
}
|
||||
|
||||
logger.info(source + ": " + destinations.length + " potential destinations");
|
||||
RadioConnection newConn = new RadioConnection(source);
|
||||
for (DestinationRadio dest: destinations) {
|
||||
if (dest.radio == source) {
|
||||
/* Fail: cannot receive our own transmission */
|
||||
logger.info(source + ": Fail, receiver is sender");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dest.ratio < 1.0 && random.nextDouble() > dest.ratio) {
|
||||
logger.info(source + ": Fail, randomly");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dest.radio.isReceiving()) {
|
||||
/* Fail: radio is already actively receiving */
|
||||
logger.info(source + ": Fail, receiving");
|
||||
newConn.addInterfered(dest.radio);
|
||||
|
||||
/* We will also interfere with the other connection */
|
||||
dest.radio.interfereAnyReception();
|
||||
RadioConnection otherConnection = null;
|
||||
for (RadioConnection conn : getActiveConnections()) {
|
||||
for (Radio dstRadio : conn.getDestinations()) {
|
||||
if (dstRadio == dest.radio) {
|
||||
otherConnection = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (otherConnection != null) {
|
||||
otherConnection.removeDestination(dest.radio);
|
||||
otherConnection.addInterfered(dest.radio);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dest.radio.isInterfered()) {
|
||||
/* Fail: radio is interfered in another connection */
|
||||
logger.info(source + ": Fail, interfered");
|
||||
newConn.addInterfered(dest.radio);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Success: radio starts receiving */
|
||||
logger.info(source + ": OK: " + dest.radio);
|
||||
newConn.addDestination(dest.radio, dest.delay);
|
||||
}
|
||||
|
||||
return newConn;
|
||||
}
|
||||
|
||||
public void updateSignalStrengths() {
|
||||
if (edgesDirty) {
|
||||
analyzeEdges();
|
||||
}
|
||||
|
||||
for (Radio radio : getRegisteredRadios()) {
|
||||
radio.setCurrentSignalStrength(SS_NOTHING);
|
||||
}
|
||||
|
||||
for (RadioConnection conn : getActiveConnections()) {
|
||||
conn.getSource().setCurrentSignalStrength(SS_STRONG);
|
||||
for (Radio dstRadio : conn.getDestinations()) {
|
||||
dstRadio.setCurrentSignalStrength(SS_STRONG);
|
||||
}
|
||||
}
|
||||
|
||||
for (RadioConnection conn : getActiveConnections()) {
|
||||
for (Radio intfRadio : conn.getInterfered()) {
|
||||
intfRadio.setCurrentSignalStrength(SS_WEAK);
|
||||
if (!intfRadio.isInterfered()) {
|
||||
intfRadio.interfereAnyReception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Collection<Element> getConfigXML() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
Element element;
|
||||
|
||||
for (Edge edge: edges) {
|
||||
element = new Element("edge");
|
||||
element.addContent(edge.getConfigXML());
|
||||
config.add(element);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public boolean setConfigXML(final Collection<Element> configXML, boolean visAvailable) {
|
||||
random = simulation.getRandomGenerator();
|
||||
|
||||
for (Element element : configXML) {
|
||||
if (element.getName().equals("edge")) {
|
||||
Edge edge = new Edge(null, null, 0, 0);
|
||||
edge.delayedLoadConfig = element.getChildren();
|
||||
addEdge(edge);
|
||||
}
|
||||
}
|
||||
|
||||
setEdgesDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Edge {
|
||||
public Mote source = null;
|
||||
public Mote dest = null; /* null: all motes*/
|
||||
public double successRatio = 1.0; /* Link success ratio (per packet). */
|
||||
public long delay = 0; /* Propagation delay (milliseconds). */
|
||||
|
||||
public Edge(Mote source, double ratio, long delay) {
|
||||
this.source = source;
|
||||
this.successRatio = ratio;
|
||||
this.delay = delay;
|
||||
|
||||
this.dest = null;
|
||||
}
|
||||
|
||||
public Edge(Mote source, Mote dest, double ratio, long delay) {
|
||||
this.source = source;
|
||||
this.successRatio = ratio;
|
||||
this.delay = delay;
|
||||
|
||||
this.dest = dest;
|
||||
}
|
||||
|
||||
public Collection<Element> delayedLoadConfig = null; /* Used for restoring edges from config */
|
||||
public Collection<Element> getConfigXML() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
Element element;
|
||||
|
||||
element = new Element("src");
|
||||
element.setText(source.toString());
|
||||
config.add(element);
|
||||
|
||||
element = new Element("dest");
|
||||
if (dest == null) {
|
||||
element.setText("ALL");
|
||||
} else {
|
||||
element.setText(dest.toString());
|
||||
}
|
||||
config.add(element);
|
||||
|
||||
element = new Element("ratio");
|
||||
element.setText("" + successRatio);
|
||||
config.add(element);
|
||||
|
||||
element = new Element("delay");
|
||||
element.setText("" + delay);
|
||||
config.add(element);
|
||||
|
||||
return config;
|
||||
}
|
||||
public boolean setConfigXML(Collection<Element> configXML, Simulation simulation) {
|
||||
for (Element element : configXML) {
|
||||
if (element.getName().equals("src")) {
|
||||
String moteDescription = element.getText();
|
||||
|
||||
boolean foundMote = false;
|
||||
for (int i=0; i < simulation.getMotesCount(); i++) {
|
||||
if (moteDescription.equals(simulation.getMote(i).toString())) {
|
||||
foundMote = true;
|
||||
source = simulation.getMote(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMote) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.getName().equals("dest")) {
|
||||
String moteDescription = element.getText();
|
||||
|
||||
if (moteDescription.equals("ALL")) {
|
||||
dest = null; /* ALL */
|
||||
} else {
|
||||
boolean foundMote = false;
|
||||
for (int i=0; i < simulation.getMotesCount(); i++) {
|
||||
if (moteDescription.equals(simulation.getMote(i).toString())) {
|
||||
foundMote = true;
|
||||
dest = simulation.getMote(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundMote) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element.getName().equals("ratio")) {
|
||||
successRatio = Double.parseDouble(element.getText());
|
||||
}
|
||||
|
||||
if (element.getName().equals("delay")) {
|
||||
delay = Long.parseLong(element.getText());
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue