diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java index 59b444c3c..cc475ee23 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java @@ -381,7 +381,21 @@ public class Msp802154Radio extends Radio implements CustomDataRadio { } rssiLastCounter = 8; } + + + /* This will set the CORR-value of the CC2420 + * + * @see se.sics.cooja.interfaces.Radio#setLQI(int) + */ + public void setLQI(int lqi){ + radio.setLQI(lqi); + } + public int getLQI(){ + return radio.getLQI(); + } + + public Mote getMote() { return mote; } diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java index e076b0d78..41e22f0c0 100644 --- a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java +++ b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java @@ -168,6 +168,25 @@ public abstract class Radio extends MoteInterface { * @return Maximum output power indicator */ public abstract int getOutputPowerIndicatorMax(); + + /** + * Returns the current LQI-value. This might differ from platform to platform + * @return Current LQI value. + * + * + */ + public int getLQI() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /** + * Sets the LQI. This in not supported by all platforms. Also results may differ + * from platform to platform. + * + * @param lqi The current LQI + */ + public void setLQI(int lqi){ + } /** * @return Current surrounding signal strength diff --git a/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java b/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java index 19f640811..e9edbe339 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java +++ b/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java @@ -91,9 +91,11 @@ public class DGRMConfigurator extends VisPlugin { private final static int IDX_DST = 1; private final static int IDX_RATIO = 2; private final static int IDX_SIGNAL = 3; - private final static int IDX_DELAY = 4; + private final static int IDX_LQI = 4; + private final static int IDX_DELAY = 5; + private final static String[] COLUMN_NAMES = new String[] { - "Source", "Destination", "RX Ratio", "RSSI", "Delay" + "Source", "Destination", "RX Ratio", "RSSI","LQI", "Delay" }; private GUI gui = null; @@ -128,6 +130,10 @@ public class DGRMConfigurator extends VisPlugin { for (double d=AbstractRadioMedium.SS_STRONG; d >= AbstractRadioMedium.SS_WEAK; d -= 1) { combo.addItem((int) d); } + } else if (column == IDX_LQI) { + for (int d = 110; d > 50; d -= 5) { + combo.addItem((int) d); + } } else if (column == IDX_DELAY) { for (double d=0; d <= 5; d++) { combo.addItem(d); @@ -161,6 +167,17 @@ public class DGRMConfigurator extends VisPlugin { setText(String.format("%1.1f dBm", v)); } }); + graphTable.getColumnModel().getColumn(IDX_LQI).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = -4669897764928372246L; + public void setValue(Object value) { + if (!(value instanceof Long)) { + setText(value.toString()); + return; + } + long v = ((Long) value).longValue(); + setText(String.valueOf(v)); + } + }); graphTable.getColumnModel().getColumn(IDX_DELAY).setCellRenderer(new DefaultTableCellRenderer() { private static final long serialVersionUID = -4669897764928372246L; public void setValue(Object value) { @@ -174,6 +191,7 @@ public class DGRMConfigurator extends VisPlugin { }); graphTable.getColumnModel().getColumn(IDX_RATIO).setCellEditor(new DefaultCellEditor(combo)); graphTable.getColumnModel().getColumn(IDX_SIGNAL).setCellEditor(new DefaultCellEditor(combo)); + graphTable.getColumnModel().getColumn(IDX_LQI).setCellEditor(new DefaultCellEditor(combo)); graphTable.getColumnModel().getColumn(IDX_DELAY).setCellEditor(new DefaultCellEditor(combo)); graphTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); @@ -411,6 +429,9 @@ public class DGRMConfigurator extends VisPlugin { if (column == IDX_SIGNAL) { return ((DGRMDestinationRadio)edge.superDest).signal; } + if (column == IDX_LQI) { + return ((DGRMDestinationRadio)edge.superDest).lqi; + } if (column == IDX_DELAY) { return ((DGRMDestinationRadio)edge.superDest).delay / Simulation.MILLISECOND; } @@ -433,7 +454,10 @@ public class DGRMConfigurator extends VisPlugin { } else if (column == IDX_DELAY) { ((DGRMDestinationRadio)edge.superDest).delay = ((Number)value).longValue() * Simulation.MILLISECOND; - } else { + } else if (column == IDX_LQI) { + ((DGRMDestinationRadio)edge.superDest).lqi = ((Number)value).intValue(); + } + else { super.setValueAt(value, row, column); } radioMedium.requestEdgeAnalysis(); @@ -461,6 +485,9 @@ public class DGRMConfigurator extends VisPlugin { if (column == IDX_SIGNAL) { return true; } + if (column == IDX_LQI) { + return true; + } if (column == IDX_DELAY) { return true; } diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java index d49ab8976..77b86bc61 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java @@ -117,6 +117,15 @@ public class DGRMVisualizerSkin implements VisualizerSkin { g.drawString(msg, x - msgWidth/2, y + 2*Visualizer.MOTE_RADIUS + 3); for (DestinationRadio r: dests) { double prob = ((DGRMDestinationRadio)r).ratio; + double rssi = ((DGRMDestinationRadio)r).signal; + double pos_rssi = rssi + 100; + int lqi = ((DGRMDestinationRadio)r).lqi; + float red = (float)(1 - prob*pos_rssi/90*lqi/100); + if(red > 1) red = 1; + if(red < 0) red = 0; + float green = (float)(prob*pos_rssi/90*lqi/100); + if(green > 1) green = 1; + if(green < 0) green = 0; if (prob == 0.0d) { continue; } @@ -124,7 +133,8 @@ public class DGRMVisualizerSkin implements VisualizerSkin { Position pos = r.radio.getPosition(); Point pixel = visualizer.transformPositionToPixel(pos); msgWidth = fm.stringWidth(msg); - g.setColor(new Color(1-(float)prob, (float)prob, 0.0f)); + g.setColor(new Color(red, green, 0.0f)); + g.drawString("LQI: " + lqi + " RSSI: " + rssi,(x + pixel.x)/2,(y + pixel.y)/2); g.drawLine(x, y, pixel.x, pixel.y); g.setColor(Color.BLACK); g.drawString(msg, pixel.x - msgWidth/2, pixel.y + 2*Visualizer.MOTE_RADIUS + 3); diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java index 08e59b1db..903af3cfd 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java @@ -61,416 +61,410 @@ import se.sics.cooja.interfaces.Radio; * @author Fredrik Osterlind */ public abstract class AbstractRadioMedium extends RadioMedium { - private static Logger logger = Logger.getLogger(AbstractRadioMedium.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 ArrayList registeredRadios = new ArrayList(); - - private ArrayList activeConnections = new ArrayList(); - - private RadioConnection lastConnection = null; - - private Simulation simulation = null; - - /* Book-keeping */ - public int COUNTER_TX = 0; - public int COUNTER_RX = 0; - public int COUNTER_INTERFERED = 0; - - public class RadioMediumObservable extends Observable { - public void setRadioMediumChanged() { - setChanged(); - } - public void setRadioMediumChangedAndNotify() { - setChanged(); - notifyObservers(); - } - } - - private RadioMediumObservable radioMediumObservable = new RadioMediumObservable(); - - /** - * This constructor should always be called from implemented radio mediums. - * - * @param simulation Simulation - */ - public AbstractRadioMedium(Simulation simulation) { - this.simulation = simulation; - } - - /** - * @return All registered radios - */ - public Radio[] getRegisteredRadios() { - return registeredRadios.toArray(new Radio[0]); - } - - /** - * @return All active connections - */ - public RadioConnection[] getActiveConnections() { - /* NOTE: toArray([0]) creates array and handles synchronization */ - return activeConnections.toArray(new RadioConnection[0]); - } - - /** - * Creates a new connection from given radio. - * - * Determines which radios should receive or be interfered by the transmission. - * - * @param radio Source radio - * @return New connection - */ - abstract public RadioConnection createConnections(Radio radio); - - /** - * Updates all radio interfaces' signal strengths according to - * the current active connections. - */ - 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) { - if (conn.getSource().getCurrentSignalStrength() < SS_STRONG) { - conn.getSource().setCurrentSignalStrength(SS_STRONG); - } - for (Radio dstRadio : conn.getDestinations()) { - if (conn.getSource().getChannel() >= 0 && - dstRadio.getChannel() >= 0 && - conn.getSource().getChannel() != dstRadio.getChannel()) { - continue; - } - if (dstRadio.getCurrentSignalStrength() < SS_STRONG) { - dstRadio.setCurrentSignalStrength(SS_STRONG); - } - } - } - - /* Set signal strength to weak on interfered */ - for (RadioConnection conn : conns) { - for (Radio intfRadio : conn.getInterfered()) { - if (intfRadio.getCurrentSignalStrength() < SS_STRONG) { - intfRadio.setCurrentSignalStrength(SS_STRONG); - } - if (conn.getSource().getChannel() >= 0 && - intfRadio.getChannel() >= 0 && - conn.getSource().getChannel() != intfRadio.getChannel()) { - continue; - } - if (!intfRadio.isInterfered()) { - /*logger.warn("Radio was not interfered");*/ - intfRadio.interfereAnyReception(); - } - } - } - } - - - /** - * Remove given radio from any active connections. - * This method can be called if a radio node falls asleep or is removed. - * - * @param radio Radio - */ - private void removeFromActiveConnections(Radio radio) { - /* This radio must not be a connection source */ - RadioConnection connection = getActiveConnectionFrom(radio); - if (connection != null) { - logger.fatal("Connection source turned off radio: " + radio); - } - - /* Set interfered if currently a connection destination */ - for (RadioConnection conn : activeConnections) { - if (conn.isDestination(radio)) { - conn.addInterfered(radio); - if (!radio.isInterfered()) { - radio.interfereAnyReception(); - } - } - } - } - - private RadioConnection getActiveConnectionFrom(Radio source) { - for (RadioConnection conn : activeConnections) { - if (conn.getSource() == source) { - return conn; - } - } - return null; - } - - /** - * This observer is responsible for detecting radio interface events, for example - * new transmissions. - */ - 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; - - final Radio.RadioEvent event = radio.getLastEvent(); - 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_ON) { - - /* Update signal strengths */ - updateSignalStrengths(); - - } else if (event == Radio.RadioEvent.HW_OFF) { - - /* Remove any radio connections from this radio */ - removeFromActiveConnections(radio); - - /* Update signal strengths */ - updateSignalStrengths(); - - } else if (event == Radio.RadioEvent.TRANSMISSION_STARTED) { - /* Create new radio connection */ - - if (radio.isReceiving()) { - /* Radio starts transmitting when it should be receiving! - * Ok, but it won't receive the packet */ - for (RadioConnection conn : activeConnections) { - if (conn.isDestination(radio)) { - conn.addInterfered(radio); - } - } - radio.interfereAnyReception(); - } - - RadioConnection newConnection = createConnections(radio); - activeConnections.add(newConnection); - for (Radio r: newConnection.getAllDestinations()) { - if (newConnection.getDestinationDelay(r) == 0) { - r.signalReceptionStart(); - } else { - - /* EXPERIMENTAL: Simulating propagation delay */ - final Radio delayedRadio = r; - TimeEvent delayedEvent = new TimeEvent(0) { - public void execute(long t) { - delayedRadio.signalReceptionStart(); - } - }; - simulation.scheduleEvent( - delayedEvent, - simulation.getSimulationTime() + newConnection.getDestinationDelay(r)); - - } - } - - /* Update signal strengths */ - updateSignalStrengths(); - - /* Notify observers */ - lastConnection = null; - radioMediumObservable.setRadioMediumChangedAndNotify(); - - } else if (event == Radio.RadioEvent.TRANSMISSION_FINISHED) { - /* Remove radio connection */ - - /* Connection */ - RadioConnection connection = getActiveConnectionFrom(radio); - if (connection == null) { - logger.fatal("No radio connection found"); - return; - } - - activeConnections.remove(connection); - lastConnection = connection; - COUNTER_TX++; - for (Radio dstRadio : connection.getAllDestinations()) { - 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)); - } - } - COUNTER_RX += connection.getDestinations().length; - COUNTER_INTERFERED += connection.getInterfered().length; - for (Radio intRadio : connection.getInterferedNonDestinations()) { - 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("No custom data object to forward"); - return; - } - - for (Radio dstRadio : connection.getAllDestinations()) { - - 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) { - - /* Connection */ - RadioConnection connection = getActiveConnectionFrom(radio); - if (connection == null) { - logger.fatal("No radio connection found"); - return; - } - - /* Radio packet */ - RadioPacket packet = radio.getLastPacketTransmitted(); - if (packet == null) { - logger.fatal("No radio packet to forward"); - return; - } - - for (Radio dstRadio : connection.getAllDestinations()) { - - 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 { - logger.fatal("Unsupported radio event: " + event); - } - } - }; - - public void registerMote(Mote mote, Simulation sim) { - registerRadioInterface(mote.getInterfaces().getRadio(), sim); - } - - public void unregisterMote(Mote mote, Simulation sim) { - unregisterRadioInterface(mote.getInterfaces().getRadio(), sim); - } - - public void registerRadioInterface(Radio radio, Simulation sim) { - 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("No radio to unregister: " + radio); - return; - } - - radio.deleteObserver(radioEventsObserver); - registeredRadios.remove(radio); - - removeFromActiveConnections(radio); - - /* Update signal strengths */ - updateSignalStrengths(); - } - - public void addRadioMediumObserver(Observer observer) { - radioMediumObservable.addObserver(observer); - } - - public Observable getRadioMediumObservable() { - return radioMediumObservable; - } - - public void deleteRadioMediumObserver(Observer observer) { - radioMediumObservable.deleteObserver(observer); - } - - public RadioConnection getLastConnection() { - return lastConnection; - } + private static Logger logger = Logger.getLogger(AbstractRadioMedium.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 ArrayList registeredRadios = new ArrayList(); + + private ArrayList activeConnections = new ArrayList(); + + private RadioConnection lastConnection = null; + + private Simulation simulation = null; + + /* Book-keeping */ + public int COUNTER_TX = 0; + public int COUNTER_RX = 0; + public int COUNTER_INTERFERED = 0; + + public class RadioMediumObservable extends Observable { + public void setRadioMediumChanged() { + setChanged(); + } + public void setRadioMediumChangedAndNotify() { + setChanged(); + notifyObservers(); + } + } + + private RadioMediumObservable radioMediumObservable = new RadioMediumObservable(); + + /** + * This constructor should always be called from implemented radio mediums. + * + * @param simulation Simulation + */ + public AbstractRadioMedium(Simulation simulation) { + this.simulation = simulation; + } + + /** + * @return All registered radios + */ + public Radio[] getRegisteredRadios() { + return registeredRadios.toArray(new Radio[0]); + } + + /** + * @return All active connections + */ + public RadioConnection[] getActiveConnections() { + /* NOTE: toArray([0]) creates array and handles synchronization */ + return activeConnections.toArray(new RadioConnection[0]); + } + + /** + * Creates a new connection from given radio. + * + * Determines which radios should receive or be interfered by the transmission. + * + * @param radio Source radio + * @return New connection + */ + abstract public RadioConnection createConnections(Radio radio); + + /** + * Updates all radio interfaces' signal strengths according to + * the current active connections. + */ + 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) { + if (conn.getSource().getCurrentSignalStrength() < SS_STRONG) { + conn.getSource().setCurrentSignalStrength(SS_STRONG); + } + for (Radio dstRadio : conn.getDestinations()) { + if (conn.getSource().getChannel() >= 0 && + dstRadio.getChannel() >= 0 && + conn.getSource().getChannel() != dstRadio.getChannel()) { + continue; + } + if (dstRadio.getCurrentSignalStrength() < SS_STRONG) { + dstRadio.setCurrentSignalStrength(SS_STRONG); + } + } + } + + /* Set signal strength to weak on interfered */ + for (RadioConnection conn : conns) { + for (Radio intfRadio : conn.getInterfered()) { + if (intfRadio.getCurrentSignalStrength() < SS_STRONG) { + intfRadio.setCurrentSignalStrength(SS_STRONG); + } + if (conn.getSource().getChannel() >= 0 && + intfRadio.getChannel() >= 0 && + conn.getSource().getChannel() != intfRadio.getChannel()) { + continue; + } + if (!intfRadio.isInterfered()) { + /*logger.warn("Radio was not interfered");*/ + intfRadio.interfereAnyReception(); + } + } + } + } + + + /** + * Remove given radio from any active connections. + * This method can be called if a radio node falls asleep or is removed. + * + * @param radio Radio + */ + private void removeFromActiveConnections(Radio radio) { + /* This radio must not be a connection source */ + RadioConnection connection = getActiveConnectionFrom(radio); + if (connection != null) { + logger.fatal("Connection source turned off radio: " + radio); + } + + /* Set interfered if currently a connection destination */ + for (RadioConnection conn : activeConnections) { + if (conn.isDestination(radio)) { + conn.addInterfered(radio); + if (!radio.isInterfered()) { + radio.interfereAnyReception(); + } + } + } + } + + private RadioConnection getActiveConnectionFrom(Radio source) { + for (RadioConnection conn : activeConnections) { + if (conn.getSource() == source) { + return conn; + } + } + return null; + } + + /** + * This observer is responsible for detecting radio interface events, for example + * new transmissions. + */ + 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; + + final Radio.RadioEvent event = radio.getLastEvent(); + + switch (event) { + case RECEPTION_STARTED: + case RECEPTION_INTERFERED: + case RECEPTION_FINISHED: + case UNKNOWN: + return; + case HW_ON: { + /* Update signal strengths */ + updateSignalStrengths(); + } + break; + case HW_OFF: { + /* Remove any radio connections from this radio */ + removeFromActiveConnections(radio); + /* Update signal strengths */ + updateSignalStrengths(); + } + break; + case TRANSMISSION_STARTED: { + /* Create new radio connection */ + if (radio.isReceiving()) { + /* + * Radio starts transmitting when it should be + * receiving! Ok, but it won't receive the packet + */ + radio.interfereAnyReception(); + for (RadioConnection conn : activeConnections) { + if (conn.isDestination(radio)) { + conn.addInterfered(radio); + } + } + } + + RadioConnection newConnection = createConnections(radio); + activeConnections.add(newConnection); + + for (Radio r : newConnection.getAllDestinations()) { + if (newConnection.getDestinationDelay(r) == 0) { + r.signalReceptionStart(); + } else { + /* EXPERIMENTAL: Simulating propagation delay */ + final Radio delayedRadio = r; + TimeEvent delayedEvent = new TimeEvent(0) { + public void execute(long t) { + delayedRadio.signalReceptionStart(); + } + }; + simulation.scheduleEvent(delayedEvent, simulation.getSimulationTime() + newConnection.getDestinationDelay(r)); + + } + } /* Update signal strengths */ + updateSignalStrengths(); + + /* Notify observers */ + lastConnection = null; + radioMediumObservable.setRadioMediumChangedAndNotify(); + } + break; + case TRANSMISSION_FINISHED: { + /* Remove radio connection */ + + /* Connection */ + RadioConnection connection = getActiveConnectionFrom(radio); + if (connection == null) { + logger.fatal("No radio connection found"); + return; + } + + activeConnections.remove(connection); + lastConnection = connection; + COUNTER_TX++; + for (Radio dstRadio : connection.getAllDestinations()) { + 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)); + } + } + COUNTER_RX += connection.getDestinations().length; + COUNTER_INTERFERED += connection.getInterfered().length; + for (Radio intRadio : connection.getInterferedNonDestinations()) { + intRadio.signalReceptionEnd(); + } + + /* Update signal strengths */ + updateSignalStrengths(); + + /* Notify observers */ + radioMediumObservable.setRadioMediumChangedAndNotify(); + } + break; + case 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("No custom data object to forward"); + return; + } + + for (Radio dstRadio : connection.getAllDestinations()) { + + 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)); + + } + } + + } + break; + case PACKET_TRANSMITTED: { + /* Connection */ + RadioConnection connection = getActiveConnectionFrom(radio); + if (connection == null) { + logger.fatal("No radio connection found"); + return; + } + + /* Radio packet */ + RadioPacket packet = radio.getLastPacketTransmitted(); + if (packet == null) { + logger.fatal("No radio packet to forward"); + return; + } + + for (Radio dstRadio : connection.getAllDestinations()) { + + 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)); + } + + } + } + break; + default: + logger.fatal("Unsupported radio event: " + event); + } + } + }; + + public void registerMote(Mote mote, Simulation sim) { + registerRadioInterface(mote.getInterfaces().getRadio(), sim); + } + + public void unregisterMote(Mote mote, Simulation sim) { + unregisterRadioInterface(mote.getInterfaces().getRadio(), sim); + } + + public void registerRadioInterface(Radio radio, Simulation sim) { + 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("No radio to unregister: " + radio); + return; + } + + radio.deleteObserver(radioEventsObserver); + registeredRadios.remove(radio); + + removeFromActiveConnections(radio); + + /* Update signal strengths */ + updateSignalStrengths(); + } + + public void addRadioMediumObserver(Observer observer) { + radioMediumObservable.addObserver(observer); + } + + public Observable getRadioMediumObservable() { + return radioMediumObservable; + } + + public void deleteRadioMediumObserver(Observer observer) { + radioMediumObservable.deleteObserver(observer); + } + + public RadioConnection getLastConnection() { + return lastConnection; + } } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java b/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java index f73397859..7ccf064cf 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java @@ -41,6 +41,7 @@ public class DGRMDestinationRadio extends DestinationRadio { public double ratio = 1.0; /* Link success ratio (per packet). */ public double signal = AbstractRadioMedium.SS_STRONG; /* RSSI */ public long delay = 0; /* EXPERIMENTAL: Propagation delay (us). */ + public int lqi = 105; public DGRMDestinationRadio() { super(); @@ -54,6 +55,7 @@ public class DGRMDestinationRadio extends DestinationRadio { clone.ratio = this.ratio; clone.delay = this.delay; clone.signal = this.signal; + clone.lqi = this.lqi; return clone; } @@ -69,6 +71,11 @@ public class DGRMDestinationRadio extends DestinationRadio { element.setText("" + signal); config.add(element); + element = new Element("lqi"); + element.setText("" + lqi); + config.add(element); + + element = new Element("delay"); element.setText("" + delay); config.add(element); @@ -85,6 +92,8 @@ public class DGRMDestinationRadio extends DestinationRadio { ratio = Double.parseDouble(element.getText()); } else if (element.getName().equals("signal")) { signal = Double.parseDouble(element.getText()); + } else if (element.getName().equals("lqi")) { + lqi = Integer.parseInt(element.getText()); } else if (element.getName().equals("delay")) { delay = Long.parseLong(element.getText()); } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java index 9d63c77d3..59a5ce671 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; +import java.util.List; import java.util.Random; import org.apache.log4j.Logger; @@ -71,7 +72,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium { private boolean edgesDirty = true; /* Used for optimizing lookup time */ - private Hashtable edgesTable = new Hashtable(); + private Hashtable edgesTable = new Hashtable(); public DirectedGraphMedium() { /* Do not initialize radio medium: use only for hash table */ @@ -164,45 +165,42 @@ public class DirectedGraphMedium extends AbstractRadioMedium { /* Set signal strengths */ RadioConnection[] conns = getActiveConnections(); for (RadioConnection conn : conns) { + /* When sending RSSI is Strong! + * TODO: is this reasonable + */ if (conn.getSource().getCurrentSignalStrength() < SS_STRONG) { conn.getSource().setCurrentSignalStrength(SS_STRONG); } - for (Radio dstRadio : conn.getDestinations()) { - if (dstRadio.getCurrentSignalStrength() < SS_STRONG) { - dstRadio.setCurrentSignalStrength(SS_STRONG); + //Maximum reception signal of all possible radios received + DGRMDestinationRadio dstRadios[] = getPotentialDestinations(conn.getSource()); + if (dstRadios == null) continue; + for (DGRMDestinationRadio dstRadio : dstRadios) { + if (dstRadio.radio.getCurrentSignalStrength() < dstRadio.signal) { + dstRadio.radio.setCurrentSignalStrength(dstRadio.signal); } + /* We can set this without further checks, as it will only be read + * if a packet is actually received. In that case it is set to the + * correct value */ + dstRadio.radio.setLQI(dstRadio.lqi); } - } - - /* Set signal strength to weak on interfered */ - for (RadioConnection conn : conns) { - for (Radio intfRadio : conn.getInterfered()) { - if (intfRadio.getCurrentSignalStrength() < SS_STRONG) { - intfRadio.setCurrentSignalStrength(SS_STRONG); - } - - if (!intfRadio.isInterfered()) { - /*logger.warn("Radio was not interfered");*/ - intfRadio.interfereAnyReception(); - } - } - } + + + } } - /** * Generates hash table using current edges for efficient lookup. */ protected void analyzeEdges() { - Hashtable> listTable = - new Hashtable>(); + Hashtable> listTable = + new Hashtable>(); /* Fill edge hash table with all edges */ for (Edge edge: getEdges()) { - ArrayList destRadios; + ArrayList destRadios; if (!listTable.containsKey(edge.source)) { - destRadios = new ArrayList(); + destRadios = new ArrayList(); } else { destRadios = listTable.get(edge.source); } @@ -212,11 +210,11 @@ public class DirectedGraphMedium extends AbstractRadioMedium { } /* Convert to arrays */ - Hashtable arrTable = new Hashtable(); + Hashtable arrTable = new Hashtable(); Enumeration sources = listTable.keys(); while (sources.hasMoreElements()) { Radio source = sources.nextElement(); - DestinationRadio[] arr = listTable.get(source).toArray(new DestinationRadio[0]); + DGRMDestinationRadio[] arr = listTable.get(source).toArray(new DGRMDestinationRadio[0]); arrTable.put(source, arr); } @@ -231,7 +229,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium { * @param source Source radio * @return All potential destination radios */ - public DestinationRadio[] getPotentialDestinations(Radio source) { + public DGRMDestinationRadio[] getPotentialDestinations(Radio source) { if (edgesDirty) { analyzeEdges(); } @@ -249,7 +247,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium { /* Create new radio connection using edge hash table */ RadioConnection newConn = new RadioConnection(source); - DestinationRadio[] destinations = getPotentialDestinations(source); + DGRMDestinationRadio[] destinations = getPotentialDestinations(source); if (destinations == null || destinations.length == 0) { /* No destinations */ /*logger.info(sendingRadio + ": No dest");*/ @@ -257,20 +255,14 @@ public class DirectedGraphMedium extends AbstractRadioMedium { } /*logger.info(source + ": " + destinations.length + " potential destinations");*/ - for (DestinationRadio d: destinations) { - DGRMDestinationRadio dest = (DGRMDestinationRadio) d; + for (DGRMDestinationRadio dest: destinations) { + if (dest.radio == source) { /* Fail: cannot receive our own transmission */ /*logger.info(source + ": Fail, receiver is sender");*/ continue; } - /* Fail if radios are on different (but configured) channels */ - if (source.getChannel() >= 0 && - dest.radio.getChannel() >= 0 && - source.getChannel() != dest.radio.getChannel()) { - continue; - } if (!dest.radio.isRadioOn()) { /* Fail: radio is off */ @@ -278,50 +270,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium { newConn.addInterfered(dest.radio); continue; } - - if (dest.ratio < 1.0 && random.nextDouble() > dest.ratio) { - /*logger.info(source + ": Fail, randomly");*/ - /* TODO Interfere now? */ - newConn.addInterfered(dest.radio); - - dest.radio.interfereAnyReception(); - RadioConnection otherConnection = null; - for (RadioConnection conn : getActiveConnections()) { - for (Radio dstRadio : conn.getDestinations()) { - if (dstRadio == dest.radio) { - otherConnection = conn; - break; - } - } - } - if (otherConnection != null) { - otherConnection.addInterfered(dest.radio); - } - continue; - } - - if (dest.radio.isReceiving()) { - /* Fail: radio is already actively receiving */ - /*logger.info(source + ": Fail, receiving");*/ - newConn.addInterfered(dest.radio); - - /* We will also interfere with the other connection */ - dest.radio.interfereAnyReception(); - RadioConnection otherConnection = null; - for (RadioConnection conn : getActiveConnections()) { - for (Radio dstRadio : conn.getDestinations()) { - if (dstRadio == dest.radio) { - otherConnection = conn; - break; - } - } - } - if (otherConnection != null) { - otherConnection.addInterfered(dest.radio); - } - continue; - } - + if (dest.radio.isInterfered()) { /* Fail: radio is interfered in another connection */ /*logger.info(source + ": Fail, interfered");*/ @@ -329,6 +278,41 @@ public class DirectedGraphMedium extends AbstractRadioMedium { continue; } + int srcc = source.getChannel(); + int dstc = dest.radio.getChannel(); + if ( srcc >= 0 && dstc >= 0 && srcc != dstc) { + /* Fail: radios are on different (but configured) channels */ + continue; + } + + if (dest.radio.isReceiving()) { + /* Fail: radio is already actively receiving */ + /*logger.info(source + ": Fail, receiving");*/ + newConn.addInterfered(dest.radio); + + /* We will also interfere with the other connection */ + dest.radio.interfereAnyReception(); + + // Find connection, that is sending to that radio + // and mark the destination as interfered + for (RadioConnection conn : getActiveConnections()) { + for (Radio dstRadio : conn.getDestinations()) { + if (dstRadio == dest.radio) { + conn.addInterfered(dest.radio);; + break; + } + } + } + continue; + } + + if (dest.ratio < 1.0 && random.nextDouble() > dest.ratio) { + /* Fail: Reception ratio */ + /*logger.info(source + ": Fail, randomly");*/ + newConn.addInterfered(dest.radio); + continue; + } + /* Success: radio starts receiving */ /*logger.info(source + ": OK: " + dest.radio);*/ newConn.addDestination(dest.radio, dest.delay); @@ -358,7 +342,8 @@ public class DirectedGraphMedium extends AbstractRadioMedium { delayedConfiguration = configXML; return true; } - public void simulationFinishedLoading() { + +public void simulationFinishedLoading() { if (delayedConfiguration == null) { return; } @@ -366,9 +351,10 @@ public class DirectedGraphMedium extends AbstractRadioMedium { boolean oldConfig = false; for (Element element : delayedConfiguration) { if (element.getName().equals("edge")) { - Collection edgeConfig = element.getChildren(); + @SuppressWarnings("unchecked") + Collection edgeConfig = element.getChildren(); Radio source = null; - DestinationRadio dest = null; + DGRMDestinationRadio dest = null; for (Element edgeElement : edgeConfig) { if (edgeElement.getName().equals("src")) { oldConfig = true; @@ -387,7 +373,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium { } else if (oldConfig && edgeElement.getName().equals("ratio")) { /* Old config: parse link ratio */ double ratio = Double.parseDouble(edgeElement.getText()); - ((DGRMDestinationRadio)dest).ratio = ratio; + dest.ratio = ratio; } else if (edgeElement.getName().equals("dest")) { if (oldConfig) { /* Old config: create simple destination link */ @@ -405,14 +391,16 @@ public class DirectedGraphMedium extends AbstractRadioMedium { if (destClassName == null || destClassName.isEmpty()) { continue; } - Class destClass = - simulation.getGUI().tryLoadClass(this, DestinationRadio.class, destClassName); + Class destClass = + simulation.getGUI().tryLoadClass(this, DGRMDestinationRadio.class, destClassName); if (destClass == null) { throw new RuntimeException("Could not load class: " + destClassName); } try { dest = destClass.newInstance(); - dest.setConfigXML(edgeElement.getChildren(), simulation); + @SuppressWarnings("unchecked") + List children = edgeElement.getChildren(); + dest.setConfigXML(children, simulation); } catch (Exception e) { throw (RuntimeException) new RuntimeException("Unknown class: " + destClassName).initCause(e); @@ -434,9 +422,9 @@ public class DirectedGraphMedium extends AbstractRadioMedium { public static class Edge { public Radio source = null; - public DestinationRadio superDest = null; + public DGRMDestinationRadio superDest = null; - public Edge(Radio source, DestinationRadio dest) { + public Edge(Radio source, DGRMDestinationRadio dest) { this.source = source; this.superDest = dest; } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java index 9e637874a..48d05c6e8 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java @@ -112,7 +112,7 @@ public class UDGM extends AbstractRadioMedium { /* Add potential destination */ addEdge( new DirectedGraphMedium.Edge(source, - new DestinationRadio(dest))); + new DGRMDestinationRadio(dest))); } } }