diff --git a/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java b/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java index 24f4b5189..4459d0e12 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java +++ b/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java @@ -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(), - ((Number)ratio.getValue()).doubleValue(), - ((Number)delay.getValue()).longValue() + ((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(), - ((Number)ratio.getValue()).doubleValue(), - ((Number)delay.getValue()).longValue() + ((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; } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java index 782143dc1..1c41f8475 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java @@ -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,12 +64,18 @@ import se.sics.cooja.interfaces.*; public abstract class AbstractRadioMedium extends RadioMedium { private static Logger logger = Logger.getLogger(AbstractRadioMedium.class); - private Vector registeredRadios = new Vector(); + /* 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 activeConnections = new Vector(); + private ArrayList registeredRadios = new ArrayList(); + + private ArrayList activeConnections = new ArrayList(); private RadioConnection lastConnection = null; - + private Simulation simulation = null; /* Book-keeping */ @@ -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 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,33 +171,39 @@ 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; + /* Connection source */ + 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) { conn.removeDestination(radio); conn.removeInterfered(radio); + } + } - if (conn.getSource() == radio) { - // Radio is currently transmitting - connToRemove = conn; - for (Radio dstRadio : conn.getDestinations()) { - dstRadio.interfereAnyReception(); - dstRadio.signalReceptionEnd(); - } - for (Radio dstRadio : conn.getInterfered()) { - dstRadio.signalReceptionEnd(); - } + private RadioConnection getActiveConnectionFrom(Radio source) { + for (RadioConnection conn : activeConnections) { + if (conn.getSource() == source) { + return conn; } } - if (connToRemove != null) { - activeConnections.remove(connToRemove); - } + return null; } /** @@ -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,153 +264,153 @@ 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 { - 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"); + logger.fatal("No radio connection found"); 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(); 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 (connection.getDestinationDelay(dstRadio) == 0) { - ((CustomDataRadio) dstRadio).receiveCustomData(data); - } else { - /* 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)); + 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 { + + /* 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) { - /* 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 (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)); - - } + 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 { + + /* 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 { 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 - registeredRadios.add(radio); - radio.addObserver(radioEventsObserver); - - // Set initial signal strength - updateSignalStrengths(); + if (radio == null) { + logger.warn("No radio to register"); + return; } + + registeredRadios.add(radio); + radio.addObserver(radioEventsObserver); + + /* 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) { diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java index 1e89076ec..5a0a66c8f 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java @@ -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 edges = new ArrayList(); + private boolean edgesDirty = true; + + /* Used for optimizing lookup time */ + private Hashtable edgesTable = new Hashtable(); + + 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 list = new ArrayList(); - 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 edgesTable = new Hashtable(); + 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> 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> listTable = new Hashtable>(); /* 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 destRadios; - if (!newTable.containsKey(edge.source.getInterfaces().getRadio())) { + if (!listTable.containsKey(edge.source)) { /* Create new source */ destRadios = new ArrayList(); } 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 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 newTable2 = new Hashtable(); - Enumeration sources = newTable.keys(); - while (sources.hasMoreElements()) { - Radio source = sources.nextElement(); - ArrayList list = newTable.get(source); - DestinationRadio[] arr = new DestinationRadio[list.size()]; - list.toArray(arr); - newTable2.put(source, arr); - } + Hashtable arrTable = + new Hashtable(); + Enumeration sources = listTable.keys(); + while (sources.hasMoreElements()) { + Radio source = sources.nextElement(); + DestinationRadio[] arr = + listTable.get(source).toArray(new DestinationRadio[0]); + arrTable.put(source, arr); + } - this.edgesTable = newTable2; - edgesDirty = false; + 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 getConfigXML() { - Vector config = new Vector(); + ArrayList config = new ArrayList(); 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 delayedLoadConfig = null; /* Used for restoring edges from config */ - public Collection getConfigXML() { + /* Internal methods */ + private Collection delayedLoadConfig = null; /* Used for restoring edges from config */ + private Collection getConfigXML() { Vector config = new Vector(); 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); - element = new Element("ratio"); - element.setText("" + successRatio); - config.add(element); + if (superDest instanceof DGRMDestinationRadio) { + element = new Element("ratio"); + element.setText("" + ((DGRMDestinationRadio)superDest).ratio); + config.add(element); - element = new Element("delay"); - element.setText("" + delay); - config.add(element); + element = new Element("delay"); + element.setText("" + ((DGRMDestinationRadio)superDest).delay); + config.add(element); + } return config; } - public boolean setConfigXML(Collection configXML, Simulation simulation) { + + private boolean setConfigXML(Collection 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; } } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java index d28d13cc7..2e1db8c4c 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java @@ -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 radio medium supports both byte and packet radios. - * - * 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. - * - * 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]%. + * The Unit Disk Graph Radio Medium abstracts radio transmission range as circles. + * + * It uses two different range parameters: one for transmissions, and one for + * interfering with other radios and transmissions. + * + * 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. + * + * 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 getConfigXML() { - Vector config = new Vector(); + ArrayList config = new ArrayList(); 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);