diff --git a/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java b/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java index ca81777a4..1409b95ba 100644 --- a/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java +++ b/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: DummyRadioMedium.java,v 1.2 2007/01/09 10:10:18 fros4943 Exp $ + * $Id: DummyRadioMedium.java,v 1.3 2007/02/28 09:51:11 fros4943 Exp $ */ import java.util.Collection; @@ -57,7 +57,7 @@ public class DummyRadioMedium extends RadioMedium { // Do nothing } - public void registerRadioInterface(Radio radio, Position position, Simulation sim) { + public void registerRadioInterface(Radio radio, Simulation sim) { // Do nothing logger.debug("I'm a dummy. Nothing will be registered by me."); } diff --git a/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java b/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java index d908a6232..fbaf178e2 100644 --- a/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java +++ b/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java @@ -26,14 +26,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: VisUAODV.java,v 1.2 2007/01/09 10:09:59 fros4943 Exp $ + * $Id: VisUAODV.java,v 1.3 2007/02/28 09:50:51 fros4943 Exp $ */ import java.awt.*; import org.apache.log4j.Logger; import se.sics.cooja.*; -import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.*; import se.sics.cooja.plugins.*; /** @@ -62,28 +62,32 @@ public class VisUAODV extends VisTraffic { } protected void paintConnection(RadioConnection connection, Graphics g2d) { - Point sourcePixelPosition = transformPositionToPixel(connection.getSourcePosition()); - for (Position destPosition: connection.getDestinationPositons()) { + Point sourcePixelPosition = transformPositionToPixel(connection.getSource().getPosition()); + for (Radio destRadio: connection.getDestinations()) { + Position destPosition = destRadio.getPosition(); Point destPixelPosition = transformPositionToPixel(destPosition); g2d.setColor(getColorOf(connection)); - if (isRouteReply(connection.getSourceData())) { + byte[] packet = ((PacketRadio)destRadio).getLastPacketReceived(); + if (isRouteReply(packet)) { ((Graphics2D) g2d).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); } g2d.drawLine(sourcePixelPosition.x, sourcePixelPosition.y, destPixelPosition.x, destPixelPosition.y); - int hopCount = getHopCount(connection.getSourceData()); + int hopCount = getHopCount(packet); if (hopCount >= 0) g2d.drawString("" + hopCount, sourcePixelPosition.x, sourcePixelPosition.y); } } protected Color getColorOf(RadioConnection conn) { - if (isRouteRequest(conn.getSourceData())) + byte[] packet = ((PacketRadio)conn.getSource()).getLastPacketReceived(); + + if (isRouteRequest(packet)) return Color.RED; - else if (isRouteReply(conn.getSourceData())) + else if (isRouteReply(packet)) return Color.GREEN; else return Color.BLACK; diff --git a/tools/cooja/java/se/sics/cooja/ConnectionLogger.java b/tools/cooja/java/se/sics/cooja/ConnectionLogger.java index 2d3fd64d1..f811f4a88 100644 --- a/tools/cooja/java/se/sics/cooja/ConnectionLogger.java +++ b/tools/cooja/java/se/sics/cooja/ConnectionLogger.java @@ -24,7 +24,7 @@ * (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: ConnectionLogger.java,v 1.4 2007/01/10 14:57:42 fros4943 Exp $ + * $Id: ConnectionLogger.java,v 1.5 2007/02/28 09:47:55 fros4943 Exp $ */ package se.sics.cooja; @@ -33,12 +33,14 @@ import java.io.File; import java.io.FileOutputStream; import org.apache.log4j.Logger; +import se.sics.cooja.interfaces.PacketRadio; import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; /** - * ConnectionLogger is a simple connection information outputter. All - * connections given via the method logConnection will be written to either - * default Log4J info stream, a log file or both. + * A connection logger is a simple connection information outputter. All + * connections given to it will be written to either the currently configured + * Log4J info stream, a log file or both. * * Log files have the following structure (seprated by tabs): SRC_POS [src_x] * [src_y] [src_z] SRC_DATA [sent data bytes] DEST_POS [dest_x] [dest_y] @@ -90,29 +92,29 @@ public class ConnectionLogger { * Connection to output */ public void logConnection(RadioConnection conn) { - if (myType == LOG_TO_LOG4J || myType == LOG_TO_FILE_AND_LOG4J) { - if (conn.getDestinationPositons() != null - && conn.getDestinationPositons().length > 0) - for (Position destPos : conn.getDestinationPositons()) { - logger.info("RADIODATA from " + conn.getSourcePosition() + " to " - + destPos + "\tsize:" + conn.getSourceData().length); + Radio[] destinations = conn.getDestinations(); + if (destinations != null && destinations.length > 0) { + for (Radio destRadio : destinations) { + logger.info("RADIODATA from " + conn.getSource().getPosition() + + " to " + destRadio.getPosition()); } - else - logger.info("RADIODATA from " + conn.getSourcePosition() + " to " - + "[NOWHERE]" + "\tsize:" + conn.getSourceData().length); + } else { + logger.info("RADIODATA from " + conn.getSource().getPosition() + + " to [NOWHERE]"); + } } - if (myType == LOG_TO_FILE || myType == LOG_TO_FILE_AND_LOG4J) { + if (myType == LOG_TO_FILE || myType == LOG_TO_FILE_AND_LOG4J) { try { FileOutputStream out = new FileOutputStream(myFile, true); - if (conn.getDestinationPositons() != null - && conn.getDestinationPositons().length > 0) { - for (int i = 0; i < conn.getDestinationPositons().length; i++) { + Radio[] destinations = conn.getDestinations(); + if (destinations != null && destinations.length > 0) { + for (int i = 0; i < destinations.length; i++) { // Source pos out.write("SRC_POS\t".getBytes()); - Position pos = conn.getSourcePosition(); + Position pos = conn.getSource().getPosition(); out.write(Double.toString(pos.getXCoordinate()).getBytes()); out.write("\t".getBytes()); out.write(Double.toString(pos.getYCoordinate()).getBytes()); @@ -122,7 +124,9 @@ public class ConnectionLogger { // Source data out.write("SRC_DATA\t".getBytes()); - for (byte b : conn.getSourceData()) { + // TODO We need to log destination data again... + for (byte b : ((PacketRadio) conn.getSource()) + .getLastPacketTransmitted()) { String hexString = Integer.toHexString((int) b); if (hexString.length() == 1) hexString = "0" + hexString; @@ -132,7 +136,7 @@ public class ConnectionLogger { // Destination pos out.write("DEST_POS\t".getBytes()); - pos = conn.getDestinationPositons()[i]; + pos = destinations[i].getPosition(); out.write(Double.toString(pos.getXCoordinate()).getBytes()); out.write("\t".getBytes()); out.write(Double.toString(pos.getYCoordinate()).getBytes()); @@ -142,7 +146,9 @@ public class ConnectionLogger { // Source data out.write("DEST_DATA\t".getBytes()); - for (byte b : conn.getDestinationData()[i]) { + // TODO We need to log destination data again... + for (byte b : ((PacketRadio) destinations[i]) + .getLastPacketReceived()) { String hexString = Integer.toHexString((int) b); if (hexString.length() == 1) hexString = "0" + hexString; @@ -156,7 +162,7 @@ public class ConnectionLogger { } else { // Source pos out.write("SRC_POS\t".getBytes()); - Position pos = conn.getSourcePosition(); + Position pos = conn.getSource().getPosition(); out.write(Double.toString(pos.getXCoordinate()).getBytes()); out.write("\t".getBytes()); out.write(Double.toString(pos.getYCoordinate()).getBytes()); @@ -166,12 +172,16 @@ public class ConnectionLogger { // Source data out.write("SRC_DATA\t".getBytes()); - for (byte b : conn.getSourceData()) { + // TODO We need to log destination data again... + for (byte b : ((PacketRadio) conn.getSource()) + .getLastPacketTransmitted()) { String hexString = Integer.toHexString((int) b); if (hexString.length() == 1) hexString = "0" + hexString; out.write(hexString.getBytes()); } + out.write("\t".getBytes()); + out.write("[NOWHERE]".getBytes()); out.write("\n".getBytes()); } out.close(); diff --git a/tools/cooja/java/se/sics/cooja/RadioConnection.java b/tools/cooja/java/se/sics/cooja/RadioConnection.java index da1ec346b..2ac2db471 100644 --- a/tools/cooja/java/se/sics/cooja/RadioConnection.java +++ b/tools/cooja/java/se/sics/cooja/RadioConnection.java @@ -26,139 +26,121 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: RadioConnection.java,v 1.3 2006/10/09 13:38:38 fros4943 Exp $ + * $Id: RadioConnection.java,v 1.4 2007/02/28 09:47:55 fros4943 Exp $ */ package se.sics.cooja; import java.util.Vector; -import se.sics.cooja.interfaces.Position; import se.sics.cooja.interfaces.Radio; /** - * RadioConnection represents a radio connection between a sending radio - * and zero or more receiving radios. - * By registering as an observer to the current radio medium, all - * radio connections and data sent in that medium can be accessed. - * - * Each radio is associated with a position and some radio data. - * Often the destinations' and source's data will refer to the same object, - * but some radio mediums may want to distort the transferred data, hence - * resulting in different data sent and received. - * + * A radio connection represents a connection between a source radio and zero or + * more destination and interfered radios. Typically the destinations are able + * to receive data sent by the source radio, and the interfered radios are not. + * * @see RadioMedium * @author Fredrik Osterlind */ public class RadioConnection { - private Radio sourceRadio; - private Position sourcePosition; - private byte[] sourceData; + private Radio source; - private Vector destinationRadios = new Vector(); - private Vector destinationPositions = new Vector(); - private Vector destinationData = new Vector(); + private Vector destinations = new Vector(); + + private Vector interfered = new Vector(); + + /** + * Creates a new radio connection with given source and no destinations. + * + * @param sourceRadio + * Source radio + */ + public RadioConnection(Radio sourceRadio) { + this.source = sourceRadio; + } /** * Set source of this connection. - * - * @param radio Source radio - * @param position Source position - * @param data Source data + * + * @param radio + * Source radio */ - public void setSource(Radio radio, Position position, byte[] data) { - sourceRadio = radio; - sourcePosition = position; - sourceData = data; + public void setSource(Radio radio) { + source = radio; } /** - * Add a connection destination. - * - * @param radio Source radio - * @param position Source position - * @param data Source data + * Adds destination radio. + * + * @param radio + * Radio */ - public void addDestination(Radio radio, Position position, byte[] data) { - destinationRadios.add(radio); - destinationPositions.add(position); - destinationData.add(data); + public void addDestination(Radio radio) { + destinations.add(radio); } - + /** - * Remove a connection destination. - * - * @param radio Destination to remove + * Adds interfered radio. + * + * @param radio + * Radio + */ + public void addInterfered(Radio radio) { + interfered.add(radio); + } + + /** + * Removes destination radio. + * + * @param radio + * Radio */ public void removeDestination(Radio radio) { - int pos = destinationRadios.indexOf(radio); - if (pos >= 0) { - destinationRadios.remove(pos); - destinationPositions.remove(pos); - destinationData.remove(pos); - } + destinations.remove(radio); + } + + /** + * Removes interfered radio. + * + * @param radio + * Radio + */ + public void removeInterfered(Radio radio) { + interfered.remove(radio); } /** * @return Source radio */ - public Radio getSourceRadio() { - return sourceRadio; + public Radio getSource() { + return source; } /** - * @return Source position + * @return All destinations of this connection */ - public Position getSourcePosition() { - return sourcePosition; - } - - /** - * Returns the data actually sent by source radio. - * @return Source data - */ - public byte[] getSourceData() { - return sourceData; - } - - /** - * @return Array of destination radios - */ - public Radio[] getDestinationRadios() { + public Radio[] getDestinations() { Radio[] radioArrayType; Radio[] radioArray; - radioArrayType = new Radio[destinationRadios.size()]; - radioArray = (Radio[]) destinationRadios.toArray(radioArrayType); + radioArrayType = new Radio[destinations.size()]; + radioArray = (Radio[]) destinations.toArray(radioArrayType); return radioArray; } /** - * @return Array of destination positions + * @return All radios interfered by this connection */ - public Position[] getDestinationPositons() { - Position[] positionArrayType; - Position[] positionArray; + public Radio[] getInterfered() { + Radio[] radioArrayType; + Radio[] radioArray; - positionArrayType = new Position[destinationPositions.size()]; - positionArray = (Position[]) destinationPositions.toArray(positionArrayType); + radioArrayType = new Radio[interfered.size()]; + radioArray = (Radio[]) interfered.toArray(radioArrayType); - return positionArray; - } - - /** - * Returns an array of data actually received by each radio. - * @return Array of destination data - */ - public byte[][] getDestinationData() { - byte[][] dataArrayType; - byte[][] dataArray; - - dataArrayType = new byte[destinationData.size()][]; - dataArray = (byte[][]) destinationData.toArray(dataArrayType); - - return dataArray; + return radioArray; } } diff --git a/tools/cooja/java/se/sics/cooja/RadioMedium.java b/tools/cooja/java/se/sics/cooja/RadioMedium.java index 612751052..d85b5c25c 100644 --- a/tools/cooja/java/se/sics/cooja/RadioMedium.java +++ b/tools/cooja/java/se/sics/cooja/RadioMedium.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: RadioMedium.java,v 1.4 2007/01/10 14:57:42 fros4943 Exp $ + * $Id: RadioMedium.java,v 1.5 2007/02/28 09:47:45 fros4943 Exp $ */ package se.sics.cooja; @@ -36,7 +36,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.*; import org.jdom.Element; -import se.sics.cooja.interfaces.Position; import se.sics.cooja.interfaces.Radio; /** @@ -79,7 +78,7 @@ public abstract class RadioMedium { public abstract void unregisterMote(Mote mote, Simulation sim); /** - * Register a radio to this medium at a given position. + * Register a radio to this radio medium. * * Concerning radio data, this radio will be treated the same way as a mote's * radio. This method can be used to add non-mote radio devices, such as a @@ -87,16 +86,13 @@ public abstract class RadioMedium { * * @param radio * Radio - * @param position - * Position * @param sim * Simulation holding radio */ - public abstract void registerRadioInterface(Radio radio, Position position, - Simulation sim); + public abstract void registerRadioInterface(Radio radio, Simulation sim); /** - * Unregisters a radio interface from this medium. + * Unregister given radio interface from this medium. * * @param radio * Radio interface to unregister diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java index 9d1312995..678346425 100644 --- a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ContikiRadio.java,v 1.10 2007/01/09 10:05:19 fros4943 Exp $ + * $Id: ContikiRadio.java,v 1.11 2007/02/28 09:48:48 fros4943 Exp $ */ package se.sics.cooja.contikimote.interfaces; @@ -39,6 +39,8 @@ import org.jdom.Element; import se.sics.cooja.*; import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.PacketRadio; +import se.sics.cooja.interfaces.Position; import se.sics.cooja.interfaces.Radio; /** @@ -46,9 +48,9 @@ import se.sics.cooja.interfaces.Radio; * transmission rates, the underlying Contiki system can be locked in either * transmission or reception states (using multi-threading). When a transmission * is initiated, it will automatically lock the Contiki system. When a packet is - * received by this radio the Contiki system, the entitiy transfering the packet may explicitly - * lock the radio in receiving mode. After some time it should then deliver the - * packet. + * received by this radio the Contiki system, the entitiy transferring the + * packet may explicitly lock the radio in receiving mode. After some time it + * should then deliver the packet. * * It needs read/write access to the following core variables: *
    @@ -64,7 +66,7 @@ import se.sics.cooja.interfaces.Radio; *
  • char simRadioHWOn (radio hardware status (on/off)) *
  • int simSignalStrength (heard radio signal strength) *
  • char simPower (number indicating power output) - *
  • int simRadioChannel + *
  • int simRadioChannel (number indicating current channel) *
*

* Dependency core interfaces are: @@ -75,9 +77,12 @@ import se.sics.cooja.interfaces.Radio; * * @author Fredrik Osterlind */ -public class ContikiRadio extends Radio implements ContikiMoteInterface { +public class ContikiRadio extends Radio implements ContikiMoteInterface, + PacketRadio { private Mote myMote; + private SectionMoteMemory myMoteMemory; + private static Logger logger = Logger.getLogger(ContikiRadio.class); /** @@ -98,17 +103,18 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { private double myEnergyConsumption = 0.0; - private boolean transmitting = false; + private boolean isTransmitting = false; + + private boolean isInterfered = false; private int transmissionEndTime = -1; - private int interferenceEndTime = -1; - private int receptionEndTime = -1; private RadioEvent lastEvent = RadioEvent.UNKNOWN; + private int lastEventTime = 0; - + private int oldOutputPowerIndicator = -1; - + /** * Creates an interface to the radio at mote. * @@ -135,10 +141,12 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { radioOn = myMoteMemory.getByteValueOf("simRadioHWOn") == 1; } + /* Contiki mote interface support */ public static String[] getCoreInterfaceDependencies() { return new String[] { "radio_interface" }; } + /* Packet radio support */ public byte[] getLastPacketTransmitted() { return packetFromMote; } @@ -146,30 +154,110 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { public byte[] getLastPacketReceived() { return packetToMote; } - - public boolean isTransmitting() { - return transmitting; + + public void setReceivedPacket(byte[] data) { + packetToMote = data; } - public int getTransmissionEndTime() { - return transmissionEndTime; + /* General radio support */ + public boolean isTransmitting() { + return isTransmitting; } - + public boolean isReceiving() { if (isLockedAtReceiving()) return true; - + return myMoteMemory.getIntValueOf("simInSize") != 0; } + public boolean isInterfered() { + return isInterfered; + } + public int getChannel() { return myMoteMemory.getIntValueOf("simRadioChannel"); } - + + public void signalReceptionStart() { + packetToMote = null; + if (isInterfered() || isReceiving() || isTransmitting()) { + interfereAnyReception(); + return; + } + lockInReceivingMode(); + + lastEventTime = myMote.getSimulation().getSimulationTime(); + lastEvent = RadioEvent.RECEPTION_STARTED; + this.setChanged(); + this.notifyObservers(); + } + + public void signalReceptionEnd() { + if (isInterfered() || packetToMote == null) { + // Reset interfered flag + isInterfered = false; + + // Reset data + packetToMote = null; + myMoteMemory.setIntValueOf("simInSize", 0); + + // Unlock (if locked) + myMoteMemory.setByteValueOf("simReceiving", (byte) 0); + + return; + } + + // Unlock (if locked) + myMoteMemory.setByteValueOf("simReceiving", (byte) 0); + + // Set data + myMoteMemory.setIntValueOf("simInSize", packetToMote.length); + myMoteMemory.setByteArray("simInDataBuffer", packetToMote); + + lastEventTime = myMote.getSimulation().getSimulationTime(); + lastEvent = RadioEvent.RECEPTION_FINISHED; + this.setChanged(); + this.notifyObservers(); + } + public RadioEvent getLastEvent() { return lastEvent; } - + + public void interfereAnyReception() { + if (!isInterfered()) { + isInterfered = true; + + lastEvent = RadioEvent.RECEPTION_INTERFERED; + lastEventTime = myMote.getSimulation().getSimulationTime(); + this.setChanged(); + this.notifyObservers(); + } + } + + public double getCurrentOutputPower() { + // TODO Implement method + logger.warn("Not implemeted, always returning 1.5 dBm"); + return 1.5; + } + + public int getCurrentOutputPowerIndicator() { + return (int) myMoteMemory.getByteValueOf("simPower"); + } + + public double getCurrentSignalStrength() { + return myMoteMemory.getIntValueOf("simSignalStrength"); + } + + public void setCurrentSignalStrength(double signalStrength) { + myMoteMemory.setIntValueOf("simSignalStrength", (int) signalStrength); + } + + public Position getPosition() { + return myMote.getInterfaces().getPosition(); + } + /** * @return True if locked at transmitting */ @@ -201,98 +289,9 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { // Lock core radio in receiving loop myMoteMemory.setByteValueOf("simReceiving", (byte) 1); - - lastEventTime = myMote.getSimulation().getSimulationTime(); - lastEvent = RadioEvent.RECEPTION_STARTED; - this.setChanged(); - this.notifyObservers(); } - public void receivePacket(byte[] data, int endTime) { - if (isInterfered() || isReceiving() || isTransmitting()) { - interferReception(endTime); - return; - } - - lockInReceivingMode(); - - receptionEndTime = endTime; - packetToMote = data; - } - - private void deliverPacket() { - // If mote is inactive, try to wake it up - if (myMote.getState() != Mote.State.ACTIVE) { - if (RAISES_EXTERNAL_INTERRUPT) - myMote.setState(Mote.State.ACTIVE); - if (myMote.getState() != Mote.State.ACTIVE) { - logger.fatal("Mote fell asleep during reception of packet, skipping packet!"); - myMoteMemory.setByteValueOf("simReceiving", (byte) 0); - myMoteMemory.setIntValueOf("simInSize", 0); - this.setChanged(); - this.notifyObservers(); - return; - } - } - - // Unlock (if locked) - myMoteMemory.setByteValueOf("simReceiving", (byte) 0); - - // Set data - myMoteMemory.setIntValueOf("simInSize", packetToMote.length); - myMoteMemory.setByteArray("simInDataBuffer", packetToMote); - - lastEventTime = myMote.getSimulation().getSimulationTime(); - lastEvent = RadioEvent.RECEPTION_FINISHED; - this.setChanged(); - this.notifyObservers(); - } - - public void interferReception(int endTime) { - // Unlock (if locked) - myMoteMemory.setByteValueOf("simReceiving", (byte) 0); - - // Reset data - myMoteMemory.setIntValueOf("simInSize", 0); - - // Save interference end time (if updated) - interferenceEndTime = Math.max(interferenceEndTime, endTime); - - if (lastEvent != RadioEvent.RECEPTION_INTERFERED) { - lastEvent = RadioEvent.RECEPTION_INTERFERED; - lastEventTime = myMote.getSimulation().getSimulationTime(); - this.setChanged(); - this.notifyObservers(); - } - } - - public boolean isInterfered() { - return interferenceEndTime >= myMote.getSimulation().getSimulationTime(); - } - - public double getCurrentOutputPower() { - // TODO Implement method - logger.warn("Not implemeted, always returning 1.5 dBm"); - return 1.5; - } - - public int getCurrentOutputPowerIndicator() { - return (int) myMoteMemory.getByteValueOf("simPower"); - } - - public double getCurrentSignalStrength() { - return myMoteMemory.getIntValueOf("simSignalStrength"); - } - - public void setCurrentSignalStrength(double signalStrength) { - myMoteMemory.setIntValueOf("simSignalStrength", (int) signalStrength); - } - public void doActionsBeforeTick() { - // Check if we need to release Contiki lock and deliver packet data - if (isLockedAtReceiving() && myMote.getSimulation().getSimulationTime() >= receptionEndTime) { - deliverPacket(); - } } public void doActionsAfterTick() { @@ -300,18 +299,18 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { if (radioOn != (myMoteMemory.getByteValueOf("simRadioHWOn") == 1)) { // Radio changed radioOn = !radioOn; - + if (!radioOn) { // Reset status myMoteMemory.setByteValueOf("simReceiving", (byte) 0); - myMoteMemory.setIntValueOf("simInSize", 0); + myMoteMemory.setIntValueOf("simInSize", 0); myMoteMemory.setByteValueOf("simTransmitting", (byte) 0); - myMoteMemory.setIntValueOf("simOutSize", 0); - transmitting = false; + myMoteMemory.setIntValueOf("simOutSize", 0); + isTransmitting = false; lastEvent = RadioEvent.HW_OFF; } else lastEvent = RadioEvent.HW_ON; - + lastEventTime = myMote.getSimulation().getSimulationTime(); this.setChanged(); this.notifyObservers(); @@ -325,26 +324,28 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { // Check if radio output power changed if (myMoteMemory.getByteValueOf("simPower") != oldOutputPowerIndicator) { oldOutputPowerIndicator = myMoteMemory.getByteValueOf("simPower"); + lastEvent = RadioEvent.UNKNOWN; this.setChanged(); this.notifyObservers(); } - + // Are we transmitting but should stop? - if (transmitting && myMote.getSimulation().getSimulationTime() >= transmissionEndTime) { + if (isTransmitting + && myMote.getSimulation().getSimulationTime() >= transmissionEndTime) { myMoteMemory.setByteValueOf("simTransmitting", (byte) 0); myMoteMemory.setIntValueOf("simOutSize", 0); - transmitting = false; - + isTransmitting = false; + lastEventTime = myMote.getSimulation().getSimulationTime(); lastEvent = RadioEvent.TRANSMISSION_FINISHED; // TODO Energy consumption of transmitted packet? this.setChanged(); this.notifyObservers(); } - + // Check if a new transmission should be started - if (!transmitting && myMoteMemory.getByteValueOf("simTransmitting") == 1) { - transmitting = true; + if (!isTransmitting && myMoteMemory.getByteValueOf("simTransmitting") == 1) { + isTransmitting = true; int size = myMoteMemory.getIntValueOf("simOutSize"); packetFromMote = myMoteMemory.getByteArray("simOutDataBuffer", size); @@ -353,11 +354,17 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { int duration = (int) ((2 * size * 9) / 19.2); // ms transmissionEndTime = myMote.getSimulation().getSimulationTime() + Math.max(1, duration); - + lastEventTime = myMote.getSimulation().getSimulationTime(); + lastEvent = RadioEvent.TRANSMISSION_STARTED; this.setChanged(); this.notifyObservers(); + + // Deliver packet right away + lastEvent = RadioEvent.PACKET_TRANSMITTED; + this.setChanged(); + this.notifyObservers(); } } @@ -365,23 +372,24 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { // Location JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - + final JLabel statusLabel = new JLabel(""); final JLabel lastEventLabel = new JLabel(""); final JLabel ssLabel = new JLabel(""); final JButton updateButton = new JButton("Update SS"); - + panel.add(statusLabel); panel.add(lastEventLabel); panel.add(ssLabel); panel.add(updateButton); - + updateButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - ssLabel.setText("Signal strength (not auto-updated): " + getCurrentSignalStrength() + " dBm"); + ssLabel.setText("Signal strength (not auto-updated): " + + getCurrentSignalStrength() + " dBm"); } }); - + Observer observer; this.addObserver(observer = new Observer() { public void update(Observable obs, Object obj) { @@ -394,19 +402,21 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { else statusLabel.setText("HW turned off"); - lastEventLabel.setText("Last event (time=" + lastEventTime + "): " + lastEvent); - ssLabel.setText("Signal strength (not auto-updated): " + getCurrentSignalStrength() + " dBm"); + lastEventLabel.setText("Last event (time=" + lastEventTime + "): " + + lastEvent); + ssLabel.setText("Signal strength (not auto-updated): " + + getCurrentSignalStrength() + " dBm"); } }); observer.update(null, null); - + // Saving observer reference for releaseInterfaceVisualizer panel.putClientProperty("intf_obs", observer); - - return panel; + + return panel; } - + public void releaseInterfaceVisualizer(JPanel panel) { Observer observer = (Observer) panel.getClientProperty("intf_obs"); if (observer == null) { @@ -416,7 +426,7 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { this.deleteObserver(observer); } - + public double energyConsumptionPerTick() { return myEnergyConsumption; } @@ -424,7 +434,7 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface { public Collection getConfigXML() { return null; } - + public void setConfigXML(Collection configXML, boolean visAvailable) { } diff --git a/tools/cooja/java/se/sics/cooja/interfaces/ByteRadio.java b/tools/cooja/java/se/sics/cooja/interfaces/ByteRadio.java new file mode 100644 index 000000000..3c5802d96 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/ByteRadio.java @@ -0,0 +1,41 @@ +package se.sics.cooja.interfaces; + +/** + * A byte radio is able to transmit and receive radio data on a byte level. + * + * The byte radio is a lower abstraction level than the packet radio and should, + * according to the bottom-up abstraction policy, implement the packet + * abstraction level. + * + * @author Fredrik Osterlind + */ +public interface ByteRadio extends PacketRadio { + + /** + * Radio receives given byte. + * + * @param b + * Byte + * @param timestamp + * Timestamp information + */ + public void receiveByte(byte b, long timestamp); + + /** + * @return Last byte transmitted by radio + */ + public byte getLastByteTransmitted(); + + /** + * Returns timestamp information of byte transmitted. This may for example be + * the number of cycles since transmission started. + * + * @return Timestamp info + */ + public long getLastByteTransmittedTimestamp(); + + /** + * @return Last byte received by radio + */ + public byte getLastByteReceived(); +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/PacketRadio.java b/tools/cooja/java/se/sics/cooja/interfaces/PacketRadio.java new file mode 100644 index 000000000..cd799464b --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/PacketRadio.java @@ -0,0 +1,33 @@ +package se.sics.cooja.interfaces; + +/** + * A packet radio is able to transmit and receive radio data on a packet level. + * + * The packet radio is the highest abstraction level of radios, and must + * therefore be implemented by all lower abstraction levels. + * + * @author Fredrik Osterlind + */ +public interface PacketRadio { + + /** + * Sets the packet data that is being received during a connection. Different + * radio may handle the data differently, but as a general rule this data + * should be supplied as soon as possible. + * + * @param p + * Packet dat + */ + public void setReceivedPacket(byte[] p); + + /** + * @return Last packet transmitted by radio + */ + public byte[] getLastPacketTransmitted(); + + /** + * @return Last packet received by radio + */ + public byte[] getLastPacketReceived(); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java index a4072d80e..80aae6974 100644 --- a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java +++ b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java @@ -24,7 +24,7 @@ * (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: Radio.java,v 1.5 2006/10/11 15:13:57 fros4943 Exp $ + * $Id: Radio.java,v 1.6 2007/02/28 09:49:20 fros4943 Exp $ */ package se.sics.cooja.interfaces; @@ -32,8 +32,15 @@ package se.sics.cooja.interfaces; import se.sics.cooja.*; /** - * A Radio represents a mote radio transceiver. An implementation should notify - * all observers both when packets are received and transmitted. + * A Radio represents a mote radio transceiver. + * + * A radio can support different abstraction levels such as transmitting and + * receiving on a byte or packet-basis. In order to support communication + * between different levels the general rule in COOJA is that all radios at a + * lower abstraction level must also implement all higher levels. + * + * @see PacketRadio + * @see ByteRadio * * @author Fredrik Osterlind */ @@ -44,84 +51,65 @@ public abstract class Radio extends MoteInterface { * Events that radios should notify observers about. */ public enum RadioEvent { - UNKNOWN, - HW_OFF, HW_ON, - RECEPTION_STARTED, RECEPTION_INTERFERED, RECEPTION_FINISHED, - TRANSMISSION_STARTED, TRANSMISSION_FINISHED + UNKNOWN, HW_OFF, HW_ON, RECEPTION_STARTED, RECEPTION_FINISHED, RECEPTION_INTERFERED, TRANSMISSION_STARTED, TRANSMISSION_FINISHED, PACKET_TRANSMITTED, BYTE_TRANSMITTED } /** - * Returns last significant event at this radio. Method may for example be - * used to learn the reason when a radio notifies a change to observers. + * Signal that a new reception just begun. This method should normally be + * called from the radio medium. + * + * @see #signalReceptionEnd() + */ + public abstract void signalReceptionStart(); + + /** + * Signal that the current reception was ended. This method should normally be + * called from the radio medium. + * + * @see #signalReceptionStart() + */ + public abstract void signalReceptionEnd(); + + /** + * Returns last event at this radio. This method should be used to learn the + * reason when a radio notifies a change to observers. * * @return Last radio event */ public abstract RadioEvent getLastEvent(); - /** - * @return Last packet data transmitted, or currently being transmitted, from - * this radio. - */ - public abstract byte[] getLastPacketTransmitted(); - - /** - * @return Last packet data received, or currently being received, by this - * radio. - */ - public abstract byte[] getLastPacketReceived(); - - /** - * Receive given packet. If reception is not interfered during - * this time, the packet will be delivered ok. - * - * @param data - * Packet data - * @param endTime - * Time (ms) when reception is finished - */ - public abstract void receivePacket(byte[] data, int endTime); - /** * Returns true if this radio is transmitting, or just finished transmitting, * data. * - * @see #getLastPacketTransmitted() + * @see #isReceiving() * @return True if radio is transmitting data */ public abstract boolean isTransmitting(); - /** - * @return Transmission end time if any transmission active - */ - public abstract int getTransmissionEndTime(); - /** * Returns true if this radio is receiving data. * - * @see #getLastPacketReceived() + * @see #isTransmitting() * @return True if radio is receiving data */ public abstract boolean isReceiving(); /** - * If a packet is being received, it will be interfered and dropped. The - * interference will continue until the given time, during which no other - * radio traffic may be received. This method can be used to simulate - * significant interference during transmissions. - * - * @param endTime - * Time when interference stops - */ - public abstract void interferReception(int endTime); - - /** - * Returns true is this radio is currently hearing noise from another - * transmission. + * Returns true if this radio had a connection that was dropped due to + * interference. * * @return True if this radio is interfered */ public abstract boolean isInterfered(); - + + /** + * Interferes with any current reception. If this method is called, the packet + * will be dropped. This method can be used to simulate radio interference + * such as high background noise. + */ + public abstract void interfereAnyReception(); + /** * @return Current output power (dBm) */ @@ -138,7 +126,8 @@ public abstract class Radio extends MoteInterface { public abstract double getCurrentSignalStrength(); /** - * Sets surrounding signal strength. + * Sets surrounding signal strength. This method should normally be called by + * the radio medium. * * @param signalStrength * Current surrounding signal strength @@ -151,5 +140,13 @@ public abstract class Radio extends MoteInterface { * @return Current channel number */ public abstract int getChannel(); + + /** + * Returns the radio position. + * This is typically the position of the mote. + * + * @return Radio position + */ + public abstract Position getPosition(); } diff --git a/tools/cooja/java/se/sics/cooja/motes/DisturberRadio.java b/tools/cooja/java/se/sics/cooja/motes/DisturberRadio.java index 7fbf36e67..3eed1cc44 100644 --- a/tools/cooja/java/se/sics/cooja/motes/DisturberRadio.java +++ b/tools/cooja/java/se/sics/cooja/motes/DisturberRadio.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: DisturberRadio.java,v 1.2 2007/01/09 10:01:14 fros4943 Exp $ + * $Id: DisturberRadio.java,v 1.3 2007/02/28 09:49:48 fros4943 Exp $ */ package se.sics.cooja.motes; @@ -40,14 +40,14 @@ import org.apache.log4j.Logger; import org.jdom.Element; import se.sics.cooja.*; -import se.sics.cooja.interfaces.Radio; +import se.sics.cooja.interfaces.*; /** * This radio periodically transmits data on a configurable channel. * * @author Fredrik Osterlind, Thiemo Voigt */ -public class DisturberRadio extends Radio { +public class DisturberRadio extends Radio implements PacketRadio { private Mote myMote; private static Logger logger = Logger.getLogger(DisturberRadio.class); @@ -78,7 +78,8 @@ public class DisturberRadio extends Radio { public DisturberRadio(Mote mote) { this.myMote = mote; } - + + /* Packet radio support */ public byte[] getLastPacketTransmitted() { return packetFromMote; } @@ -87,6 +88,17 @@ public class DisturberRadio extends Radio { return null; } + public void setReceivedPacket(byte[] data) { + } + + + /* General radio support */ + public void signalReceptionStart() { + } + + public void signalReceptionEnd() { + } + public boolean isTransmitting() { return transmitting; } @@ -96,8 +108,6 @@ public class DisturberRadio extends Radio { } public boolean isReceiving() { - if (isLockedAtReceiving()) - return true; return false; } @@ -105,21 +115,15 @@ public class DisturberRadio extends Radio { return distChannel; } + public Position getPosition() { + return myMote.getInterfaces().getPosition(); + } + public RadioEvent getLastEvent() { return lastEvent; } - /** - * @return True if locked at receiving - */ - private boolean isLockedAtReceiving() { - return false; - } - - public void receivePacket(byte[] data, int endTime) { - } - - public void interferReception(int endTime) { + public void interfereAnyReception() { } public boolean isInterfered() { diff --git a/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java b/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java index 189e1202c..c89796685 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java +++ b/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: VisTraffic.java,v 1.5 2007/01/09 09:49:24 fros4943 Exp $ + * $Id: VisTraffic.java,v 1.6 2007/02/28 09:50:00 fros4943 Exp $ */ package se.sics.cooja.plugins; @@ -38,6 +38,7 @@ import org.apache.log4j.Logger; import se.sics.cooja.*; import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; /** * A Traffic Visualizer visualizes radio traffic by painting lines between @@ -124,11 +125,10 @@ public class VisTraffic extends Visualizer2D { * Graphics to paint on */ protected void paintConnection(PaintedConnection connection, Graphics g2d) { - Point sourcePixelPosition = transformPositionToPixel(connection.radioConnection - .getSourcePosition()); + Point sourcePixelPosition = transformPositionToPixel(connection.radioConnection.getSource().getPosition()); g2d.setColor(connection.getColor(simulation.isRunning())); - for (Position destPosition : connection.radioConnection - .getDestinationPositons()) { + for (Radio destRadio : connection.radioConnection.getDestinations()) { + Position destPosition = destRadio.getPosition(); Point destPixelPosition = transformPositionToPixel(destPosition); g2d.drawLine(sourcePixelPosition.x, sourcePixelPosition.y, destPixelPosition.x, destPixelPosition.y); diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java index da50b553c..0decd511a 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: SilentRadioMedium.java,v 1.2 2007/01/09 09:47:10 fros4943 Exp $ + * $Id: SilentRadioMedium.java,v 1.3 2007/02/28 09:50:00 fros4943 Exp $ */ package se.sics.cooja.radiomediums; @@ -57,7 +57,7 @@ public class SilentRadioMedium extends RadioMedium { // Do nothing } - public void registerRadioInterface(Radio radio, Position position, Simulation sim) { + public void registerRadioInterface(Radio radio, Simulation sim) { // Do nothing } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java index d622d12c7..0b893c816 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: UDGM.java,v 1.1 2007/01/09 09:47:36 fros4943 Exp $ + * $Id: UDGM.java,v 1.2 2007/02/28 09:50:00 fros4943 Exp $ */ package se.sics.cooja.radiomediums; @@ -47,35 +47,41 @@ import se.sics.cooja.plugins.Visualizer2D; * The Unit Disk Graph medium has two different range parameters; one for * transmitting and one for interfering other transmissions. * - * Radio data are analysed when all registered motes have ticked once (this - * medium is registered as a tick observer). For every mote in transmission - * range of a sending mote, current listen status is changed from hearing - * nothing to hearing packet, or hearing packet to hearing noise. This way, if a - * mote hears two packets during one tick loop, it will receive none (noise). If - * a mote is in the interference range, the current listen status will be set to - * hears noise immediately. + * The radio medium supports both byte and packet radios. Any transmitted bytes + * are forwarded TODO immediately with a timestamp (more fine-grained than + * ticks). * - * This radio medium registers a temporary visual plugin class. - * Via this plugin ranges can be viewed and changed. Active connection may also - * be viewed. + * The radio medium registers a visualizer plugin. Via this plugin the current + * radio states and range parameters can be viewed and changed. * + * 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]%. + * + * @see #SS_OK + * @see #SS_NOISE + * @see #SS_NOTHING + * + * @see VisUDGM * @author Fredrik Osterlind */ @ClassDescription("Unit Disk Graph Medium (UDGM)") public class UDGM extends RadioMedium { private static Logger logger = Logger.getLogger(UDGM.class); - private Vector registeredPositions = new Vector(); - private Vector registeredRadios = new Vector(); - private Vector transmissionEndedRadios = new Vector(); + // private Vector transmissionEndedRadios = new Vector(); + private Vector finishedConnections = new Vector(); private static RadioMedium myRadioMedium; public static final double SS_NOTHING = -200; - public static final double SS_BAD = -60; + public static final double SS_NOISE = -60; public static final double SS_OK = 0; @@ -89,7 +95,7 @@ public class UDGM extends RadioMedium { * * @author Fredrik Osterlind */ - @ClassDescription("Radio Medium Visualizer") + @ClassDescription("UDGM Visualizer") @PluginType(PluginType.SIM_PLUGIN) public static class VisUDGM extends Visualizer2D { private Mote selectedMote = null; @@ -118,7 +124,7 @@ public class UDGM extends RadioMedium { public VisUDGM(Simulation sim, GUI gui) { super(sim, gui); - setTitle("Radio Medium Visualizer"); + setTitle("UDGM Visualizer"); // Create spinners for changing ranges SpinnerNumberModel transmissionModel = new SpinnerNumberModel(); @@ -253,54 +259,57 @@ public class UDGM extends RadioMedium { int y = pixelCoord.y; // Fetch current output power indicator (scale with as percent) - // TODO Probably not the best way to use indicator - double moteInterferenceRange = INTERFERENCE_RANGE - * (0.01 * (double) selectedMote.getInterfaces().getRadio() - .getCurrentOutputPowerIndicator()); - double moteTransmissionRange = TRANSMITTING_RANGE - * (0.01 * (double) selectedMote.getInterfaces().getRadio() - .getCurrentOutputPowerIndicator()); + if (selectedMote.getInterfaces().getRadio() != null) { + double moteInterferenceRange = INTERFERENCE_RANGE + * (0.01 * (double) selectedMote.getInterfaces().getRadio() + .getCurrentOutputPowerIndicator()); + double moteTransmissionRange = TRANSMITTING_RANGE + * (0.01 * (double) selectedMote.getInterfaces().getRadio() + .getCurrentOutputPowerIndicator()); - Point translatedZero = transformPositionToPixel(0.0, 0.0, 0.0); - Point translatedInterference = transformPositionToPixel( - moteInterferenceRange, moteInterferenceRange, 0.0); - Point translatedTransmission = transformPositionToPixel( - moteTransmissionRange, moteTransmissionRange, 0.0); + Point translatedZero = transformPositionToPixel(0.0, 0.0, 0.0); + Point translatedInterference = transformPositionToPixel( + moteInterferenceRange, moteInterferenceRange, 0.0); + Point translatedTransmission = transformPositionToPixel( + moteTransmissionRange, moteTransmissionRange, 0.0); - translatedInterference.x = Math.abs(translatedInterference.x - - translatedZero.x); - translatedInterference.y = Math.abs(translatedInterference.y - - translatedZero.y); - translatedTransmission.x = Math.abs(translatedTransmission.x - - translatedZero.x); - translatedTransmission.y = Math.abs(translatedTransmission.y - - translatedZero.y); + translatedInterference.x = Math.abs(translatedInterference.x + - translatedZero.x); + translatedInterference.y = Math.abs(translatedInterference.y + - translatedZero.y); + translatedTransmission.x = Math.abs(translatedTransmission.x + - translatedZero.x); + translatedTransmission.y = Math.abs(translatedTransmission.y + - translatedZero.y); - // Interference - g.setColor(Color.DARK_GRAY); - g.fillOval(x - translatedInterference.x, y - translatedInterference.y, - 2 * translatedInterference.x, 2 * translatedInterference.y); - - // Transmission - g.setColor(Color.GREEN); - g.fillOval(x - translatedTransmission.x, y - translatedTransmission.y, - 2 * translatedTransmission.x, 2 * translatedTransmission.y); + // Interference + g.setColor(Color.DARK_GRAY); + g.fillOval(x - translatedInterference.x, + y - translatedInterference.y, 2 * translatedInterference.x, + 2 * translatedInterference.y); + // Transmission + g.setColor(Color.GREEN); + g.fillOval(x - translatedTransmission.x, + y - translatedTransmission.y, 2 * translatedTransmission.x, + 2 * translatedTransmission.y); + } } // Let parent paint motes super.visualizeSimulation(g); - // Paint last tick connections + // Paint just finished connections if (myRadioMedium != null && myRadioMedium.getLastTickConnections() != null) { for (RadioConnection conn : myRadioMedium.getLastTickConnections()) { if (conn != null) { - Point sourcePoint = transformPositionToPixel(conn - .getSourcePosition()); + Point sourcePoint = transformPositionToPixel(conn.getSource() + .getPosition()); // Paint destinations - for (Position destPos : conn.getDestinationPositons()) { + for (Radio destRadio : conn.getDestinations()) { + Position destPos = destRadio.getPosition(); Point destPoint = transformPositionToPixel(destPos); g.setColor(Color.BLACK); @@ -338,205 +347,417 @@ public class UDGM extends RadioMedium { private RadioConnection[] lastTickConnections = null; - private Vector pendingConnections = new Vector(); + private Vector activeConnections = new Vector(); private ConnectionLogger myLogger = null; - private Observer radioDataObserver = new Observer() { - public void update(Observable radio, Object obj) { - // This radio changed, let tick loop notify observers - radioMediumObservable.setRadioMediumChanged(); + /** + * Creates and registers a new connection from given radio. + * + * @param radio + * Transmitting radio + * @return New registered connection + */ + private RadioConnection createConnections(Radio radio) { + Radio sendingRadio = radio; + Position sendingPosition = sendingRadio.getPosition(); - // Register any new transmission - if (((Radio) radio).getLastEvent() == Radio.RadioEvent.TRANSMISSION_STARTED) { - Radio sendingRadio = (Radio) radio; + RadioConnection newConnection = new RadioConnection(sendingRadio); - // If obj is the position, use it directly (speeds up things) - // Otherwise we must search for the position ourselves - Position sendingPosition = (Position) obj; - if (sendingPosition == null) { - if (!registeredRadios.contains(radio)) { - logger.fatal("Sending radio not registered, skipping packet"); - return; - } + // Fetch current output power indicator (scale with as percent) + double moteTransmissionRange = TRANSMITTING_RANGE + * (0.01 * (double) sendingRadio.getCurrentOutputPowerIndicator()); + double moteInterferenceRange = INTERFERENCE_RANGE + * (0.01 * (double) sendingRadio.getCurrentOutputPowerIndicator()); - sendingPosition = registeredPositions.get(registeredRadios - .indexOf(radio)); - if (sendingPosition == null) { - logger.fatal("Sending radio not registered, skipping packet"); - return; - } - } + // Loop through all radios + for (int listenNr = 0; listenNr < registeredRadios.size(); listenNr++) { + Radio listeningRadio = registeredRadios.get(listenNr); + Position listeningRadioPosition = listeningRadio.getPosition(); - byte[] dataToSend = sendingRadio.getLastPacketTransmitted(); - - RadioConnection newConnection = new RadioConnection(); - pendingConnections.add(newConnection); - newConnection.setSource(sendingRadio, sendingPosition, dataToSend); + // Ignore sending radio and radios on different channels + if (sendingRadio == listeningRadio) + continue; + if (sendingRadio.getChannel() != listeningRadio.getChannel()) + continue; - // Fetch current output power indicator (scale with as percent) - // TODO Probably not the best way to use indicator - double moteInterferenceRange = INTERFERENCE_RANGE - * (0.01 * (double) sendingRadio.getCurrentOutputPowerIndicator()); - double moteTransmissionRange = TRANSMITTING_RANGE - * (0.01 * (double) sendingRadio.getCurrentOutputPowerIndicator()); + double distance = sendingPosition.getDistanceTo(listeningRadioPosition); - // Loop through all radios that are listening - for (int listenNr = 0; listenNr < registeredPositions.size(); listenNr++) { - Radio listeningRadio = registeredRadios.get(listenNr); + if (distance <= moteTransmissionRange) { + // Check if this radio is able to receive transmission + if (listeningRadio.isInterfered()) { + // Keep interfering radio + newConnection.addInterfered(listeningRadio); - if (sendingRadio == listeningRadio) - continue; - if (sendingRadio.getChannel() != listeningRadio.getChannel()) - continue; - - - // If not the sending radio.. - double distance = sendingPosition.getDistanceTo(registeredPositions - .get(listenNr)); - - if (distance <= moteTransmissionRange) { - newConnection.addDestination(registeredRadios.get(listenNr), - registeredPositions.get(listenNr), dataToSend); - - // If close enough to transmit ok.. - if (listeningRadio.isReceiving() || listeningRadio.isInterfered()) { - // .. but listening radio already received a packet - listeningRadio.interferReception(sendingRadio - .getTransmissionEndTime()); - listeningRadio.setCurrentSignalStrength(SS_BAD); - } else { - // .. send packet - listeningRadio.receivePacket(dataToSend, sendingRadio - .getTransmissionEndTime()); - listeningRadio.setCurrentSignalStrength(SS_OK); + } else if (listeningRadio.isReceiving()) { + newConnection.addInterfered(listeningRadio); + + // Start interfering radio + listeningRadio.interfereAnyReception(); + + // Update connection that is transmitting to this radio + RadioConnection existingConn = null; + for (RadioConnection conn : activeConnections) { + for (Radio dstRadio : conn.getDestinations()) { + if (dstRadio == listeningRadio) { + existingConn = conn; + break; + } } - } else if (distance <= moteInterferenceRange) { - // If close enough to sabotage other transmissions.. - listeningRadio.interferReception(sendingRadio - .getTransmissionEndTime()); - listeningRadio.setCurrentSignalStrength(SS_BAD); } - // else too far away + if (existingConn != null) { + // Change radio from receiving to interfered + existingConn.removeDestination(listeningRadio); + existingConn.addInterfered(listeningRadio); + + } + } else { + // Radio OK to receive + newConnection.addDestination(listeningRadio); + listeningRadio.signalReceptionStart(); + } + } else if (distance <= moteInterferenceRange) { + // Interfere radio + newConnection.addInterfered(listeningRadio); + listeningRadio.interfereAnyReception(); + } + + } + + // Register new connection + activeConnections.add(newConnection); + return newConnection; + } + + /** + * Forward given packet from source to all destinations in given connection. + * + * @param connection + * Radio connection + * @param packetData + * Packet data + */ + private void forwardPacket(RadioConnection connection, byte[] packetData) { + Radio sourceRadio = connection.getSource(); + + if (sourceRadio instanceof ByteRadio) { + // Byte radios only forwards packets to packet radios + for (Radio receivingRadio : connection.getDestinations()) { + if (receivingRadio instanceof ByteRadio) { + // Do nothing (data will be forwarded on byte-per-byte basis) + } else if (receivingRadio instanceof PacketRadio) { + // Forward packet data + ((PacketRadio) receivingRadio).setReceivedPacket(packetData); + } else { + logger.warn("Packet was not forwarded correctly"); } } - - if (((Radio) radio).getLastEvent() == Radio.RadioEvent.TRANSMISSION_FINISHED) { - transmissionEndedRadios.add((Radio) radio); + } else if (sourceRadio instanceof PacketRadio) { + // Packet radios forwards packets to all packet radios + for (Radio receivingRadio : connection.getDestinations()) { + if (receivingRadio instanceof PacketRadio) { + // Forward packet data + ((PacketRadio) receivingRadio).setReceivedPacket(packetData); + } else { + logger.warn("Packet was not forwarded correctly"); + } + } + } + } + + private void removeFromActiveConnections(Radio radio) { + // Abort any reception + 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()) { + dstRadio.interfereAnyReception(); + dstRadio.signalReceptionEnd(); + } + for (Radio dstRadio : conn.getInterfered()) { + dstRadio.signalReceptionEnd(); + } + } + } + if (connToRemove != null) + activeConnections.remove(connToRemove); + } + + /** + * Updates all radio signal strengths according to current transmissions. This + * method also updates earlier interfered radios. + */ + private 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(); + // } + + // Reset signal strength on all radios + for (Radio radio : registeredRadios) { + radio.setCurrentSignalStrength(SS_NOTHING); + } + + // Set signal strength on all OK transmissions + for (RadioConnection conn : activeConnections) { + conn.getSource().setCurrentSignalStrength(SS_OK); + for (Radio dstRadio : conn.getDestinations()) { + dstRadio.setCurrentSignalStrength(SS_OK); + } + } + + // Set signal strength on all interferences + for (RadioConnection conn : activeConnections) { + for (Radio dstRadio : conn.getInterfered()) { + dstRadio.setCurrentSignalStrength(SS_NOISE); + if (!dstRadio.isInterfered()) { + // Set to interfered again + dstRadio.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]); + // } + } + + private Observer radioEventsObserver = new Observer() { + public void update(Observable obs, Object obj) { + if (!(obs instanceof Radio)) { + 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) { + return; + } + + if (event == Radio.RadioEvent.HW_OFF) { + // Destroy any(?) transfers + removeFromActiveConnections(radio); + + // Recalculate signal strengths on all radios + updateSignalStrengths(); + + // Wake up tick observer + radioMediumObservable.setRadioMediumChanged(); + + } else if (event == Radio.RadioEvent.HW_ON) { + // No action + // TODO Maybe set signal strength levels now? + + // Recalculate signal strengths on all radios + updateSignalStrengths(); + + // Wake up tick observer + radioMediumObservable.setRadioMediumChanged(); + + } else if (event == Radio.RadioEvent.TRANSMISSION_STARTED) { + /* Create radio connections */ + + createConnections((Radio) radio); + + // Recalculate signal strengths on all radios + updateSignalStrengths(); + + // Wake up tick observer + radioMediumObservable.setRadioMediumChanged(); + + } 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; + } + } + + if (connection == null) { + logger.fatal("Can't find active connection to remove"); + } else { + activeConnections.remove(connection); + finishedConnections.add(connection); + for (Radio dstRadio : connection.getDestinations()) { + dstRadio.signalReceptionEnd(); + } + for (Radio dstRadio : connection.getInterfered()) { + dstRadio.signalReceptionEnd(); + } + } + + // Recalculate signal strengths on all radios + updateSignalStrengths(); + + // Wake up tick observer + radioMediumObservable.setRadioMediumChanged(); + + } else if (event == Radio.RadioEvent.BYTE_TRANSMITTED) { + /* Forward byte */ + + // 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 byte in"); + } else { + byte b = ((ByteRadio) radio).getLastByteTransmitted(); + long timestamp = ((ByteRadio) radio).getLastByteTransmittedTimestamp(); + + for (Radio dstRadio : connection.getDestinations()) { + if (dstRadio instanceof ByteRadio) { + ((ByteRadio) dstRadio).receiveByte(b, timestamp); + } + } + } + + } else if (event == Radio.RadioEvent.PACKET_TRANSMITTED) { + /* Forward packet */ + + // 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 byte in"); + } else { + byte[] packetData = ((PacketRadio) radio).getLastPacketTransmitted(); + forwardPacket(connection, packetData); + } + + } else if (event == Radio.RadioEvent.UNKNOWN) { + // Do nothing + } else { + logger.fatal("Unsupported radio event: " + event); } - } }; - + + /** + * This observer is resposible for making last tick connections available to + * external observers, as well as forwarding finished connections to any + * registered connection logger. + * + * @see #getLastTickConnections() + * @see #setConnectionLogger(ConnectionLogger) + */ private Observer tickObserver = new Observer() { public void update(Observable obs, Object obj) { - if (lastTickConnections != null) + // Reset any last tick connections + if (lastTickConnections != null) { radioMediumObservable.setRadioMediumChanged(); + lastTickConnections = null; + } - // Reset last tick connections - lastTickConnections = null; + // Do nothing if radio medium unchanged + if (!radioMediumObservable.hasChanged()) + return; - // Log finished connections if any - Vector updatedPendingConnections = new Vector(); - if (transmissionEndedRadios.size() > 0) { - final int numberFinished = transmissionEndedRadios.size(); - Vector newTickConnections = new Vector(); - - // Loop through all radios that finished transmitting data - for (int recvNr = 0; recvNr < numberFinished; recvNr++) { - Radio transmittingRadio = transmissionEndedRadios.get(recvNr); - - for (RadioConnection pendingConnection : pendingConnections) { - - // Log finished connection - if (pendingConnection.getSourceRadio() == transmittingRadio) { - for (Radio destRadio : pendingConnection.getDestinationRadios()) { - if (destRadio.getLastEvent() != Radio.RadioEvent.RECEPTION_FINISHED) { - // Radio was interfered - pendingConnection.removeDestination(destRadio); - } - } - newTickConnections.add(pendingConnection); - } - - // Remove connection if old (don't keep) - if (pendingConnection.getSourceRadio().isTransmitting()) { - updatedPendingConnections.add(pendingConnection); - } - } - } - - lastTickConnections = new RadioConnection[newTickConnections.size()]; - for (int i = 0; i < lastTickConnections.length; i++) - lastTickConnections[i] = newTickConnections.get(i); - transmissionEndedRadios.clear(); - - pendingConnections = updatedPendingConnections; + // Log any new finished connections + if (finishedConnections.size() > 0) { + lastTickConnections = new RadioConnection[finishedConnections.size()]; + for (int i = 0; i < finishedConnections.size(); i++) + lastTickConnections[i] = finishedConnections.get(i); + finishedConnections.clear(); + // Notify radio medium logger of the finished transmissions if (myLogger != null) { for (RadioConnection conn : lastTickConnections) myLogger.logConnection(conn); } - - // Radio medium has changed, notifing below - radioMediumObservable.setRadioMediumChanged(); } - // Set signal strengths on all radios - for (Radio radio : registeredRadios) { - if (radio.isTransmitting()) - radio.setCurrentSignalStrength(SS_OK); - else if (radio.isReceiving()) - radio.setCurrentSignalStrength(SS_OK); - else if (radio.isInterfered()) - radio.setCurrentSignalStrength(SS_BAD); - else - radio.setCurrentSignalStrength(SS_NOTHING); - } - - // Notify observers (if anything has changed) + // Notify all other radio medium observers radioMediumObservable.notifyObservers(); } }; public void registerMote(Mote mote, Simulation sim) { - registerRadioInterface(mote.getInterfaces().getRadio(), mote - .getInterfaces().getPosition(), sim); + registerRadioInterface(mote.getInterfaces().getRadio(), sim); } public void unregisterMote(Mote mote, Simulation sim) { unregisterRadioInterface(mote.getInterfaces().getRadio(), sim); } - public void registerRadioInterface(Radio radio, Position position, - Simulation sim) { - if (radio != null && position != null) { + public void registerRadioInterface(Radio radio, Simulation sim) { + if (radio != null) { if (!isTickObserver) { sim.addTickObserver(tickObserver); isTickObserver = true; } - registeredPositions.add(position); + // Warn if radio medium does not support radio + if (!(radio instanceof PacketRadio)) { + logger + .warn("Radio medium does not support radio (no transmission supported)"); + } + + // Register and start observing radio registeredRadios.add(radio); - radio.addObserver(radioDataObserver); + radio.addObserver(radioEventsObserver); // Set initial signal strenth radio.setCurrentSignalStrength(SS_NOTHING); - - } // else logger.warn("Radio Medium not registering mote"); + } } public void unregisterRadioInterface(Radio radio, Simulation sim) { - for (int i = 0; i < registeredRadios.size(); i++) { - if (registeredRadios.get(i).equals(radio)) { - registeredRadios.remove(i); - registeredPositions.remove(i); - radio.deleteObserver(radioDataObserver); - return; - } + if (!registeredRadios.contains(radio)) { + logger.warn("Could not find radio: " + radio + " to unregister"); + return; } - logger.warn("Could not find radio: " + radio + " to unregister"); + + radio.deleteObserver(radioEventsObserver); + registeredRadios.remove(radio); + + removeFromActiveConnections(radio); } public void addRadioMediumObserver(Observer observer) { @@ -576,7 +797,8 @@ public class UDGM extends RadioMedium { return config; } - public boolean setConfigXML(Collection configXML, boolean visAvailable) { + public boolean setConfigXML(Collection configXML, + boolean visAvailable) { for (Element element : configXML) { if (element.getName().equals("transmitting_range")) { TRANSMITTING_RANGE = Double.parseDouble(element.getText());