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
4 changed files with 639 additions and 443 deletions
|
@ -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;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
|
@ -6,6 +37,7 @@ 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;
|
||||
|
@ -29,8 +61,13 @@ import se.sics.cooja.PluginType;
|
|||
import se.sics.cooja.Simulation;
|
||||
import se.sics.cooja.VisPlugin;
|
||||
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
|
||||
*/
|
||||
@ClassDescription("DGRM Configurator")
|
||||
|
@ -82,11 +119,11 @@ public class DGRMConfigurator extends VisPlugin {
|
|||
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(0);
|
||||
combo.addItem(1);
|
||||
combo.addItem(2);
|
||||
combo.addItem(3);
|
||||
|
@ -190,16 +227,21 @@ public class DGRMConfigurator extends VisPlugin {
|
|||
DirectedGraphMedium.Edge newEdge;
|
||||
if (dest.getSelectedItem() instanceof Mote) {
|
||||
newEdge = new DirectedGraphMedium.Edge(
|
||||
(Mote) source.getSelectedItem(),
|
||||
(Mote) dest.getSelectedItem(),
|
||||
((Mote) source.getSelectedItem()).getInterfaces().getRadio(),
|
||||
new DGRMDestinationRadio(
|
||||
((Mote) dest.getSelectedItem()).getInterfaces().getRadio(),
|
||||
((Number)ratio.getValue()).doubleValue(),
|
||||
((Number)delay.getValue()).longValue()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
newEdge = new DirectedGraphMedium.Edge(
|
||||
(Mote) source.getSelectedItem(),
|
||||
((Mote) source.getSelectedItem()).getInterfaces().getRadio(),
|
||||
new DGRMDestinationRadio(
|
||||
null,
|
||||
((Number)ratio.getValue()).doubleValue(),
|
||||
((Number)delay.getValue()).longValue()
|
||||
)
|
||||
);
|
||||
}
|
||||
radioMedium.addEdge(newEdge);
|
||||
|
@ -243,19 +285,19 @@ public class DGRMConfigurator extends VisPlugin {
|
|||
if (edge.source == null) {
|
||||
return "?";
|
||||
}
|
||||
return edge.source;
|
||||
return edge.source.getMote();
|
||||
}
|
||||
if (column == IDX_DST) {
|
||||
if (edge.dest == null) {
|
||||
if (edge.superDest.toAll) {
|
||||
return "ALL";
|
||||
}
|
||||
return edge.dest;
|
||||
return edge.superDest.radio.getMote();
|
||||
}
|
||||
if (column == IDX_RATIO) {
|
||||
return edge.successRatio;
|
||||
return ((DGRMDestinationRadio)edge.superDest).ratio;
|
||||
}
|
||||
if (column == IDX_DELAY) {
|
||||
return edge.delay / Simulation.MILLISECOND;
|
||||
return ((DGRMDestinationRadio)edge.superDest).delay / Simulation.MILLISECOND;
|
||||
}
|
||||
if (column == IDX_DEL) {
|
||||
return new Boolean(false);
|
||||
|
@ -278,14 +320,16 @@ public class DGRMConfigurator extends VisPlugin {
|
|||
DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row];
|
||||
if (column == IDX_RATIO) {
|
||||
/* Success ratio */
|
||||
edge.successRatio = ((Number)value).doubleValue();
|
||||
radioMedium.setEdgesDirty();
|
||||
((DGRMDestinationRadio)edge.superDest).ratio =
|
||||
((Number)value).doubleValue();
|
||||
radioMedium.requestEdgeAnalysis();
|
||||
return;
|
||||
}
|
||||
if (column == IDX_DELAY) {
|
||||
/* Propagation delay (ms) */
|
||||
edge.delay = ((Number)value).longValue() * Simulation.MILLISECOND;
|
||||
radioMedium.setEdgesDirty();
|
||||
((DGRMDestinationRadio)edge.superDest).delay =
|
||||
((Number)value).longValue() * Simulation.MILLISECOND;
|
||||
radioMedium.requestEdgeAnalysis();
|
||||
return;
|
||||
}
|
||||
if (column == IDX_DEL) {
|
||||
|
@ -301,14 +345,14 @@ public class DGRMConfigurator extends VisPlugin {
|
|||
return false;
|
||||
}
|
||||
|
||||
Mote sourceMote = radioMedium.getEdges()[row].source;
|
||||
Mote sourceMote = radioMedium.getEdges()[row].source.getMote();
|
||||
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);
|
||||
if (!radioMedium.getEdges()[row].superDest.toAll) {
|
||||
gui.signalMoteHighlight(radioMedium.getEdges()[row].superDest.radio.getMote());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -26,21 +26,36 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* 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;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.cooja.*;
|
||||
import se.sics.cooja.interfaces.*;
|
||||
import se.sics.cooja.Mote;
|
||||
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
|
||||
* 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
|
||||
* observes all registered radio interfaces.
|
||||
*
|
||||
|
@ -49,9 +64,15 @@ import se.sics.cooja.interfaces.*;
|
|||
public abstract class AbstractRadioMedium extends RadioMedium {
|
||||
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;
|
||||
|
||||
|
@ -74,8 +95,6 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
|
||||
private RadioMediumObservable radioMediumObservable = new RadioMediumObservable();
|
||||
|
||||
private RadioConnection[] lastTickConnections = null;
|
||||
|
||||
/**
|
||||
* This constructor should always be called from implemented radio mediums.
|
||||
*
|
||||
|
@ -88,8 +107,8 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
/**
|
||||
* @return All registered radios
|
||||
*/
|
||||
public Vector<Radio> getRegisteredRadios() {
|
||||
return registeredRadios;
|
||||
public Radio[] getRegisteredRadios() {
|
||||
return registeredRadios.toArray(new Radio[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,7 +134,35 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
* Updates all radio interfaces' signal strengths according to
|
||||
* 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.
|
||||
|
@ -124,34 +171,40 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
* @param radio Radio
|
||||
*/
|
||||
private void removeFromActiveConnections(Radio radio) {
|
||||
// Abort any reception
|
||||
/* Abort ongoing receptions */
|
||||
if (radio.isReceiving()) {
|
||||
radio.interfereAnyReception();
|
||||
radio.signalReceptionEnd();
|
||||
}
|
||||
|
||||
// Remove radio from all active connections
|
||||
RadioConnection connToRemove = null;
|
||||
for (RadioConnection conn : activeConnections) {
|
||||
conn.removeDestination(radio);
|
||||
conn.removeInterfered(radio);
|
||||
|
||||
if (conn.getSource() == radio) {
|
||||
// Radio is currently transmitting
|
||||
connToRemove = conn;
|
||||
for (Radio dstRadio : conn.getDestinations()) {
|
||||
/* Connection source */
|
||||
RadioConnection connection = getActiveConnectionFrom(radio);
|
||||
if (connection != null) {
|
||||
for (Radio dstRadio : connection.getDestinations()) {
|
||||
dstRadio.interfereAnyReception();
|
||||
dstRadio.signalReceptionEnd();
|
||||
}
|
||||
for (Radio dstRadio : conn.getInterfered()) {
|
||||
for (Radio dstRadio : connection.getInterfered()) {
|
||||
dstRadio.signalReceptionEnd();
|
||||
}
|
||||
activeConnections.remove(connection);
|
||||
}
|
||||
|
||||
/* Connection destination and interfered */
|
||||
for (RadioConnection conn : activeConnections) {
|
||||
conn.removeDestination(radio);
|
||||
conn.removeInterfered(radio);
|
||||
}
|
||||
}
|
||||
if (connToRemove != null) {
|
||||
activeConnections.remove(connToRemove);
|
||||
|
||||
private RadioConnection getActiveConnectionFrom(Radio source) {
|
||||
for (RadioConnection conn : activeConnections) {
|
||||
if (conn.getSource() == source) {
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This observer is responsible for detecting radio interface events, for example
|
||||
|
@ -163,34 +216,32 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
logger.fatal("Radio event dispatched by non-radio object");
|
||||
return;
|
||||
}
|
||||
|
||||
Radio radio = (Radio) obs;
|
||||
|
||||
// Handle radio event
|
||||
final Radio.RadioEvent event = radio.getLastEvent();
|
||||
|
||||
// Ignore reception events
|
||||
if (event == Radio.RadioEvent.RECEPTION_STARTED
|
||||
|| event == Radio.RadioEvent.RECEPTION_INTERFERED
|
||||
|| event == Radio.RadioEvent.RECEPTION_FINISHED) {
|
||||
if (event == Radio.RadioEvent.RECEPTION_STARTED ||
|
||||
event == Radio.RadioEvent.RECEPTION_INTERFERED ||
|
||||
event == Radio.RadioEvent.RECEPTION_FINISHED ||
|
||||
event == Radio.RadioEvent.UNKNOWN) {
|
||||
/* Ignored */
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == Radio.RadioEvent.HW_OFF) {
|
||||
// Destroy any(?) transfers
|
||||
if (event == Radio.RadioEvent.HW_ON) {
|
||||
|
||||
/* Update signal strengths */
|
||||
updateSignalStrengths();
|
||||
|
||||
} else if (event == Radio.RadioEvent.HW_OFF) {
|
||||
|
||||
/* Remove any radio connections from this radio */
|
||||
removeFromActiveConnections(radio);
|
||||
|
||||
// Recalculate signal strengths on all radios
|
||||
updateSignalStrengths();
|
||||
} else if (event == Radio.RadioEvent.HW_ON) {
|
||||
// No action
|
||||
// TODO Maybe set signal strength levels now?
|
||||
|
||||
// Recalculate signal strengths on all radios
|
||||
/* Update signal strengths */
|
||||
updateSignalStrengths();
|
||||
|
||||
} else if (event == Radio.RadioEvent.TRANSMISSION_STARTED) {
|
||||
/* Create radio connections */
|
||||
/* Create new radio connection */
|
||||
|
||||
RadioConnection newConnection = createConnections(radio);
|
||||
activeConnections.add(newConnection);
|
||||
|
@ -213,27 +264,22 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
}
|
||||
}
|
||||
|
||||
// Recalculate signal strengths on all radios
|
||||
/* Update signal strengths */
|
||||
updateSignalStrengths();
|
||||
|
||||
/* Notify observers */
|
||||
radioMediumObservable.setRadioMediumChanged();
|
||||
radioMediumObservable.setRadioMediumChangedAndNotify();
|
||||
|
||||
} else if (event == Radio.RadioEvent.TRANSMISSION_FINISHED) {
|
||||
/* Remove active connection */
|
||||
|
||||
// Find corresponding connection of radio
|
||||
RadioConnection connection = null;
|
||||
for (RadioConnection conn : activeConnections) {
|
||||
if (conn.getSource() == radio) {
|
||||
connection = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Remove radio connection */
|
||||
|
||||
/* Connection */
|
||||
RadioConnection connection = getActiveConnectionFrom(radio);
|
||||
if (connection == null) {
|
||||
logger.fatal("Can't find active connection to remove, source=" + radio);
|
||||
} else {
|
||||
logger.fatal("No radio connection found");
|
||||
return;
|
||||
}
|
||||
|
||||
activeConnections.remove(connection);
|
||||
lastConnection = connection;
|
||||
COUNTER_TX++;
|
||||
|
@ -255,43 +301,53 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
||||
}
|
||||
}
|
||||
for (Radio dstRadio : connection.getInterfered()) {
|
||||
for (Radio intRadio : 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;
|
||||
/* 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("Can't find active connection to forward custom data in");
|
||||
logger.fatal("No radio connection found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Custom data object */
|
||||
Object data = ((CustomDataRadio) radio).getLastCustomDataTransmitted();
|
||||
if (data == null) {
|
||||
logger.fatal("Custom data object is null");
|
||||
logger.fatal("No custom data object to forward");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Radio dstRadio : connection.getDestinations()) {
|
||||
if (dstRadio instanceof CustomDataRadio) {
|
||||
|
||||
if (!radio.getClass().equals(dstRadio.getClass()) ||
|
||||
!(radio instanceof CustomDataRadio)) {
|
||||
/* Radios communicate via radio packets */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connection.getDestinationDelay(dstRadio) == 0) {
|
||||
((CustomDataRadio) dstRadio).receiveCustomData(data);
|
||||
} else {
|
||||
|
@ -310,34 +366,32 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (event == Radio.RadioEvent.PACKET_TRANSMITTED) {
|
||||
/* Forward packet, if any */
|
||||
|
||||
// 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) {
|
||||
logger.fatal("Can't find active connection to forward packet in");
|
||||
logger.fatal("No radio connection found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Radio packet */
|
||||
RadioPacket packet = radio.getLastPacketTransmitted();
|
||||
if (packet == null) {
|
||||
logger.fatal("Radio packet is null");
|
||||
logger.fatal("No radio packet to forward");
|
||||
return;
|
||||
}
|
||||
|
||||
Radio srcRadio = connection.getSource();
|
||||
for (Radio dstRadio : connection.getDestinations()) {
|
||||
if (!(srcRadio instanceof CustomDataRadio) ||
|
||||
!(dstRadio instanceof CustomDataRadio)) {
|
||||
|
||||
if (radio.getClass().equals(dstRadio.getClass()) &&
|
||||
radio instanceof CustomDataRadio) {
|
||||
/* Radios instead communicate via custom data objects */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Forward radio packet */
|
||||
if (connection.getDestinationDelay(dstRadio) == 0) {
|
||||
dstRadio.setReceivedPacket(packet);
|
||||
} else {
|
||||
|
@ -353,13 +407,10 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
simulation.scheduleEvent(
|
||||
delayedEvent,
|
||||
simulation.getSimulationTime() + connection.getDestinationDelay(dstRadio));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (event == Radio.RadioEvent.UNKNOWN) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.fatal("Unsupported radio event: " + event);
|
||||
}
|
||||
|
@ -375,19 +426,21 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
}
|
||||
|
||||
public void registerRadioInterface(Radio radio, Simulation sim) {
|
||||
if (radio != null) {
|
||||
// Register and start observing radio
|
||||
if (radio == null) {
|
||||
logger.warn("No radio to register");
|
||||
return;
|
||||
}
|
||||
|
||||
registeredRadios.add(radio);
|
||||
radio.addObserver(radioEventsObserver);
|
||||
|
||||
// Set initial signal strength
|
||||
/* Update signal strengths */
|
||||
updateSignalStrengths();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterRadioInterface(Radio radio, Simulation sim) {
|
||||
if (!registeredRadios.contains(radio)) {
|
||||
logger.warn("Could not find radio: " + radio + " to unregister");
|
||||
logger.warn("No radio to unregister: " + radio);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -395,6 +448,9 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
|||
registeredRadios.remove(radio);
|
||||
|
||||
removeFromActiveConnections(radio);
|
||||
|
||||
/* Update signal strengths */
|
||||
updateSignalStrengths();
|
||||
}
|
||||
|
||||
public void addRadioMediumObserver(Observer observer) {
|
||||
|
|
|
@ -26,92 +26,116 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* 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;
|
||||
|
||||
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.jdom.Element;
|
||||
|
||||
import se.sics.cooja.*;
|
||||
import se.sics.cooja.interfaces.*;
|
||||
import se.sics.cooja.ClassDescription;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@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 Random random;
|
||||
|
||||
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) {
|
||||
super(simulation);
|
||||
this.simulation = simulation;
|
||||
random = simulation.getRandomGenerator();
|
||||
|
||||
setEdgesDirty();
|
||||
requestEdgeAnalysis();
|
||||
|
||||
/* Register visualizer plugin */
|
||||
/* Register plugin.
|
||||
* TODO Should be unregistered when radio medium is removed */
|
||||
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();
|
||||
edges.add(e);
|
||||
requestEdgeAnalysis();
|
||||
|
||||
((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)) {
|
||||
if (!edges.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();
|
||||
edges.remove(edge);
|
||||
requestEdgeAnalysis();
|
||||
|
||||
((AbstractRadioMedium.RadioMediumObservable)
|
||||
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||
}
|
||||
|
||||
public void setEdgesDirty() {
|
||||
edgesDirty = true;
|
||||
public void clearEdges() {
|
||||
edges.clear();
|
||||
requestEdgeAnalysis();
|
||||
|
||||
((AbstractRadioMedium.RadioMediumObservable)
|
||||
this.getRadioMediumObservable()).setRadioMediumChangedAndNotify();
|
||||
}
|
||||
|
||||
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) {
|
||||
if (edge.delayedLoadConfig == null) {
|
||||
|
@ -124,107 +148,148 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
|||
}
|
||||
}
|
||||
|
||||
setEdgesDirty();
|
||||
requestEdgeAnalysis();
|
||||
}
|
||||
|
||||
public void unregisterMote(Mote mote, Simulation sim) {
|
||||
super.unregisterMote(mote, sim);
|
||||
public void unregisterRadioInterface(Radio radio, Simulation sim) {
|
||||
super.unregisterRadioInterface(radio, sim);
|
||||
|
||||
for (Edge edge: edges) {
|
||||
if (edge.source == mote || edge.dest == mote) {
|
||||
if (radio == null) {
|
||||
return;
|
||||
}
|
||||
for (Edge edge: getEdges()) {
|
||||
if (edge.source == radio || edge.superDest.radio == radio) {
|
||||
removeEdge(edge);
|
||||
}
|
||||
}
|
||||
|
||||
setEdgesDirty();
|
||||
requestEdgeAnalysis();
|
||||
}
|
||||
|
||||
private class DestinationRadio {
|
||||
Radio radio;
|
||||
double ratio;
|
||||
long delay; /* us */
|
||||
public static class DestinationRadio {
|
||||
public Radio radio; /* destination radio */
|
||||
public boolean toAll; /* to all destinations */
|
||||
|
||||
public DestinationRadio(Radio dest, double ratio, long delay) {
|
||||
public DestinationRadio(Radio dest) {
|
||||
this.radio = dest;
|
||||
|
||||
this.ratio = ratio;
|
||||
this.delay = delay;
|
||||
toAll = (radio == null);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return radio.getMote().toString();
|
||||
}
|
||||
|
||||
protected Object clone() {
|
||||
return new DestinationRadio(radio);
|
||||
}
|
||||
}
|
||||
|
||||
/* Used for optimizing lookup time */
|
||||
private Hashtable<Radio,DestinationRadio[]> edgesTable = new Hashtable<Radio,DestinationRadio[]>();
|
||||
public static class DGRMDestinationRadio extends DestinationRadio {
|
||||
public double ratio; /* Link success ratio (per packet). */
|
||||
public long delay; /* EXPERIMENTAL: Propagation delay (us). */
|
||||
|
||||
private void analyzeEdges() {
|
||||
Hashtable<Radio,ArrayList<DestinationRadio>> newTable =
|
||||
public DGRMDestinationRadio(Radio dest, double ratio, long delay) {
|
||||
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>>();
|
||||
|
||||
/* Fill edge hash table with all edges */
|
||||
for (Edge edge: edges) {
|
||||
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;
|
||||
if (!newTable.containsKey(edge.source.getInterfaces().getRadio())) {
|
||||
if (!listTable.containsKey(edge.source)) {
|
||||
/* Create new source */
|
||||
destRadios = new ArrayList<DestinationRadio>();
|
||||
} else {
|
||||
/* Extend source radio with another destination */
|
||||
destRadios = newTable.get(edge.source.getInterfaces().getRadio());
|
||||
destRadios = listTable.get(edge.source);
|
||||
}
|
||||
|
||||
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);
|
||||
/* Explode special rule: to all radios */
|
||||
if (edge.superDest.toAll) {
|
||||
for (Radio r: getRegisteredRadios()) {
|
||||
if (edge.source == r) {
|
||||
continue;
|
||||
}
|
||||
DestinationRadio d = (DestinationRadio) edge.superDest.clone();
|
||||
d.radio = r;
|
||||
d.toAll = false;
|
||||
destRadios.add(d);
|
||||
}
|
||||
} else {
|
||||
destRadio = new DestinationRadio(edge.dest.getInterfaces().getRadio(), edge.successRatio, edge.delay);
|
||||
destRadios.add(destRadio);
|
||||
destRadios.add(edge.superDest);
|
||||
}
|
||||
|
||||
newTable.put(edge.source.getInterfaces().getRadio(), destRadios);
|
||||
listTable.put(edge.source, destRadios);
|
||||
}
|
||||
|
||||
/* Convert to arrays */
|
||||
Hashtable<Radio,DestinationRadio[]> newTable2 = new Hashtable<Radio,DestinationRadio[]>();
|
||||
Enumeration<Radio> sources = newTable.keys();
|
||||
Hashtable<Radio,DestinationRadio[]> arrTable =
|
||||
new Hashtable<Radio,DestinationRadio[]>();
|
||||
Enumeration<Radio> sources = listTable.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);
|
||||
DestinationRadio[] arr =
|
||||
listTable.get(source).toArray(new DestinationRadio[0]);
|
||||
arrTable.put(source, arr);
|
||||
}
|
||||
|
||||
this.edgesTable = newTable2;
|
||||
this.edgesTable = arrTable;
|
||||
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) {
|
||||
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");*/
|
||||
if (edgesDirty) {
|
||||
logger.fatal("Error when analyzing edges, aborting new radio connection");
|
||||
return new RadioConnection(source);
|
||||
}
|
||||
|
||||
/*logger.info(source + ": " + destinations.length + " potential destinations");*/
|
||||
/* Create new radio connection using edge hash table */
|
||||
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) {
|
||||
/* Fail: cannot receive our own transmission */
|
||||
/*logger.info(source + ": Fail, receiver is sender");*/
|
||||
|
@ -274,35 +339,8 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
|||
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>();
|
||||
ArrayList<Element> config = new ArrayList<Element>();
|
||||
Element element;
|
||||
|
||||
for (Edge edge: edges) {
|
||||
|
@ -319,66 +357,67 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
|||
|
||||
for (Element element : configXML) {
|
||||
if (element.getName().equals("edge")) {
|
||||
Edge edge = new Edge(null, null, 0, 0);
|
||||
Edge edge = new Edge();
|
||||
edge.delayedLoadConfig = element.getChildren();
|
||||
addEdge(edge);
|
||||
}
|
||||
}
|
||||
|
||||
setEdgesDirty();
|
||||
requestEdgeAnalysis();
|
||||
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 (us). */
|
||||
public Radio source;
|
||||
public DestinationRadio superDest;
|
||||
|
||||
public Edge(Mote source, double ratio, long delay) {
|
||||
this.source = source;
|
||||
this.successRatio = ratio;
|
||||
this.delay = delay;
|
||||
|
||||
this.dest = null;
|
||||
private Edge() {
|
||||
/* Internal constructor: await config */
|
||||
source = null;
|
||||
superDest = null;
|
||||
}
|
||||
|
||||
public Edge(Mote source, Mote dest, double ratio, long delay) {
|
||||
public Edge(Radio source, DestinationRadio dest) {
|
||||
this.source = source;
|
||||
this.successRatio = ratio;
|
||||
this.delay = delay;
|
||||
|
||||
this.dest = dest;
|
||||
this.superDest = dest;
|
||||
}
|
||||
|
||||
public Collection<Element> delayedLoadConfig = null; /* Used for restoring edges from config */
|
||||
public Collection<Element> getConfigXML() {
|
||||
/* Internal methods */
|
||||
private Collection<Element> delayedLoadConfig = null; /* Used for restoring edges from config */
|
||||
private Collection<Element> getConfigXML() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
Element element;
|
||||
|
||||
element = new Element("src");
|
||||
element.setText(source.toString());
|
||||
element.setText(source.getMote().toString());
|
||||
config.add(element);
|
||||
|
||||
element = new Element("dest");
|
||||
if (dest == null) {
|
||||
if (superDest.toAll) {
|
||||
element.setText("ALL");
|
||||
} else {
|
||||
element.setText(dest.toString());
|
||||
element.setText(superDest.radio.getMote().toString());
|
||||
}
|
||||
config.add(element);
|
||||
|
||||
if (superDest instanceof DGRMDestinationRadio) {
|
||||
element = new Element("ratio");
|
||||
element.setText("" + successRatio);
|
||||
element.setText("" + ((DGRMDestinationRadio)superDest).ratio);
|
||||
config.add(element);
|
||||
|
||||
element = new Element("delay");
|
||||
element.setText("" + delay);
|
||||
element.setText("" + ((DGRMDestinationRadio)superDest).delay);
|
||||
config.add(element);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (element.getName().equals("src")) {
|
||||
String moteDescription = element.getText();
|
||||
|
@ -387,7 +426,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
|||
for (Mote m: simulation.getMotes()) {
|
||||
if (moteDescription.equals(m.toString())) {
|
||||
foundMote = true;
|
||||
source = m;
|
||||
source = m.getInterfaces().getRadio();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +446,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
|||
for (Mote m: simulation.getMotes()) {
|
||||
if (moteDescription.equals(m.toString())) {
|
||||
foundMote = true;
|
||||
dest = m;
|
||||
dest = m.getInterfaces().getRadio();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -418,14 +457,19 @@ public class DirectedGraphMedium extends AbstractRadioMedium {
|
|||
}
|
||||
|
||||
if (element.getName().equals("ratio")) {
|
||||
successRatio = Double.parseDouble(element.getText());
|
||||
ratio = Double.parseDouble(element.getText());
|
||||
}
|
||||
|
||||
if (element.getName().equals("delay")) {
|
||||
delay = Long.parseLong(element.getText());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ratio < 0 || delay < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
superDest = new DGRMDestinationRadio(dest, ratio, delay);
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.util.*;
|
||||
import org.jdom.Element;
|
||||
import org.apache.log4j.Logger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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.interfaces.*;
|
||||
import se.sics.cooja.interfaces.Position;
|
||||
import se.sics.cooja.interfaces.Radio;
|
||||
import se.sics.cooja.plugins.Visualizer;
|
||||
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
|
||||
* transmitting and one for interfering other transmissions.
|
||||
* The Unit Disk Graph Radio Medium abstracts radio transmission range as circles.
|
||||
*
|
||||
* The radio medium supports both byte and packet radios.
|
||||
* It uses two different range parameters: one for transmissions, and one for
|
||||
* interfering with other radios and transmissions.
|
||||
*
|
||||
* 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.
|
||||
* Both radio ranges grow with the radio output power indicator.
|
||||
* The range parameters are multiplied with [output power]/[maximum output power].
|
||||
* 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
|
||||
* range becomes 50m.
|
||||
*
|
||||
* The radio output power indicator (0-100) is used in a very simple way; the
|
||||
* 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_WEAK
|
||||
* @see #SS_NOTHING
|
||||
*
|
||||
* @see UDGMVisualizerSkin
|
||||
* @see DirectedGraphMedium, UDGMVisualizerSkin
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
@ClassDescription("Unit Disk Graph Medium (UDGM)")
|
||||
public class UDGM extends AbstractRadioMedium {
|
||||
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_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 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;
|
||||
|
||||
public UDGM(Simulation 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 */
|
||||
/* TODO Should be unregistered when radio medium is removed */
|
||||
/* Register as position observer.
|
||||
* 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);
|
||||
|
||||
mySimulation = simulation;
|
||||
random = mySimulation.getRandomGenerator();
|
||||
}
|
||||
|
||||
public RadioConnection createConnections(Radio sendingRadio) {
|
||||
Position sendingPosition = sendingRadio.getPosition();
|
||||
RadioConnection newConnection = new RadioConnection(sendingRadio);
|
||||
public void setTxRange(double r) {
|
||||
TRANSMITTING_RANGE = r;
|
||||
dgrm.requestEdgeAnalysis();
|
||||
}
|
||||
|
||||
// Fetch current output power indicator (scale with as percent)
|
||||
double moteTransmissionRange = TRANSMITTING_RANGE
|
||||
* ((double) sendingRadio.getCurrentOutputPowerIndicator() / (double) sendingRadio.getOutputPowerIndicatorMax());
|
||||
double moteInterferenceRange = INTERFERENCE_RANGE
|
||||
* ((double) sendingRadio.getCurrentOutputPowerIndicator() / (double) sendingRadio.getOutputPowerIndicatorMax());
|
||||
public void setInterferenceRange(double r) {
|
||||
INTERFERENCE_RANGE = r;
|
||||
dgrm.requestEdgeAnalysis();
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
return newConnection;
|
||||
}
|
||||
|
||||
// Loop through all radios
|
||||
for (int listenNr = 0; listenNr < getRegisteredRadios().size(); listenNr++) {
|
||||
Radio listeningRadio = getRegisteredRadios().get(listenNr);
|
||||
Position listeningRadioPosition = listeningRadio.getPosition();
|
||||
/* Calculate ranges: grows with radio output power */
|
||||
double moteTransmissionRange = TRANSMITTING_RANGE
|
||||
* ((double) sender.getCurrentOutputPowerIndicator() / (double) sender.getOutputPowerIndicatorMax());
|
||||
double moteInterferenceRange = INTERFERENCE_RANGE
|
||||
* ((double) sender.getCurrentOutputPowerIndicator() / (double) sender.getOutputPowerIndicatorMax());
|
||||
|
||||
// Ignore sending radio and radios on different channels
|
||||
if (sendingRadio == listeningRadio) {
|
||||
/* Get all potential destination radios */
|
||||
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;
|
||||
}
|
||||
if (sendingRadio.getChannel() >= 0 &&
|
||||
listeningRadio.getChannel() >= 0 &&
|
||||
sendingRadio.getChannel() != listeningRadio.getChannel()) {
|
||||
continue;
|
||||
}
|
||||
if (!listeningRadio.isReceiverOn()) {
|
||||
|
||||
/* Fail if radio is turned off */
|
||||
if (!recv.isReceiverOn()) {
|
||||
/* Special case: allow connection if source is Contiki radio,
|
||||
* and destination is something else (byte radio).
|
||||
* Allows cross-level communication with power-saving MACs. */
|
||||
if (sendingRadio instanceof ContikiRadio &&
|
||||
!(listeningRadio instanceof ContikiRadio)) {
|
||||
if (sender instanceof ContikiRadio &&
|
||||
!(recv instanceof ContikiRadio)) {
|
||||
/*logger.info("Special case: creating connection to turned off radio");*/
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
double distance = sendingPosition.getDistanceTo(listeningRadioPosition);
|
||||
|
||||
double distance = senderPos.getDistanceTo(recvPos);
|
||||
if (distance <= moteTransmissionRange) {
|
||||
// Check if this radio is able to receive transmission
|
||||
if (listeningRadio.isInterfered()) {
|
||||
// Keep interfering radio
|
||||
newConnection.addInterfered(listeningRadio);
|
||||
/* Within transmission range */
|
||||
|
||||
} 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)) {
|
||||
newConnection.addInterfered(listeningRadio);
|
||||
/* Was receiving, or reception failed: start interfering */
|
||||
newConnection.addInterfered(recv);
|
||||
recv.interfereAnyReception();
|
||||
|
||||
// Start interfering radio
|
||||
listeningRadio.interfereAnyReception();
|
||||
|
||||
// Update connection that is transmitting to this radio
|
||||
RadioConnection existingConn = null;
|
||||
/* Interfere receiver in all other active radio connections */
|
||||
for (RadioConnection conn : getActiveConnections()) {
|
||||
for (Radio dstRadio : conn.getDestinations()) {
|
||||
if (dstRadio == listeningRadio) {
|
||||
existingConn = conn;
|
||||
if (dstRadio == recv) {
|
||||
conn.removeDestination(recv);
|
||||
conn.addInterfered(recv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (existingConn != null) {
|
||||
// Change radio from receiving to interfered
|
||||
existingConn.removeDestination(listeningRadio);
|
||||
existingConn.addInterfered(listeningRadio);
|
||||
|
||||
}
|
||||
} else {
|
||||
// Radio OK to receive
|
||||
newConnection.addDestination(listeningRadio);
|
||||
/* Success: radio starts receiving */
|
||||
newConnection.addDestination(recv);
|
||||
}
|
||||
} else if (distance <= moteInterferenceRange) {
|
||||
// Interfere radio
|
||||
newConnection.addInterfered(listeningRadio);
|
||||
listeningRadio.interfereAnyReception();
|
||||
/* Within interference range */
|
||||
newConnection.addInterfered(recv);
|
||||
recv.interfereAnyReception();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,20 +248,16 @@ public class UDGM extends AbstractRadioMedium {
|
|||
}
|
||||
|
||||
public void updateSignalStrengths() {
|
||||
// // Save old signal strengths
|
||||
// double[] oldSignalStrengths = new double[registeredRadios.size()];
|
||||
// for (int i = 0; i < registeredRadios.size(); i++) {
|
||||
// oldSignalStrengths[i] = registeredRadios.get(i)
|
||||
// .getCurrentSignalStrength();
|
||||
// }
|
||||
/* Override: uses distance as signal strength factor */
|
||||
|
||||
// Reset signal strength on all radios
|
||||
/* Reset signal strengths */
|
||||
for (Radio radio : getRegisteredRadios()) {
|
||||
radio.setCurrentSignalStrength(SS_NOTHING);
|
||||
}
|
||||
|
||||
// Set signal strength on all OK transmissions
|
||||
for (RadioConnection conn : getActiveConnections()) {
|
||||
/* Set signal strength to below strong on destinations */
|
||||
RadioConnection[] conns = getActiveConnections();
|
||||
for (RadioConnection conn : conns) {
|
||||
conn.getSource().setCurrentSignalStrength(SS_STRONG);
|
||||
for (Radio dstRadio : conn.getDestinations()) {
|
||||
double dist = conn.getSource().getPosition().getDistanceTo(dstRadio.getPosition());
|
||||
|
@ -205,8 +271,8 @@ public class UDGM extends AbstractRadioMedium {
|
|||
}
|
||||
}
|
||||
|
||||
// Set signal strength on all interferences
|
||||
for (RadioConnection conn : getActiveConnections()) {
|
||||
/* Set signal strength to below weak on interfered */
|
||||
for (RadioConnection conn : conns) {
|
||||
for (Radio intfRadio : conn.getInterfered()) {
|
||||
double dist = conn.getSource().getPosition().getDistanceTo(intfRadio.getPosition());
|
||||
|
||||
|
@ -222,37 +288,23 @@ public class UDGM extends AbstractRadioMedium {
|
|||
}
|
||||
|
||||
if (!intfRadio.isInterfered()) {
|
||||
// Set to interfered again
|
||||
logger.warn("Radio was not interfered: " + intfRadio);
|
||||
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() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
ArrayList<Element> config = new ArrayList<Element>();
|
||||
Element element;
|
||||
|
||||
// Transmitting range
|
||||
/* Transmitting range */
|
||||
element = new Element("transmitting_range");
|
||||
element.setText(Double.toString(TRANSMITTING_RANGE));
|
||||
config.add(element);
|
||||
|
||||
// Interference range
|
||||
/* Interference range */
|
||||
element = new Element("interference_range");
|
||||
element.setText(Double.toString(INTERFERENCE_RANGE));
|
||||
config.add(element);
|
||||
|
|
Loading…
Reference in a new issue