radio medium patch: udgm uses hash table for efficient lookup in large networks + minor patches to dgrm
This commit is contained in:
parent
59e1c464e7
commit
a81f216acb
|
@ -1,3 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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: DGRMConfigurator.java,v 1.3 2009/10/27 10:10:03 fros4943 Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
package se.sics.cooja.plugins;
|
package se.sics.cooja.plugins;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
|
@ -6,6 +37,7 @@ import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
|
||||||
import javax.swing.DefaultCellEditor;
|
import javax.swing.DefaultCellEditor;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
@ -29,8 +61,13 @@ import se.sics.cooja.PluginType;
|
||||||
import se.sics.cooja.Simulation;
|
import se.sics.cooja.Simulation;
|
||||||
import se.sics.cooja.VisPlugin;
|
import se.sics.cooja.VisPlugin;
|
||||||
import se.sics.cooja.radiomediums.DirectedGraphMedium;
|
import se.sics.cooja.radiomediums.DirectedGraphMedium;
|
||||||
|
import se.sics.cooja.radiomediums.DirectedGraphMedium.DGRMDestinationRadio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Simple user interface for configuring edges for the Directed Graph
|
||||||
|
* Radio Medium (DGRM).
|
||||||
|
*
|
||||||
|
* @see DirectedGraphMedium
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
*/
|
*/
|
||||||
@ClassDescription("DGRM Configurator")
|
@ClassDescription("DGRM Configurator")
|
||||||
|
@ -82,11 +119,11 @@ public class DGRMConfigurator extends VisPlugin {
|
||||||
combo.addItem(0.3);
|
combo.addItem(0.3);
|
||||||
combo.addItem(0.2);
|
combo.addItem(0.2);
|
||||||
combo.addItem(0.1);
|
combo.addItem(0.1);
|
||||||
combo.addItem(0.1);
|
|
||||||
combo.addItem(0.0);
|
combo.addItem(0.0);
|
||||||
}
|
}
|
||||||
if (column == IDX_DELAY) {
|
if (column == IDX_DELAY) {
|
||||||
combo.removeAllItems();
|
combo.removeAllItems();
|
||||||
|
combo.addItem(0);
|
||||||
combo.addItem(1);
|
combo.addItem(1);
|
||||||
combo.addItem(2);
|
combo.addItem(2);
|
||||||
combo.addItem(3);
|
combo.addItem(3);
|
||||||
|
@ -190,16 +227,21 @@ public class DGRMConfigurator extends VisPlugin {
|
||||||
DirectedGraphMedium.Edge newEdge;
|
DirectedGraphMedium.Edge newEdge;
|
||||||
if (dest.getSelectedItem() instanceof Mote) {
|
if (dest.getSelectedItem() instanceof Mote) {
|
||||||
newEdge = new DirectedGraphMedium.Edge(
|
newEdge = new DirectedGraphMedium.Edge(
|
||||||
(Mote) source.getSelectedItem(),
|
((Mote) source.getSelectedItem()).getInterfaces().getRadio(),
|
||||||
(Mote) dest.getSelectedItem(),
|
new DGRMDestinationRadio(
|
||||||
((Number)ratio.getValue()).doubleValue(),
|
((Mote) dest.getSelectedItem()).getInterfaces().getRadio(),
|
||||||
((Number)delay.getValue()).longValue()
|
((Number)ratio.getValue()).doubleValue(),
|
||||||
|
((Number)delay.getValue()).longValue()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
newEdge = new DirectedGraphMedium.Edge(
|
newEdge = new DirectedGraphMedium.Edge(
|
||||||
(Mote) source.getSelectedItem(),
|
((Mote) source.getSelectedItem()).getInterfaces().getRadio(),
|
||||||
((Number)ratio.getValue()).doubleValue(),
|
new DGRMDestinationRadio(
|
||||||
((Number)delay.getValue()).longValue()
|
null,
|
||||||
|
((Number)ratio.getValue()).doubleValue(),
|
||||||
|
((Number)delay.getValue()).longValue()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
radioMedium.addEdge(newEdge);
|
radioMedium.addEdge(newEdge);
|
||||||
|
@ -243,19 +285,19 @@ public class DGRMConfigurator extends VisPlugin {
|
||||||
if (edge.source == null) {
|
if (edge.source == null) {
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
return edge.source;
|
return edge.source.getMote();
|
||||||
}
|
}
|
||||||
if (column == IDX_DST) {
|
if (column == IDX_DST) {
|
||||||
if (edge.dest == null) {
|
if (edge.superDest.toAll) {
|
||||||
return "ALL";
|
return "ALL";
|
||||||
}
|
}
|
||||||
return edge.dest;
|
return edge.superDest.radio.getMote();
|
||||||
}
|
}
|
||||||
if (column == IDX_RATIO) {
|
if (column == IDX_RATIO) {
|
||||||
return edge.successRatio;
|
return ((DGRMDestinationRadio)edge.superDest).ratio;
|
||||||
}
|
}
|
||||||
if (column == IDX_DELAY) {
|
if (column == IDX_DELAY) {
|
||||||
return edge.delay / Simulation.MILLISECOND;
|
return ((DGRMDestinationRadio)edge.superDest).delay / Simulation.MILLISECOND;
|
||||||
}
|
}
|
||||||
if (column == IDX_DEL) {
|
if (column == IDX_DEL) {
|
||||||
return new Boolean(false);
|
return new Boolean(false);
|
||||||
|
@ -278,14 +320,16 @@ public class DGRMConfigurator extends VisPlugin {
|
||||||
DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row];
|
DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row];
|
||||||
if (column == IDX_RATIO) {
|
if (column == IDX_RATIO) {
|
||||||
/* Success ratio */
|
/* Success ratio */
|
||||||
edge.successRatio = ((Number)value).doubleValue();
|
((DGRMDestinationRadio)edge.superDest).ratio =
|
||||||
radioMedium.setEdgesDirty();
|
((Number)value).doubleValue();
|
||||||
|
radioMedium.requestEdgeAnalysis();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (column == IDX_DELAY) {
|
if (column == IDX_DELAY) {
|
||||||
/* Propagation delay (ms) */
|
/* Propagation delay (ms) */
|
||||||
edge.delay = ((Number)value).longValue() * Simulation.MILLISECOND;
|
((DGRMDestinationRadio)edge.superDest).delay =
|
||||||
radioMedium.setEdgesDirty();
|
((Number)value).longValue() * Simulation.MILLISECOND;
|
||||||
|
radioMedium.requestEdgeAnalysis();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (column == IDX_DEL) {
|
if (column == IDX_DEL) {
|
||||||
|
@ -301,14 +345,14 @@ public class DGRMConfigurator extends VisPlugin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mote sourceMote = radioMedium.getEdges()[row].source;
|
Mote sourceMote = radioMedium.getEdges()[row].source.getMote();
|
||||||
if (column == IDX_SRC) {
|
if (column == IDX_SRC) {
|
||||||
gui.signalMoteHighlight(sourceMote);
|
gui.signalMoteHighlight(sourceMote);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (column == IDX_DST) {
|
if (column == IDX_DST) {
|
||||||
if (radioMedium.getEdges()[row].dest != null) {
|
if (!radioMedium.getEdges()[row].superDest.toAll) {
|
||||||
gui.signalMoteHighlight(radioMedium.getEdges()[row].dest);
|
gui.signalMoteHighlight(radioMedium.getEdges()[row].superDest.radio.getMote());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,21 +26,36 @@
|
||||||
* 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: AbstractRadioMedium.java,v 1.10 2009/05/26 14:17:29 fros4943 Exp $
|
* $Id: AbstractRadioMedium.java,v 1.11 2009/10/27 10:10:03 fros4943 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package se.sics.cooja.radiomediums;
|
package se.sics.cooja.radiomediums;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
import se.sics.cooja.Mote;
|
||||||
import se.sics.cooja.interfaces.*;
|
import se.sics.cooja.RadioConnection;
|
||||||
|
import se.sics.cooja.RadioMedium;
|
||||||
|
import se.sics.cooja.RadioPacket;
|
||||||
|
import se.sics.cooja.Simulation;
|
||||||
|
import se.sics.cooja.TimeEvent;
|
||||||
|
import se.sics.cooja.interfaces.CustomDataRadio;
|
||||||
|
import se.sics.cooja.interfaces.Radio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract radio medium provides basic functionality for implementing radio
|
* Abstract radio medium provides basic functionality for implementing radio
|
||||||
* mediums.
|
* mediums.
|
||||||
*
|
*
|
||||||
|
* The radio medium forwards both radio packets and custom data objects.
|
||||||
|
*
|
||||||
|
* The registered radios' signal strengths are updated whenever the radio medium
|
||||||
|
* changes. There are three fixed levels: no surrounding traffic heard, noise
|
||||||
|
* heard and data heard.
|
||||||
|
*
|
||||||
* It handles radio registrations, radio loggers, active connections and
|
* It handles radio registrations, radio loggers, active connections and
|
||||||
* observes all registered radio interfaces.
|
* observes all registered radio interfaces.
|
||||||
*
|
*
|
||||||
|
@ -49,12 +64,18 @@ import se.sics.cooja.interfaces.*;
|
||||||
public abstract class AbstractRadioMedium extends RadioMedium {
|
public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
private static Logger logger = Logger.getLogger(AbstractRadioMedium.class);
|
private static Logger logger = Logger.getLogger(AbstractRadioMedium.class);
|
||||||
|
|
||||||
private Vector<Radio> registeredRadios = new Vector<Radio>();
|
/* 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 Vector<RadioConnection> activeConnections = new Vector<RadioConnection>();
|
private ArrayList<Radio> registeredRadios = new ArrayList<Radio>();
|
||||||
|
|
||||||
|
private ArrayList<RadioConnection> activeConnections = new ArrayList<RadioConnection>();
|
||||||
|
|
||||||
private RadioConnection lastConnection = null;
|
private RadioConnection lastConnection = null;
|
||||||
|
|
||||||
private Simulation simulation = null;
|
private Simulation simulation = null;
|
||||||
|
|
||||||
/* Book-keeping */
|
/* Book-keeping */
|
||||||
|
@ -74,8 +95,6 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
|
|
||||||
private RadioMediumObservable radioMediumObservable = new RadioMediumObservable();
|
private RadioMediumObservable radioMediumObservable = new RadioMediumObservable();
|
||||||
|
|
||||||
private RadioConnection[] lastTickConnections = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor should always be called from implemented radio mediums.
|
* This constructor should always be called from implemented radio mediums.
|
||||||
*
|
*
|
||||||
|
@ -88,8 +107,8 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
/**
|
/**
|
||||||
* @return All registered radios
|
* @return All registered radios
|
||||||
*/
|
*/
|
||||||
public Vector<Radio> getRegisteredRadios() {
|
public Radio[] getRegisteredRadios() {
|
||||||
return registeredRadios;
|
return registeredRadios.toArray(new Radio[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,7 +134,35 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
* Updates all radio interfaces' signal strengths according to
|
* Updates all radio interfaces' signal strengths according to
|
||||||
* the current active connections.
|
* the current active connections.
|
||||||
*/
|
*/
|
||||||
abstract public void updateSignalStrengths();
|
public void updateSignalStrengths() {
|
||||||
|
|
||||||
|
/* Reset signal strengths */
|
||||||
|
for (Radio radio : getRegisteredRadios()) {
|
||||||
|
radio.setCurrentSignalStrength(SS_NOTHING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set signal strength to strong on destinations */
|
||||||
|
RadioConnection[] conns = getActiveConnections();
|
||||||
|
for (RadioConnection conn : conns) {
|
||||||
|
conn.getSource().setCurrentSignalStrength(SS_STRONG);
|
||||||
|
for (Radio dstRadio : conn.getDestinations()) {
|
||||||
|
dstRadio.setCurrentSignalStrength(SS_STRONG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set signal strength to weak on interfered */
|
||||||
|
for (RadioConnection conn : conns) {
|
||||||
|
for (Radio intfRadio : conn.getInterfered()) {
|
||||||
|
intfRadio.setCurrentSignalStrength(SS_WEAK);
|
||||||
|
|
||||||
|
if (!intfRadio.isInterfered()) {
|
||||||
|
logger.warn("Radio was not interfered");
|
||||||
|
intfRadio.interfereAnyReception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove given radio from any active connections.
|
* Remove given radio from any active connections.
|
||||||
|
@ -124,33 +171,39 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
* @param radio Radio
|
* @param radio Radio
|
||||||
*/
|
*/
|
||||||
private void removeFromActiveConnections(Radio radio) {
|
private void removeFromActiveConnections(Radio radio) {
|
||||||
// Abort any reception
|
/* Abort ongoing receptions */
|
||||||
if (radio.isReceiving()) {
|
if (radio.isReceiving()) {
|
||||||
radio.interfereAnyReception();
|
radio.interfereAnyReception();
|
||||||
radio.signalReceptionEnd();
|
radio.signalReceptionEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove radio from all active connections
|
/* Connection source */
|
||||||
RadioConnection connToRemove = null;
|
RadioConnection connection = getActiveConnectionFrom(radio);
|
||||||
|
if (connection != null) {
|
||||||
|
for (Radio dstRadio : connection.getDestinations()) {
|
||||||
|
dstRadio.interfereAnyReception();
|
||||||
|
dstRadio.signalReceptionEnd();
|
||||||
|
}
|
||||||
|
for (Radio dstRadio : connection.getInterfered()) {
|
||||||
|
dstRadio.signalReceptionEnd();
|
||||||
|
}
|
||||||
|
activeConnections.remove(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connection destination and interfered */
|
||||||
for (RadioConnection conn : activeConnections) {
|
for (RadioConnection conn : activeConnections) {
|
||||||
conn.removeDestination(radio);
|
conn.removeDestination(radio);
|
||||||
conn.removeInterfered(radio);
|
conn.removeInterfered(radio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (conn.getSource() == radio) {
|
private RadioConnection getActiveConnectionFrom(Radio source) {
|
||||||
// Radio is currently transmitting
|
for (RadioConnection conn : activeConnections) {
|
||||||
connToRemove = conn;
|
if (conn.getSource() == source) {
|
||||||
for (Radio dstRadio : conn.getDestinations()) {
|
return conn;
|
||||||
dstRadio.interfereAnyReception();
|
|
||||||
dstRadio.signalReceptionEnd();
|
|
||||||
}
|
|
||||||
for (Radio dstRadio : conn.getInterfered()) {
|
|
||||||
dstRadio.signalReceptionEnd();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (connToRemove != null) {
|
return null;
|
||||||
activeConnections.remove(connToRemove);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,34 +216,32 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
logger.fatal("Radio event dispatched by non-radio object");
|
logger.fatal("Radio event dispatched by non-radio object");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Radio radio = (Radio) obs;
|
Radio radio = (Radio) obs;
|
||||||
|
|
||||||
// Handle radio event
|
|
||||||
final Radio.RadioEvent event = radio.getLastEvent();
|
final Radio.RadioEvent event = radio.getLastEvent();
|
||||||
|
if (event == Radio.RadioEvent.RECEPTION_STARTED ||
|
||||||
// Ignore reception events
|
event == Radio.RadioEvent.RECEPTION_INTERFERED ||
|
||||||
if (event == Radio.RadioEvent.RECEPTION_STARTED
|
event == Radio.RadioEvent.RECEPTION_FINISHED ||
|
||||||
|| event == Radio.RadioEvent.RECEPTION_INTERFERED
|
event == Radio.RadioEvent.UNKNOWN) {
|
||||||
|| event == Radio.RadioEvent.RECEPTION_FINISHED) {
|
/* Ignored */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event == Radio.RadioEvent.HW_OFF) {
|
if (event == Radio.RadioEvent.HW_ON) {
|
||||||
// Destroy any(?) transfers
|
|
||||||
|
/* Update signal strengths */
|
||||||
|
updateSignalStrengths();
|
||||||
|
|
||||||
|
} else if (event == Radio.RadioEvent.HW_OFF) {
|
||||||
|
|
||||||
|
/* Remove any radio connections from this radio */
|
||||||
removeFromActiveConnections(radio);
|
removeFromActiveConnections(radio);
|
||||||
|
|
||||||
// Recalculate signal strengths on all radios
|
/* Update signal strengths */
|
||||||
updateSignalStrengths();
|
|
||||||
} else if (event == Radio.RadioEvent.HW_ON) {
|
|
||||||
// No action
|
|
||||||
// TODO Maybe set signal strength levels now?
|
|
||||||
|
|
||||||
// Recalculate signal strengths on all radios
|
|
||||||
updateSignalStrengths();
|
updateSignalStrengths();
|
||||||
|
|
||||||
} else if (event == Radio.RadioEvent.TRANSMISSION_STARTED) {
|
} else if (event == Radio.RadioEvent.TRANSMISSION_STARTED) {
|
||||||
/* Create radio connections */
|
/* Create new radio connection */
|
||||||
|
|
||||||
RadioConnection newConnection = createConnections(radio);
|
RadioConnection newConnection = createConnections(radio);
|
||||||
activeConnections.add(newConnection);
|
activeConnections.add(newConnection);
|
||||||
|
@ -213,153 +264,153 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate signal strengths on all radios
|
/* Update signal strengths */
|
||||||
updateSignalStrengths();
|
updateSignalStrengths();
|
||||||
|
|
||||||
/* Notify observers */
|
/* Notify observers */
|
||||||
radioMediumObservable.setRadioMediumChanged();
|
radioMediumObservable.setRadioMediumChangedAndNotify();
|
||||||
|
|
||||||
} else if (event == Radio.RadioEvent.TRANSMISSION_FINISHED) {
|
} else if (event == Radio.RadioEvent.TRANSMISSION_FINISHED) {
|
||||||
/* Remove active connection */
|
/* Remove radio connection */
|
||||||
|
|
||||||
// Find corresponding connection of radio
|
|
||||||
RadioConnection connection = null;
|
|
||||||
for (RadioConnection conn : activeConnections) {
|
|
||||||
if (conn.getSource() == radio) {
|
|
||||||
connection = conn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Connection */
|
||||||
|
RadioConnection connection = getActiveConnectionFrom(radio);
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
logger.fatal("Can't find active connection to remove, source=" + radio);
|
logger.fatal("No radio connection found");
|
||||||
} else {
|
|
||||||
activeConnections.remove(connection);
|
|
||||||
lastConnection = connection;
|
|
||||||
COUNTER_TX++;
|
|
||||||
for (Radio dstRadio : connection.getDestinations()) {
|
|
||||||
COUNTER_RX++;
|
|
||||||
if (connection.getDestinationDelay(dstRadio) == 0) {
|
|
||||||
dstRadio.signalReceptionEnd();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* EXPERIMENTAL: Simulating propagation delay */
|
|
||||||
final Radio delayedRadio = dstRadio;
|
|
||||||
TimeEvent delayedEvent = new TimeEvent(0) {
|
|
||||||
public void execute(long t) {
|
|
||||||
delayedRadio.signalReceptionEnd();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
simulation.scheduleEvent(
|
|
||||||
delayedEvent,
|
|
||||||
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Radio dstRadio : connection.getInterfered()) {
|
|
||||||
COUNTER_INTERFERED++;
|
|
||||||
dstRadio.signalReceptionEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recalculate signal strengths on all radios
|
|
||||||
updateSignalStrengths();
|
|
||||||
|
|
||||||
/* Notify observers */
|
|
||||||
radioMediumObservable.setRadioMediumChanged();
|
|
||||||
radioMediumObservable.notifyObservers();
|
|
||||||
|
|
||||||
} else if (event == Radio.RadioEvent.CUSTOM_DATA_TRANSMITTED) {
|
|
||||||
/* Forward custom data, if any */
|
|
||||||
|
|
||||||
// Find corresponding connection of radio
|
|
||||||
RadioConnection connection = null;
|
|
||||||
for (RadioConnection conn : activeConnections) {
|
|
||||||
if (conn.getSource() == radio) {
|
|
||||||
connection = conn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (connection == null) {
|
|
||||||
logger.fatal("Can't find active connection to forward custom data in");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activeConnections.remove(connection);
|
||||||
|
lastConnection = connection;
|
||||||
|
COUNTER_TX++;
|
||||||
|
for (Radio dstRadio : connection.getDestinations()) {
|
||||||
|
COUNTER_RX++;
|
||||||
|
if (connection.getDestinationDelay(dstRadio) == 0) {
|
||||||
|
dstRadio.signalReceptionEnd();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* EXPERIMENTAL: Simulating propagation delay */
|
||||||
|
final Radio delayedRadio = dstRadio;
|
||||||
|
TimeEvent delayedEvent = new TimeEvent(0) {
|
||||||
|
public void execute(long t) {
|
||||||
|
delayedRadio.signalReceptionEnd();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
simulation.scheduleEvent(
|
||||||
|
delayedEvent,
|
||||||
|
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Radio intRadio : connection.getInterfered()) {
|
||||||
|
COUNTER_INTERFERED++;
|
||||||
|
/* Check if radio is still interfered by some other connection */
|
||||||
|
boolean stillInterfered = false;
|
||||||
|
for (RadioConnection conn : getActiveConnections()) {
|
||||||
|
for (Radio r: conn.getInterfered()) {
|
||||||
|
if (intRadio == r) {
|
||||||
|
stillInterfered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!stillInterfered) {
|
||||||
|
intRadio.signalReceptionEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update signal strengths */
|
||||||
|
updateSignalStrengths();
|
||||||
|
|
||||||
|
/* Notify observers */
|
||||||
|
radioMediumObservable.setRadioMediumChangedAndNotify();
|
||||||
|
|
||||||
|
} else if (event == Radio.RadioEvent.CUSTOM_DATA_TRANSMITTED) {
|
||||||
|
|
||||||
|
/* Connection */
|
||||||
|
RadioConnection connection = getActiveConnectionFrom(radio);
|
||||||
|
if (connection == null) {
|
||||||
|
logger.fatal("No radio connection found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom data object */
|
||||||
Object data = ((CustomDataRadio) radio).getLastCustomDataTransmitted();
|
Object data = ((CustomDataRadio) radio).getLastCustomDataTransmitted();
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
logger.fatal("Custom data object is null");
|
logger.fatal("No custom data object to forward");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Radio dstRadio : connection.getDestinations()) {
|
for (Radio dstRadio : connection.getDestinations()) {
|
||||||
if (dstRadio instanceof CustomDataRadio) {
|
|
||||||
if (connection.getDestinationDelay(dstRadio) == 0) {
|
|
||||||
((CustomDataRadio) dstRadio).receiveCustomData(data);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* EXPERIMENTAL: Simulating propagation delay */
|
if (!radio.getClass().equals(dstRadio.getClass()) ||
|
||||||
final CustomDataRadio delayedRadio = (CustomDataRadio) dstRadio;
|
!(radio instanceof CustomDataRadio)) {
|
||||||
final Object delayedData = data;
|
/* Radios communicate via radio packets */
|
||||||
TimeEvent delayedEvent = new TimeEvent(0) {
|
continue;
|
||||||
public void execute(long t) {
|
}
|
||||||
delayedRadio.receiveCustomData(delayedData);
|
|
||||||
}
|
if (connection.getDestinationDelay(dstRadio) == 0) {
|
||||||
};
|
((CustomDataRadio) dstRadio).receiveCustomData(data);
|
||||||
simulation.scheduleEvent(
|
} else {
|
||||||
delayedEvent,
|
|
||||||
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
/* EXPERIMENTAL: Simulating propagation delay */
|
||||||
|
final CustomDataRadio delayedRadio = (CustomDataRadio) dstRadio;
|
||||||
|
final Object delayedData = data;
|
||||||
|
TimeEvent delayedEvent = new TimeEvent(0) {
|
||||||
|
public void execute(long t) {
|
||||||
|
delayedRadio.receiveCustomData(delayedData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
simulation.scheduleEvent(
|
||||||
|
delayedEvent,
|
||||||
|
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (event == Radio.RadioEvent.PACKET_TRANSMITTED) {
|
} else if (event == Radio.RadioEvent.PACKET_TRANSMITTED) {
|
||||||
/* Forward packet, if any */
|
|
||||||
|
|
||||||
// Find corresponding connection of radio
|
/* Connection */
|
||||||
RadioConnection connection = null;
|
RadioConnection connection = getActiveConnectionFrom(radio);
|
||||||
for (RadioConnection conn : activeConnections) {
|
|
||||||
if (conn.getSource() == radio) {
|
|
||||||
connection = conn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
logger.fatal("Can't find active connection to forward packet in");
|
logger.fatal("No radio connection found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Radio packet */
|
||||||
RadioPacket packet = radio.getLastPacketTransmitted();
|
RadioPacket packet = radio.getLastPacketTransmitted();
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
logger.fatal("Radio packet is null");
|
logger.fatal("No radio packet to forward");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Radio srcRadio = connection.getSource();
|
|
||||||
for (Radio dstRadio : connection.getDestinations()) {
|
for (Radio dstRadio : connection.getDestinations()) {
|
||||||
if (!(srcRadio instanceof CustomDataRadio) ||
|
|
||||||
!(dstRadio instanceof CustomDataRadio)) {
|
|
||||||
if (connection.getDestinationDelay(dstRadio) == 0) {
|
|
||||||
dstRadio.setReceivedPacket(packet);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* EXPERIMENTAL: Simulating propagation delay */
|
if (radio.getClass().equals(dstRadio.getClass()) &&
|
||||||
final Radio delayedRadio = dstRadio;
|
radio instanceof CustomDataRadio) {
|
||||||
final RadioPacket delayedPacket = packet;
|
/* Radios instead communicate via custom data objects */
|
||||||
TimeEvent delayedEvent = new TimeEvent(0) {
|
continue;
|
||||||
public void execute(long t) {
|
|
||||||
delayedRadio.setReceivedPacket(delayedPacket);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
simulation.scheduleEvent(
|
|
||||||
delayedEvent,
|
|
||||||
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward radio packet */
|
||||||
|
if (connection.getDestinationDelay(dstRadio) == 0) {
|
||||||
|
dstRadio.setReceivedPacket(packet);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* EXPERIMENTAL: Simulating propagation delay */
|
||||||
|
final Radio delayedRadio = dstRadio;
|
||||||
|
final RadioPacket delayedPacket = packet;
|
||||||
|
TimeEvent delayedEvent = new TimeEvent(0) {
|
||||||
|
public void execute(long t) {
|
||||||
|
delayedRadio.setReceivedPacket(delayedPacket);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
simulation.scheduleEvent(
|
||||||
|
delayedEvent,
|
||||||
|
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (event == Radio.RadioEvent.UNKNOWN) {
|
|
||||||
// Do nothing
|
|
||||||
} else {
|
} else {
|
||||||
logger.fatal("Unsupported radio event: " + event);
|
logger.fatal("Unsupported radio event: " + event);
|
||||||
}
|
}
|
||||||
|
@ -375,19 +426,21 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerRadioInterface(Radio radio, Simulation sim) {
|
public void registerRadioInterface(Radio radio, Simulation sim) {
|
||||||
if (radio != null) {
|
if (radio == null) {
|
||||||
// Register and start observing radio
|
logger.warn("No radio to register");
|
||||||
registeredRadios.add(radio);
|
return;
|
||||||
radio.addObserver(radioEventsObserver);
|
|
||||||
|
|
||||||
// Set initial signal strength
|
|
||||||
updateSignalStrengths();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registeredRadios.add(radio);
|
||||||
|
radio.addObserver(radioEventsObserver);
|
||||||
|
|
||||||
|
/* Update signal strengths */
|
||||||
|
updateSignalStrengths();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterRadioInterface(Radio radio, Simulation sim) {
|
public void unregisterRadioInterface(Radio radio, Simulation sim) {
|
||||||
if (!registeredRadios.contains(radio)) {
|
if (!registeredRadios.contains(radio)) {
|
||||||
logger.warn("Could not find radio: " + radio + " to unregister");
|
logger.warn("No radio to unregister: " + radio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,6 +448,9 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
registeredRadios.remove(radio);
|
registeredRadios.remove(radio);
|
||||||
|
|
||||||
removeFromActiveConnections(radio);
|
removeFromActiveConnections(radio);
|
||||||
|
|
||||||
|
/* Update signal strengths */
|
||||||
|
updateSignalStrengths();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRadioMediumObserver(Observer observer) {
|
public void addRadioMediumObserver(Observer observer) {
|
||||||
|
|
|
@ -26,92 +26,116 @@
|
||||||
* 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: DirectedGraphMedium.java,v 1.2 2009/06/08 12:42:10 fros4943 Exp $
|
* $Id: DirectedGraphMedium.java,v 1.3 2009/10/27 10:10:03 fros4943 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package se.sics.cooja.radiomediums;
|
package se.sics.cooja.radiomediums;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import org.jdom.Element;
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
import se.sics.cooja.ClassDescription;
|
||||||
import se.sics.cooja.interfaces.*;
|
import se.sics.cooja.Mote;
|
||||||
|
import se.sics.cooja.RadioConnection;
|
||||||
|
import se.sics.cooja.Simulation;
|
||||||
|
import se.sics.cooja.interfaces.Radio;
|
||||||
import se.sics.cooja.plugins.DGRMConfigurator;
|
import se.sics.cooja.plugins.DGRMConfigurator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Directed Graph Radio Medium.
|
||||||
|
*
|
||||||
|
* Can be used both stand-alone as a radio medium, and
|
||||||
|
* as a basis for other radio medium implementations.
|
||||||
|
*
|
||||||
|
* The stand-alone radio medium supports propagation delays and
|
||||||
|
* and single-value per-link transmission success ratio.
|
||||||
|
*
|
||||||
|
* @see UDGM
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
*/
|
*/
|
||||||
@ClassDescription("Directed Graph Radio Medium (DGRM)")
|
@ClassDescription("Directed Graph Radio Medium (DGRM)")
|
||||||
public class DirectedGraphMedium extends AbstractRadioMedium {
|
public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
private static Logger logger = Logger.getLogger(DirectedGraphMedium.class);
|
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 Simulation simulation;
|
||||||
private boolean edgesDirty = false;
|
private Random random;
|
||||||
private Random random = null;
|
|
||||||
|
|
||||||
private DirectedGraphMedium.Edge edges[] = new DirectedGraphMedium.Edge[0];
|
private ArrayList<Edge> edges = new ArrayList<Edge>();
|
||||||
|
private boolean edgesDirty = true;
|
||||||
|
|
||||||
|
/* Used for optimizing lookup time */
|
||||||
|
private Hashtable<Radio,DestinationRadio[]> edgesTable = new Hashtable<Radio,DestinationRadio[]>();
|
||||||
|
|
||||||
|
public DirectedGraphMedium() {
|
||||||
|
/* Do not initialize radio medium: use only for hash table */
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
public DirectedGraphMedium(Simulation simulation) {
|
public DirectedGraphMedium(Simulation simulation) {
|
||||||
super(simulation);
|
super(simulation);
|
||||||
|
this.simulation = simulation;
|
||||||
random = simulation.getRandomGenerator();
|
random = simulation.getRandomGenerator();
|
||||||
|
|
||||||
setEdgesDirty();
|
requestEdgeAnalysis();
|
||||||
|
|
||||||
/* Register visualizer plugin */
|
/* Register plugin.
|
||||||
|
* TODO Should be unregistered when radio medium is removed */
|
||||||
simulation.getGUI().registerTemporaryPlugin(DGRMConfigurator.class);
|
simulation.getGUI().registerTemporaryPlugin(DGRMConfigurator.class);
|
||||||
|
|
||||||
this.simulation = simulation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEdge(Edge e) {
|
public void addEdge(Edge e) {
|
||||||
DirectedGraphMedium.Edge newEdges[] = new DirectedGraphMedium.Edge[edges.length+1];
|
edges.add(e);
|
||||||
System.arraycopy(edges, 0, newEdges, 0, edges.length);
|
requestEdgeAnalysis();
|
||||||
|
|
||||||
newEdges[newEdges.length-1] = e;
|
|
||||||
edges = newEdges;
|
|
||||||
setEdgesDirty();
|
|
||||||
|
|
||||||
((AbstractRadioMedium.RadioMediumObservable)
|
((AbstractRadioMedium.RadioMediumObservable)
|
||||||
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEdge(Edge edge) {
|
public void removeEdge(Edge edge) {
|
||||||
ArrayList<Edge> list = new ArrayList<Edge>();
|
if (!edges.contains(edge)) {
|
||||||
for (DirectedGraphMedium.Edge e: edges) {
|
|
||||||
list.add(e);
|
|
||||||
}
|
|
||||||
if (!list.contains(edge)) {
|
|
||||||
logger.fatal("Cannot remove edge: " + edge);
|
logger.fatal("Cannot remove edge: " + edge);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
list.remove(edge);
|
edges.remove(edge);
|
||||||
DirectedGraphMedium.Edge newEdges[] = new DirectedGraphMedium.Edge[list.size()];
|
requestEdgeAnalysis();
|
||||||
list.toArray(newEdges);
|
|
||||||
edges = newEdges;
|
|
||||||
setEdgesDirty();
|
|
||||||
|
|
||||||
((AbstractRadioMedium.RadioMediumObservable)
|
((AbstractRadioMedium.RadioMediumObservable)
|
||||||
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEdgesDirty() {
|
public void clearEdges() {
|
||||||
edgesDirty = true;
|
edges.clear();
|
||||||
|
requestEdgeAnalysis();
|
||||||
|
|
||||||
|
((AbstractRadioMedium.RadioMediumObservable)
|
||||||
|
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Edge[] getEdges() {
|
public Edge[] getEdges() {
|
||||||
return edges;
|
return edges.toArray(new Edge[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerMote(Mote mote, Simulation sim) {
|
/**
|
||||||
super.registerMote(mote, sim);
|
* Signal that the configuration changed, and needs to be re-analyzed
|
||||||
|
* before used.
|
||||||
|
*/
|
||||||
|
public void requestEdgeAnalysis() {
|
||||||
|
edgesDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean needsEdgeAnalysis() {
|
||||||
|
return edgesDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerRadioInterface(Radio radio, Simulation sim) {
|
||||||
|
super.registerRadioInterface(radio, sim);
|
||||||
|
|
||||||
for (Edge edge: edges) {
|
for (Edge edge: edges) {
|
||||||
if (edge.delayedLoadConfig == null) {
|
if (edge.delayedLoadConfig == null) {
|
||||||
|
@ -124,107 +148,148 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setEdgesDirty();
|
requestEdgeAnalysis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterMote(Mote mote, Simulation sim) {
|
public void unregisterRadioInterface(Radio radio, Simulation sim) {
|
||||||
super.unregisterMote(mote, sim);
|
super.unregisterRadioInterface(radio, sim);
|
||||||
|
|
||||||
for (Edge edge: edges) {
|
if (radio == null) {
|
||||||
if (edge.source == mote || edge.dest == mote) {
|
return;
|
||||||
|
}
|
||||||
|
for (Edge edge: getEdges()) {
|
||||||
|
if (edge.source == radio || edge.superDest.radio == radio) {
|
||||||
removeEdge(edge);
|
removeEdge(edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setEdgesDirty();
|
requestEdgeAnalysis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DestinationRadio {
|
public static class DestinationRadio {
|
||||||
Radio radio;
|
public Radio radio; /* destination radio */
|
||||||
double ratio;
|
public boolean toAll; /* to all destinations */
|
||||||
long delay; /* us */
|
|
||||||
|
|
||||||
public DestinationRadio(Radio dest, double ratio, long delay) {
|
public DestinationRadio(Radio dest) {
|
||||||
this.radio = dest;
|
this.radio = dest;
|
||||||
|
toAll = (radio == null);
|
||||||
this.ratio = ratio;
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return radio.getMote().toString();
|
return radio.getMote().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Object clone() {
|
||||||
|
return new DestinationRadio(radio);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used for optimizing lookup time */
|
public static class DGRMDestinationRadio extends DestinationRadio {
|
||||||
private Hashtable<Radio,DestinationRadio[]> edgesTable = new Hashtable<Radio,DestinationRadio[]>();
|
public double ratio; /* Link success ratio (per packet). */
|
||||||
|
public long delay; /* EXPERIMENTAL: Propagation delay (us). */
|
||||||
|
|
||||||
private void analyzeEdges() {
|
public DGRMDestinationRadio(Radio dest, double ratio, long delay) {
|
||||||
Hashtable<Radio,ArrayList<DestinationRadio>> newTable =
|
super(dest);
|
||||||
|
this.ratio = ratio;
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object clone() {
|
||||||
|
return new DGRMDestinationRadio(radio, ratio, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates hash table using current edges for efficient lookup.
|
||||||
|
*/
|
||||||
|
protected void analyzeEdges() {
|
||||||
|
Hashtable<Radio,ArrayList<DestinationRadio>> listTable =
|
||||||
new Hashtable<Radio,ArrayList<DestinationRadio>>();
|
new Hashtable<Radio,ArrayList<DestinationRadio>>();
|
||||||
|
|
||||||
/* Fill edge hash table with all edges */
|
/* Fill edge hash table with all edges */
|
||||||
for (Edge edge: edges) {
|
for (Edge edge: edges) {
|
||||||
if (edge.source == null) {
|
if (edge.source == null) {
|
||||||
return; /* Still dirty, wait until all edges are loaded */
|
/* XXX Wait until edge configuration has been loaded */
|
||||||
|
logger.warn("DGRM edges not loaded");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<DestinationRadio> destRadios;
|
ArrayList<DestinationRadio> destRadios;
|
||||||
if (!newTable.containsKey(edge.source.getInterfaces().getRadio())) {
|
if (!listTable.containsKey(edge.source)) {
|
||||||
/* Create new source */
|
/* Create new source */
|
||||||
destRadios = new ArrayList<DestinationRadio>();
|
destRadios = new ArrayList<DestinationRadio>();
|
||||||
} else {
|
} else {
|
||||||
/* Extend source radio with another destination */
|
/* Extend source radio with another destination */
|
||||||
destRadios = newTable.get(edge.source.getInterfaces().getRadio());
|
destRadios = listTable.get(edge.source);
|
||||||
}
|
}
|
||||||
|
|
||||||
DestinationRadio destRadio;
|
/* Explode special rule: to all radios */
|
||||||
if (edge.dest == null) {
|
if (edge.superDest.toAll) {
|
||||||
/* All radios */
|
for (Radio r: getRegisteredRadios()) {
|
||||||
Vector<Radio> allRadios = getRegisteredRadios();
|
if (edge.source == r) {
|
||||||
for (Radio r: allRadios) {
|
continue;
|
||||||
destRadio = new DestinationRadio(r, edge.successRatio, edge.delay);
|
}
|
||||||
destRadios.add(destRadio);
|
DestinationRadio d = (DestinationRadio) edge.superDest.clone();
|
||||||
|
d.radio = r;
|
||||||
|
d.toAll = false;
|
||||||
|
destRadios.add(d);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
destRadio = new DestinationRadio(edge.dest.getInterfaces().getRadio(), edge.successRatio, edge.delay);
|
destRadios.add(edge.superDest);
|
||||||
destRadios.add(destRadio);
|
|
||||||
}
|
}
|
||||||
|
listTable.put(edge.source, destRadios);
|
||||||
newTable.put(edge.source.getInterfaces().getRadio(), destRadios);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert to arrays */
|
/* Convert to arrays */
|
||||||
Hashtable<Radio,DestinationRadio[]> newTable2 = new Hashtable<Radio,DestinationRadio[]>();
|
Hashtable<Radio,DestinationRadio[]> arrTable =
|
||||||
Enumeration<Radio> sources = newTable.keys();
|
new Hashtable<Radio,DestinationRadio[]>();
|
||||||
while (sources.hasMoreElements()) {
|
Enumeration<Radio> sources = listTable.keys();
|
||||||
Radio source = sources.nextElement();
|
while (sources.hasMoreElements()) {
|
||||||
ArrayList<DestinationRadio> list = newTable.get(source);
|
Radio source = sources.nextElement();
|
||||||
DestinationRadio[] arr = new DestinationRadio[list.size()];
|
DestinationRadio[] arr =
|
||||||
list.toArray(arr);
|
listTable.get(source).toArray(new DestinationRadio[0]);
|
||||||
newTable2.put(source, arr);
|
arrTable.put(source, arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.edgesTable = newTable2;
|
this.edgesTable = arrTable;
|
||||||
edgesDirty = false;
|
edgesDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all potential destination radios, i.e. all radios "within reach".
|
||||||
|
* Does not consider radio channels, transmission success ratios etc.
|
||||||
|
*
|
||||||
|
* @param source Source radio
|
||||||
|
* @return All potential destination radios
|
||||||
|
*/
|
||||||
|
public DestinationRadio[] getPotentialDestinations(Radio source) {
|
||||||
|
if (edgesDirty) {
|
||||||
|
analyzeEdges();
|
||||||
|
}
|
||||||
|
return edgesTable.get(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RadioConnection createConnections(Radio source) {
|
public RadioConnection createConnections(Radio source) {
|
||||||
if (edgesDirty) {
|
if (edgesDirty) {
|
||||||
analyzeEdges();
|
analyzeEdges();
|
||||||
}
|
}
|
||||||
|
if (edgesDirty) {
|
||||||
/* Create new radio connection using edge hash table */
|
logger.fatal("Error when analyzing edges, aborting new radio connection");
|
||||||
DestinationRadio[] destinations = edgesTable.get(source);
|
|
||||||
if (destinations == null || destinations.length == 0) {
|
|
||||||
/* No destinations */
|
|
||||||
/*logger.info(sendingRadio + ": No dest");*/
|
|
||||||
return new RadioConnection(source);
|
return new RadioConnection(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*logger.info(source + ": " + destinations.length + " potential destinations");*/
|
/* Create new radio connection using edge hash table */
|
||||||
RadioConnection newConn = new RadioConnection(source);
|
RadioConnection newConn = new RadioConnection(source);
|
||||||
for (DestinationRadio dest: destinations) {
|
DestinationRadio[] destinations = getPotentialDestinations(source);
|
||||||
|
if (destinations == null || destinations.length == 0) {
|
||||||
|
/* No destinations */
|
||||||
|
/*logger.info(sendingRadio + ": No dest");*/
|
||||||
|
return newConn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*logger.info(source + ": " + destinations.length + " potential destinations");*/
|
||||||
|
for (DestinationRadio d: destinations) {
|
||||||
|
DGRMDestinationRadio dest = (DGRMDestinationRadio) d;
|
||||||
if (dest.radio == source) {
|
if (dest.radio == source) {
|
||||||
/* Fail: cannot receive our own transmission */
|
/* Fail: cannot receive our own transmission */
|
||||||
/*logger.info(source + ": Fail, receiver is sender");*/
|
/*logger.info(source + ": Fail, receiver is sender");*/
|
||||||
|
@ -274,35 +339,8 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
return newConn;
|
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() {
|
public Collection<Element> getConfigXML() {
|
||||||
Vector<Element> config = new Vector<Element>();
|
ArrayList<Element> config = new ArrayList<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
for (Edge edge: edges) {
|
for (Edge edge: edges) {
|
||||||
|
@ -319,66 +357,67 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
|
|
||||||
for (Element element : configXML) {
|
for (Element element : configXML) {
|
||||||
if (element.getName().equals("edge")) {
|
if (element.getName().equals("edge")) {
|
||||||
Edge edge = new Edge(null, null, 0, 0);
|
Edge edge = new Edge();
|
||||||
edge.delayedLoadConfig = element.getChildren();
|
edge.delayedLoadConfig = element.getChildren();
|
||||||
addEdge(edge);
|
addEdge(edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setEdgesDirty();
|
requestEdgeAnalysis();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Edge {
|
public static class Edge {
|
||||||
public Mote source = null;
|
public Radio source;
|
||||||
public Mote dest = null; /* null: all motes*/
|
public DestinationRadio superDest;
|
||||||
public double successRatio = 1.0; /* Link success ratio (per packet). */
|
|
||||||
public long delay = 0; /* Propagation delay (us). */
|
|
||||||
|
|
||||||
public Edge(Mote source, double ratio, long delay) {
|
private Edge() {
|
||||||
this.source = source;
|
/* Internal constructor: await config */
|
||||||
this.successRatio = ratio;
|
source = null;
|
||||||
this.delay = delay;
|
superDest = null;
|
||||||
|
|
||||||
this.dest = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Edge(Mote source, Mote dest, double ratio, long delay) {
|
public Edge(Radio source, DestinationRadio dest) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.successRatio = ratio;
|
this.superDest = dest;
|
||||||
this.delay = delay;
|
|
||||||
|
|
||||||
this.dest = dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Element> delayedLoadConfig = null; /* Used for restoring edges from config */
|
/* Internal methods */
|
||||||
public Collection<Element> getConfigXML() {
|
private Collection<Element> delayedLoadConfig = null; /* Used for restoring edges from config */
|
||||||
|
private Collection<Element> getConfigXML() {
|
||||||
Vector<Element> config = new Vector<Element>();
|
Vector<Element> config = new Vector<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
element = new Element("src");
|
element = new Element("src");
|
||||||
element.setText(source.toString());
|
element.setText(source.getMote().toString());
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
|
||||||
element = new Element("dest");
|
element = new Element("dest");
|
||||||
if (dest == null) {
|
if (superDest.toAll) {
|
||||||
element.setText("ALL");
|
element.setText("ALL");
|
||||||
} else {
|
} else {
|
||||||
element.setText(dest.toString());
|
element.setText(superDest.radio.getMote().toString());
|
||||||
}
|
}
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
|
||||||
element = new Element("ratio");
|
if (superDest instanceof DGRMDestinationRadio) {
|
||||||
element.setText("" + successRatio);
|
element = new Element("ratio");
|
||||||
config.add(element);
|
element.setText("" + ((DGRMDestinationRadio)superDest).ratio);
|
||||||
|
config.add(element);
|
||||||
|
|
||||||
element = new Element("delay");
|
element = new Element("delay");
|
||||||
element.setText("" + delay);
|
element.setText("" + ((DGRMDestinationRadio)superDest).delay);
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
public boolean setConfigXML(Collection<Element> configXML, Simulation simulation) {
|
|
||||||
|
private boolean setConfigXML(Collection<Element> configXML, Simulation simulation) {
|
||||||
|
Radio dest = null;
|
||||||
|
double ratio = -1;
|
||||||
|
long delay = -1;
|
||||||
|
|
||||||
for (Element element : configXML) {
|
for (Element element : configXML) {
|
||||||
if (element.getName().equals("src")) {
|
if (element.getName().equals("src")) {
|
||||||
String moteDescription = element.getText();
|
String moteDescription = element.getText();
|
||||||
|
@ -387,7 +426,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
for (Mote m: simulation.getMotes()) {
|
for (Mote m: simulation.getMotes()) {
|
||||||
if (moteDescription.equals(m.toString())) {
|
if (moteDescription.equals(m.toString())) {
|
||||||
foundMote = true;
|
foundMote = true;
|
||||||
source = m;
|
source = m.getInterfaces().getRadio();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,7 +446,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
for (Mote m: simulation.getMotes()) {
|
for (Mote m: simulation.getMotes()) {
|
||||||
if (moteDescription.equals(m.toString())) {
|
if (moteDescription.equals(m.toString())) {
|
||||||
foundMote = true;
|
foundMote = true;
|
||||||
dest = m;
|
dest = m.getInterfaces().getRadio();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,14 +457,19 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.getName().equals("ratio")) {
|
if (element.getName().equals("ratio")) {
|
||||||
successRatio = Double.parseDouble(element.getText());
|
ratio = Double.parseDouble(element.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.getName().equals("delay")) {
|
if (element.getName().equals("delay")) {
|
||||||
delay = Long.parseLong(element.getText());
|
delay = Long.parseLong(element.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ratio < 0 || delay < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
superDest = new DGRMDestinationRadio(dest, ratio, delay);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
* Copyright (c) 2009, Swedish Institute of Computer Science.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -26,151 +26,221 @@
|
||||||
* 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: UDGM.java,v 1.25 2009/05/26 14:17:29 fros4943 Exp $
|
* $Id: UDGM.java,v 1.26 2009/10/27 10:10:03 fros4943 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package se.sics.cooja.radiomediums;
|
package se.sics.cooja.radiomediums;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import org.jdom.Element;
|
import java.util.Collection;
|
||||||
import org.apache.log4j.Logger;
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
|
import se.sics.cooja.ClassDescription;
|
||||||
|
import se.sics.cooja.Mote;
|
||||||
|
import se.sics.cooja.RadioConnection;
|
||||||
|
import se.sics.cooja.Simulation;
|
||||||
|
import se.sics.cooja.SimEventCentral.MoteCountListener;
|
||||||
import se.sics.cooja.contikimote.interfaces.ContikiRadio;
|
import se.sics.cooja.contikimote.interfaces.ContikiRadio;
|
||||||
import se.sics.cooja.interfaces.*;
|
import se.sics.cooja.interfaces.Position;
|
||||||
|
import se.sics.cooja.interfaces.Radio;
|
||||||
import se.sics.cooja.plugins.Visualizer;
|
import se.sics.cooja.plugins.Visualizer;
|
||||||
import se.sics.cooja.plugins.skins.UDGMVisualizerSkin;
|
import se.sics.cooja.plugins.skins.UDGMVisualizerSkin;
|
||||||
|
import se.sics.cooja.radiomediums.DirectedGraphMedium.DestinationRadio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Unit Disk Graph medium has two different range parameters; one for
|
* The Unit Disk Graph Radio Medium abstracts radio transmission range as circles.
|
||||||
* transmitting and one for interfering other transmissions.
|
*
|
||||||
*
|
* It uses two different range parameters: one for transmissions, and one for
|
||||||
* The radio medium supports both byte and packet radios.
|
* interfering with other radios and transmissions.
|
||||||
*
|
*
|
||||||
* The registered radios' signal strengths are updated whenever the radio medium
|
* Both radio ranges grow with the radio output power indicator.
|
||||||
* changes. There are three fixed levels: no surrounding traffic heard, noise
|
* The range parameters are multiplied with [output power]/[maximum output power].
|
||||||
* heard and data heard.
|
* For example, if the transmission range is 100m, the current power indicator
|
||||||
*
|
* is 50, and the maximum output power indicator is 100, then the resulting transmission
|
||||||
* The radio output power indicator (0-100) is used in a very simple way; the
|
* range becomes 50m.
|
||||||
* total transmission (and interfering) range is multiplied with [power_ind]%.
|
*
|
||||||
|
* For radio transmissions within range, two different success ratios are used [0.0-1.0]:
|
||||||
|
* one for successful transmissions, and one for successful receptions.
|
||||||
|
* If the transmission fails, no radio will hear the transmission.
|
||||||
|
* If one of receptions fail, only that receiving radio will not receive the transmission,
|
||||||
|
* but will be interfered throughout the entire radio connection.
|
||||||
|
*
|
||||||
|
* The received radio packet signal strength grows inversely with the distance to the
|
||||||
|
* transmitter.
|
||||||
*
|
*
|
||||||
* @see #SS_STRONG
|
* @see #SS_STRONG
|
||||||
* @see #SS_WEAK
|
* @see #SS_WEAK
|
||||||
* @see #SS_NOTHING
|
* @see #SS_NOTHING
|
||||||
*
|
*
|
||||||
* @see UDGMVisualizerSkin
|
* @see DirectedGraphMedium, UDGMVisualizerSkin
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
*/
|
*/
|
||||||
@ClassDescription("Unit Disk Graph Medium (UDGM)")
|
@ClassDescription("Unit Disk Graph Medium (UDGM)")
|
||||||
public class UDGM extends AbstractRadioMedium {
|
public class UDGM extends AbstractRadioMedium {
|
||||||
private static Logger logger = Logger.getLogger(UDGM.class);
|
private static Logger logger = Logger.getLogger(UDGM.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;
|
|
||||||
|
|
||||||
public double SUCCESS_RATIO_TX = 1.0; /* Success ratio of TX. If this fails, no radios receive the packet */
|
public double SUCCESS_RATIO_TX = 1.0; /* Success ratio of TX. If this fails, no radios receive the packet */
|
||||||
public double SUCCESS_RATIO_RX = 1.0; /* Success ratio of RX. If this fails, a single radio does not receive the packet */
|
public double SUCCESS_RATIO_RX = 1.0; /* Success ratio of RX. If this fails, the single affected receiver does not receive the packet */
|
||||||
public double TRANSMITTING_RANGE = 50; /* Transmission range. */
|
public double TRANSMITTING_RANGE = 50; /* Transmission range. */
|
||||||
public double INTERFERENCE_RANGE = 100; /* Interference range. Ignored if below transmission range. */
|
public double INTERFERENCE_RANGE = 100; /* Interference range. Ignored if below transmission range. */
|
||||||
|
|
||||||
private Simulation mySimulation;
|
private Simulation simulation;
|
||||||
|
private DirectedGraphMedium dgrm; /* Used only for efficient destination lookup */
|
||||||
|
|
||||||
private Random random = null;
|
private Random random = null;
|
||||||
|
|
||||||
public UDGM(Simulation simulation) {
|
public UDGM(Simulation simulation) {
|
||||||
super(simulation);
|
super(simulation);
|
||||||
|
this.simulation = simulation;
|
||||||
|
random = simulation.getRandomGenerator();
|
||||||
|
dgrm = new DirectedGraphMedium() {
|
||||||
|
protected void analyzeEdges() {
|
||||||
|
/* Create edges according to distances.
|
||||||
|
* XXX May be slow for mobile networks */
|
||||||
|
clearEdges();
|
||||||
|
for (Radio source: UDGM.this.getRegisteredRadios()) {
|
||||||
|
Position sourcePos = source.getPosition();
|
||||||
|
for (Radio dest: UDGM.this.getRegisteredRadios()) {
|
||||||
|
Position destPos = dest.getPosition();
|
||||||
|
/* Ignore ourselves */
|
||||||
|
if (source == dest) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double distance = sourcePos.getDistanceTo(destPos);
|
||||||
|
if (distance < Math.max(TRANSMITTING_RANGE, INTERFERENCE_RANGE)) {
|
||||||
|
/* Add potential destination */
|
||||||
|
addEdge(
|
||||||
|
new DirectedGraphMedium.Edge(source,
|
||||||
|
new DestinationRadio(dest)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.analyzeEdges();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* Register visualizer skin */
|
/* Register as position observer.
|
||||||
/* TODO Should be unregistered when radio medium is removed */
|
* If any positions change, re-analyze potential receivers. */
|
||||||
|
final Observer positionObserver = new Observer() {
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
dgrm.requestEdgeAnalysis();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/* Re-analyze potential receivers if radios are added/removed. */
|
||||||
|
simulation.getEventCentral().addMoteCountListener(new MoteCountListener() {
|
||||||
|
public void moteWasAdded(Mote mote) {
|
||||||
|
mote.getInterfaces().getPosition().addObserver(positionObserver);
|
||||||
|
dgrm.requestEdgeAnalysis();
|
||||||
|
}
|
||||||
|
public void moteWasRemoved(Mote mote) {
|
||||||
|
mote.getInterfaces().getPosition().deleteObserver(positionObserver);
|
||||||
|
dgrm.requestEdgeAnalysis();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (Mote mote: simulation.getMotes()) {
|
||||||
|
mote.getInterfaces().getPosition().addObserver(positionObserver);
|
||||||
|
}
|
||||||
|
dgrm.requestEdgeAnalysis();
|
||||||
|
|
||||||
|
/* Register visualizer skin.
|
||||||
|
* TODO Should be unregistered when radio medium is removed */
|
||||||
Visualizer.registerVisualizerSkin(UDGMVisualizerSkin.class);
|
Visualizer.registerVisualizerSkin(UDGMVisualizerSkin.class);
|
||||||
|
|
||||||
mySimulation = simulation;
|
|
||||||
random = mySimulation.getRandomGenerator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RadioConnection createConnections(Radio sendingRadio) {
|
public void setTxRange(double r) {
|
||||||
Position sendingPosition = sendingRadio.getPosition();
|
TRANSMITTING_RANGE = r;
|
||||||
RadioConnection newConnection = new RadioConnection(sendingRadio);
|
dgrm.requestEdgeAnalysis();
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch current output power indicator (scale with as percent)
|
public void setInterferenceRange(double r) {
|
||||||
double moteTransmissionRange = TRANSMITTING_RANGE
|
INTERFERENCE_RANGE = r;
|
||||||
* ((double) sendingRadio.getCurrentOutputPowerIndicator() / (double) sendingRadio.getOutputPowerIndicatorMax());
|
dgrm.requestEdgeAnalysis();
|
||||||
double moteInterferenceRange = INTERFERENCE_RANGE
|
}
|
||||||
* ((double) sendingRadio.getCurrentOutputPowerIndicator() / (double) sendingRadio.getOutputPowerIndicatorMax());
|
|
||||||
|
|
||||||
/* Fail transmission randomly (affects all receiving nodes) */
|
public RadioConnection createConnections(Radio sender) {
|
||||||
|
RadioConnection newConnection = new RadioConnection(sender);
|
||||||
|
|
||||||
|
/* Fail radio transmission randomly - no radios will hear this transmission */
|
||||||
if (SUCCESS_RATIO_TX < 1.0 && random.nextDouble() > SUCCESS_RATIO_TX) {
|
if (SUCCESS_RATIO_TX < 1.0 && random.nextDouble() > SUCCESS_RATIO_TX) {
|
||||||
return newConnection;
|
return newConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through all radios
|
/* Calculate ranges: grows with radio output power */
|
||||||
for (int listenNr = 0; listenNr < getRegisteredRadios().size(); listenNr++) {
|
double moteTransmissionRange = TRANSMITTING_RANGE
|
||||||
Radio listeningRadio = getRegisteredRadios().get(listenNr);
|
* ((double) sender.getCurrentOutputPowerIndicator() / (double) sender.getOutputPowerIndicatorMax());
|
||||||
Position listeningRadioPosition = listeningRadio.getPosition();
|
double moteInterferenceRange = INTERFERENCE_RANGE
|
||||||
|
* ((double) sender.getCurrentOutputPowerIndicator() / (double) sender.getOutputPowerIndicatorMax());
|
||||||
|
|
||||||
// Ignore sending radio and radios on different channels
|
/* Get all potential destination radios */
|
||||||
if (sendingRadio == listeningRadio) {
|
DestinationRadio[] potentialDestinations = dgrm.getPotentialDestinations(sender);
|
||||||
|
if (potentialDestinations == null) {
|
||||||
|
return newConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop through all potential destinations */
|
||||||
|
Position senderPos = sender.getPosition();
|
||||||
|
for (DestinationRadio dest: potentialDestinations) {
|
||||||
|
Radio recv = dest.radio;
|
||||||
|
Position recvPos = recv.getPosition();
|
||||||
|
|
||||||
|
/* Fail if radios are on different (but configured) channels */
|
||||||
|
if (sender.getChannel() >= 0 &&
|
||||||
|
recv.getChannel() >= 0 &&
|
||||||
|
sender.getChannel() != recv.getChannel()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (sendingRadio.getChannel() >= 0 &&
|
|
||||||
listeningRadio.getChannel() >= 0 &&
|
/* Fail if radio is turned off */
|
||||||
sendingRadio.getChannel() != listeningRadio.getChannel()) {
|
if (!recv.isReceiverOn()) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!listeningRadio.isReceiverOn()) {
|
|
||||||
/* Special case: allow connection if source is Contiki radio,
|
/* Special case: allow connection if source is Contiki radio,
|
||||||
* and destination is something else (byte radio).
|
* and destination is something else (byte radio).
|
||||||
* Allows cross-level communication with power-saving MACs. */
|
* Allows cross-level communication with power-saving MACs. */
|
||||||
if (sendingRadio instanceof ContikiRadio &&
|
if (sender instanceof ContikiRadio &&
|
||||||
!(listeningRadio instanceof ContikiRadio)) {
|
!(recv instanceof ContikiRadio)) {
|
||||||
/*logger.info("Special case: creating connection to turned off radio");*/
|
/*logger.info("Special case: creating connection to turned off radio");*/
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double distance = sendingPosition.getDistanceTo(listeningRadioPosition);
|
double distance = senderPos.getDistanceTo(recvPos);
|
||||||
|
|
||||||
if (distance <= moteTransmissionRange) {
|
if (distance <= moteTransmissionRange) {
|
||||||
// Check if this radio is able to receive transmission
|
/* Within transmission range */
|
||||||
if (listeningRadio.isInterfered()) {
|
|
||||||
// Keep interfering radio
|
|
||||||
newConnection.addInterfered(listeningRadio);
|
|
||||||
|
|
||||||
} else if (listeningRadio.isReceiving() ||
|
if (recv.isInterfered()) {
|
||||||
|
/* Was interfered: keep interfering */
|
||||||
|
newConnection.addInterfered(recv);
|
||||||
|
|
||||||
|
} else if (recv.isReceiving() ||
|
||||||
(SUCCESS_RATIO_RX < 1.0 && random.nextDouble() > SUCCESS_RATIO_RX)) {
|
(SUCCESS_RATIO_RX < 1.0 && random.nextDouble() > SUCCESS_RATIO_RX)) {
|
||||||
newConnection.addInterfered(listeningRadio);
|
/* Was receiving, or reception failed: start interfering */
|
||||||
|
newConnection.addInterfered(recv);
|
||||||
|
recv.interfereAnyReception();
|
||||||
|
|
||||||
// Start interfering radio
|
/* Interfere receiver in all other active radio connections */
|
||||||
listeningRadio.interfereAnyReception();
|
|
||||||
|
|
||||||
// Update connection that is transmitting to this radio
|
|
||||||
RadioConnection existingConn = null;
|
|
||||||
for (RadioConnection conn : getActiveConnections()) {
|
for (RadioConnection conn : getActiveConnections()) {
|
||||||
for (Radio dstRadio : conn.getDestinations()) {
|
for (Radio dstRadio : conn.getDestinations()) {
|
||||||
if (dstRadio == listeningRadio) {
|
if (dstRadio == recv) {
|
||||||
existingConn = conn;
|
conn.removeDestination(recv);
|
||||||
|
conn.addInterfered(recv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (existingConn != null) {
|
|
||||||
// Change radio from receiving to interfered
|
|
||||||
existingConn.removeDestination(listeningRadio);
|
|
||||||
existingConn.addInterfered(listeningRadio);
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Radio OK to receive
|
/* Success: radio starts receiving */
|
||||||
newConnection.addDestination(listeningRadio);
|
newConnection.addDestination(recv);
|
||||||
}
|
}
|
||||||
} else if (distance <= moteInterferenceRange) {
|
} else if (distance <= moteInterferenceRange) {
|
||||||
// Interfere radio
|
/* Within interference range */
|
||||||
newConnection.addInterfered(listeningRadio);
|
newConnection.addInterfered(recv);
|
||||||
listeningRadio.interfereAnyReception();
|
recv.interfereAnyReception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,20 +248,16 @@ public class UDGM extends AbstractRadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSignalStrengths() {
|
public void updateSignalStrengths() {
|
||||||
// // Save old signal strengths
|
/* Override: uses distance as signal strength factor */
|
||||||
// double[] oldSignalStrengths = new double[registeredRadios.size()];
|
|
||||||
// for (int i = 0; i < registeredRadios.size(); i++) {
|
|
||||||
// oldSignalStrengths[i] = registeredRadios.get(i)
|
|
||||||
// .getCurrentSignalStrength();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Reset signal strength on all radios
|
/* Reset signal strengths */
|
||||||
for (Radio radio : getRegisteredRadios()) {
|
for (Radio radio : getRegisteredRadios()) {
|
||||||
radio.setCurrentSignalStrength(SS_NOTHING);
|
radio.setCurrentSignalStrength(SS_NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set signal strength on all OK transmissions
|
/* Set signal strength to below strong on destinations */
|
||||||
for (RadioConnection conn : getActiveConnections()) {
|
RadioConnection[] conns = getActiveConnections();
|
||||||
|
for (RadioConnection conn : conns) {
|
||||||
conn.getSource().setCurrentSignalStrength(SS_STRONG);
|
conn.getSource().setCurrentSignalStrength(SS_STRONG);
|
||||||
for (Radio dstRadio : conn.getDestinations()) {
|
for (Radio dstRadio : conn.getDestinations()) {
|
||||||
double dist = conn.getSource().getPosition().getDistanceTo(dstRadio.getPosition());
|
double dist = conn.getSource().getPosition().getDistanceTo(dstRadio.getPosition());
|
||||||
|
@ -205,8 +271,8 @@ public class UDGM extends AbstractRadioMedium {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set signal strength on all interferences
|
/* Set signal strength to below weak on interfered */
|
||||||
for (RadioConnection conn : getActiveConnections()) {
|
for (RadioConnection conn : conns) {
|
||||||
for (Radio intfRadio : conn.getInterfered()) {
|
for (Radio intfRadio : conn.getInterfered()) {
|
||||||
double dist = conn.getSource().getPosition().getDistanceTo(intfRadio.getPosition());
|
double dist = conn.getSource().getPosition().getDistanceTo(intfRadio.getPosition());
|
||||||
|
|
||||||
|
@ -222,37 +288,23 @@ public class UDGM extends AbstractRadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!intfRadio.isInterfered()) {
|
if (!intfRadio.isInterfered()) {
|
||||||
// Set to interfered again
|
logger.warn("Radio was not interfered: " + intfRadio);
|
||||||
intfRadio.interfereAnyReception();
|
intfRadio.interfereAnyReception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Fetch new signal strengths
|
|
||||||
// double[] newSignalStrengths = new double[registeredRadios.size()];
|
|
||||||
// for (int i = 0; i < registeredRadios.size(); i++) {
|
|
||||||
// newSignalStrengths[i] = registeredRadios.get(i)
|
|
||||||
// .getCurrentSignalStrength();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Compare new and old signal strengths
|
|
||||||
// for (int i = 0; i < registeredRadios.size(); i++) {
|
|
||||||
// if (oldSignalStrengths[i] != newSignalStrengths[i])
|
|
||||||
// logger.warn("Signal strengths changed on radio[" + i + "]: "
|
|
||||||
// + oldSignalStrengths[i] + " -> " + newSignalStrengths[i]);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Element> getConfigXML() {
|
public Collection<Element> getConfigXML() {
|
||||||
Vector<Element> config = new Vector<Element>();
|
ArrayList<Element> config = new ArrayList<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
// Transmitting range
|
/* Transmitting range */
|
||||||
element = new Element("transmitting_range");
|
element = new Element("transmitting_range");
|
||||||
element.setText(Double.toString(TRANSMITTING_RANGE));
|
element.setText(Double.toString(TRANSMITTING_RANGE));
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
|
||||||
// Interference range
|
/* Interference range */
|
||||||
element = new Element("interference_range");
|
element = new Element("interference_range");
|
||||||
element.setText(Double.toString(INTERFERENCE_RANGE));
|
element.setText(Double.toString(INTERFERENCE_RANGE));
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
|
Loading…
Reference in a new issue