diff --git a/tools/cooja/config/cooja_default.config b/tools/cooja/config/cooja_default.config index b28337631..a48c89e2d 100644 --- a/tools/cooja/config/cooja_default.config +++ b/tools/cooja/config/cooja_default.config @@ -3,8 +3,7 @@ org.contikios.cooja.contikimote.interfaces.ContikiRadio.RADIO_TRANSMISSION_RATE_ org.contikios.cooja.contikimote.ContikiMoteType.MOTE_INTERFACES = org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.Battery org.contikios.cooja.contikimote.interfaces.ContikiVib org.contikios.cooja.contikimote.interfaces.ContikiMoteID org.contikios.cooja.contikimote.interfaces.ContikiRS232 org.contikios.cooja.contikimote.interfaces.ContikiBeeper org.contikios.cooja.interfaces.RimeAddress org.contikios.cooja.contikimote.interfaces.ContikiIPAddress org.contikios.cooja.contikimote.interfaces.ContikiRadio org.contikios.cooja.contikimote.interfaces.ContikiButton org.contikios.cooja.contikimote.interfaces.ContikiPIR org.contikios.cooja.contikimote.interfaces.ContikiClock org.contikios.cooja.contikimote.interfaces.ContikiLED org.contikios.cooja.contikimote.interfaces.ContikiCFS org.contikios.cooja.interfaces.Mote2MoteRelations org.contikios.cooja.interfaces.MoteAttributes org.contikios.cooja.contikimote.ContikiMoteType.C_SOURCES = org.contikios.cooja.Cooja.MOTETYPES = org.contikios.cooja.motes.ImportAppMoteType org.contikios.cooja.motes.DisturberMoteType org.contikios.cooja.contikimote.ContikiMoteType -org.contikios.cooja.Cooja.PLUGINS = org.contikios.cooja.plugins.Visualizer org.contikios.cooja.plugins.LogListener org.contikios.cooja.plugins.TimeLine org.contikios.cooja.plugins.MoteInformation org.contikios.cooja.plugins.MoteInterfaceViewer org.contikios.cooja.plugins.VariableWatcher org.contikios.cooja.plugins.EventListener org.contikios.cooja.plugins.RadioLogger org.contikios.cooja.plugins.ScriptRunner org.contikios.cooja.plugins.Notes org.contikios.cooja.plugins.BufferListener org.contikios.cooja.plugins.DGRMConfigurator +org.contikios.cooja.Cooja.PLUGINS = org.contikios.cooja.plugins.Visualizer org.contikios.cooja.plugins.LogListener org.contikios.cooja.plugins.TimeLine org.contikios.cooja.plugins.MoteInformation org.contikios.cooja.plugins.MoteInterfaceViewer org.contikios.cooja.plugins.VariableWatcher org.contikios.cooja.plugins.EventListener org.contikios.cooja.plugins.RadioLogger org.contikios.cooja.plugins.ScriptRunner org.contikios.cooja.plugins.Notes org.contikios.cooja.plugins.BufferListener org.contikios.cooja.plugins.DGRMConfigurator org.contikios.cooja.plugins.BaseRSSIconf org.contikios.cooja.Cooja.POSITIONERS = org.contikios.cooja.positioners.RandomPositioner org.contikios.cooja.positioners.LinearPositioner org.contikios.cooja.positioners.EllipsePositioner org.contikios.cooja.positioners.ManualPositioner org.contikios.cooja.Cooja.RADIOMEDIUMS = org.contikios.cooja.radiomediums.UDGM org.contikios.cooja.radiomediums.UDGMConstantLoss org.contikios.cooja.radiomediums.DirectedGraphMedium org.contikios.cooja.radiomediums.SilentRadioMedium org.contikios.cooja.plugins.Visualizer.SKINS = org.contikios.cooja.plugins.skins.DGRMVisualizerSkin - diff --git a/tools/cooja/java/org/contikios/cooja/plugins/BaseRSSIconf.java b/tools/cooja/java/org/contikios/cooja/plugins/BaseRSSIconf.java new file mode 100644 index 000000000..bf0982902 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/plugins/BaseRSSIconf.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +package org.contikios.cooja.plugins; + +import java.awt.BorderLayout; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellEditor; + +import org.apache.log4j.Logger; + +import org.contikios.cooja.ClassDescription; +import org.contikios.cooja.Cooja; +import org.contikios.cooja.PluginType; +import org.contikios.cooja.Simulation; +import org.contikios.cooja.SupportedArguments; +import org.contikios.cooja.VisPlugin; +import org.contikios.cooja.interfaces.Radio; +import org.contikios.cooja.radiomediums.AbstractRadioMedium; +import org.contikios.cooja.radiomediums.DirectedGraphMedium; + + +/** + * Simple user interface for configuring BaseRSSI of Motes + * + * @see DirectedGraphMedium + * @author Sebastian Schinabeck + */ +@ClassDescription("Base RSSI") +@PluginType(PluginType.SIM_PLUGIN) +@SupportedArguments(radioMediums = { AbstractRadioMedium.class }) + +public class BaseRSSIconf extends VisPlugin { + private static final long serialVersionUID = 8955776548892545638L; + private static Logger logger = Logger.getLogger(BaseRSSIconf.class); + + private final static int IDX_Mote = 0; + private final static int IDX_BaseRSSI = 1; + + private final static String[] COLUMN_NAMES = new String[] { "Mote", + "BaseRSSI (-45!)" }; // TODO maybe include offset of -45 directly + + private Cooja gui = null; + private AbstractRadioMedium radioMedium = null; + private Observer changeObserver; + private JTable motesTable = null; + private JComboBox combo = new JComboBox(); + private Simulation sim = null; + + + + public BaseRSSIconf(Simulation sim, Cooja gui) { + super("Base RSSI Configurator", gui); + this.gui = gui; + this.sim = sim; + radioMedium = (AbstractRadioMedium) sim.getRadioMedium(); + + changeObserver = new Observer() { + public void update(Observable obs, Object obj) { + logger.debug("Changed"); + model.fireTableDataChanged(); + + } + }; + + radioMedium.addRadioMediumObserver(changeObserver); + + sim.addObserver(changeObserver); + + /* Represent motes and RSSI by table */ + motesTable = new JTable(model) { + private static final long serialVersionUID = -4680013510092815210L; + + public TableCellEditor getCellEditor(int row, int column) { + combo.removeAllItems(); + if (column == IDX_Mote) { + for (double d = 1.0; d <= radioMedium.getRegisteredRadios().length; d += 1.0) { + combo.addItem(d); + } + } else if (column == IDX_BaseRSSI) { + for (double d = AbstractRadioMedium.SS_STRONG; d >= AbstractRadioMedium.SS_NOTHING; d -= 1) { + combo.addItem((int) d); + } + } + + return super.getCellEditor(row, column); + } + }; + motesTable.setFillsViewportHeight(true); + combo.setEditable(true); + + motesTable.getColumnModel().getColumn(IDX_Mote) + .setCellRenderer(new DefaultTableCellRenderer() { // TODO ???? + private static final long serialVersionUID = 4470088575039698508L; + + public void setValue(Object value) { + if (!(value instanceof Double)) { + setText(value.toString()); + return; + } + double v = ((Double) value).doubleValue(); + setText(String.format("%1.1f", v)); + } + }); + motesTable.getColumnModel().getColumn(IDX_BaseRSSI) + .setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = -7170745293267593460L; + + public void setValue(Object value) { + if (!(value instanceof Double)) { + setText(value.toString()); + return; + } + double v = ((Double) value).doubleValue(); + setText(String.format("%1.1f dBm", v)); + } + }); + motesTable.getColumnModel().getColumn(IDX_Mote) + .setCellEditor(new DefaultCellEditor(combo)); + motesTable.getColumnModel().getColumn(IDX_BaseRSSI) + .setCellEditor(new DefaultCellEditor(combo)); + + motesTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); + motesTable.getSelectionModel().setSelectionMode( + ListSelectionModel.SINGLE_SELECTION); + + + add(BorderLayout.CENTER, new JScrollPane(motesTable)); + + model.fireTableDataChanged(); + setSize(400, 300); + } + + + final AbstractTableModel model = new AbstractTableModel() { + private static final long serialVersionUID = 9101118401527171218L; + + public String getColumnName(int column) { + if (column < 0 || column >= COLUMN_NAMES.length) { + return ""; + } + return COLUMN_NAMES[column]; + } + + public int getRowCount() { + return radioMedium.getRegisteredRadios().length; + } + + public int getColumnCount() { + return COLUMN_NAMES.length; + } + + public Object getValueAt(int row, int column) { + if (row < 0 || row >= radioMedium.getRegisteredRadios().length) { + return ""; + } + if (column < 0 || column >= COLUMN_NAMES.length) { + return ""; + } + Radio radio = radioMedium.getRegisteredRadios()[row]; // sim.getMotes()... + if (column == IDX_Mote) { + return radio.getMote(); + } + if (column == IDX_BaseRSSI) { + return radioMedium.getBaseRssi(radio); + } + return ""; + } + + public void setValueAt(Object value, int row, int column) { + if (row < 0 || row >= radioMedium.getRegisteredRadios().length) { + return; + } + if (column < 0 || column >= COLUMN_NAMES.length) { + return; + } + + Radio radio = radioMedium.getRegisteredRadios()[row]; + try { + if (column == IDX_BaseRSSI) { + radioMedium.setBaseRssi(radio, + ((Number) value).doubleValue()); + } else { + super.setValueAt(value, row, column); + } + + } catch (ClassCastException e) { + } + } + + public boolean isCellEditable(int row, int column) { + if (row < 0 || row >= radioMedium.getRegisteredRadios().length) { + return false; + } + + if (column == IDX_Mote) { + gui.signalMoteHighlight(radioMedium.getRegisteredRadios()[row] + .getMote()); + return false; + } + if (column == IDX_BaseRSSI) { + gui.signalMoteHighlight(radioMedium.getRegisteredRadios()[row] + .getMote()); + return true; + } + return false; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + }; + + public void closePlugin() { + radioMedium.deleteRadioMediumObserver(changeObserver); + sim.deleteObserver(changeObserver); + } + +} diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java b/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java index 742dbeaf3..0aed97d52 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java @@ -31,8 +31,13 @@ package org.contikios.cooja.radiomediums; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; import java.util.Observable; import java.util.Observer; +import java.util.WeakHashMap; import org.apache.log4j.Logger; @@ -44,6 +49,7 @@ import org.contikios.cooja.Simulation; import org.contikios.cooja.TimeEvent; import org.contikios.cooja.interfaces.CustomDataRadio; import org.contikios.cooja.interfaces.Radio; +import org.jdom.Element; /** * Abstract radio medium provides basic functionality for implementing radio @@ -68,6 +74,8 @@ public abstract class AbstractRadioMedium extends RadioMedium { public static final double SS_NOTHING = -100; public static final double SS_STRONG = -10; public static final double SS_WEAK = -95; + protected Map baseRssi = java.util.Collections.synchronizedMap(new HashMap()); + protected Map sendRssi = java.util.Collections.synchronizedMap(new HashMap()); private ArrayList registeredRadios = new ArrayList(); @@ -136,7 +144,7 @@ public abstract class AbstractRadioMedium extends RadioMedium { /* Reset signal strengths */ for (Radio radio : getRegisteredRadios()) { - radio.setCurrentSignalStrength(SS_NOTHING); + radio.setCurrentSignalStrength(getBaseRssi(radio)); } /* Set signal strength to strong on destinations */ @@ -454,6 +462,68 @@ public abstract class AbstractRadioMedium extends RadioMedium { updateSignalStrengths(); } + /** + * Get the RSSI value that is set when there is "silence" + * + * @param radio + * The radio to get the base RSSI for + * @return The base RSSI value; Default: SS_NOTHING + */ + public double getBaseRssi(Radio radio) { + Double rssi = baseRssi.get(radio); + if (rssi == null) { + rssi = SS_NOTHING; + } + return rssi; + } + + /** + * Set the base RSSI for a radio. This value is set when there is "silence" + * + * @param radio + * The radio to set the RSSI value for + * @param rssi + * The RSSI value to set during silence + */ + public void setBaseRssi(Radio radio, double rssi) { + baseRssi.put(radio, rssi); + simulation.invokeSimulationThread(new Runnable() { + @Override + public void run() { + updateSignalStrengths(); + } + }); + } + + + /** + * Get the minimum RSSI value that is set when the radio is sending + * + * @param radio + * The radio to get the send RSSI for + * @return The send RSSI value; Default: SS_STRONG + */ + public double getSendRssi(Radio radio) { + Double rssi = sendRssi.get(radio); + if (rssi == null) { + rssi = SS_STRONG; + } + return rssi; + } + + /** + * Set the send RSSI for a radio. This is the minimum value when the radio is + * sending + * + * @param radio + * The radio to set the RSSI value for + * @param rssi + * The minimum RSSI value to set when sending + */ + public void setSendRssi(Radio radio, double rssi) { + sendRssi.put(radio, rssi); + } + public void addRadioMediumObserver(Observer observer) { radioMediumObservable.addObserver(observer); } @@ -469,5 +539,46 @@ public abstract class AbstractRadioMedium extends RadioMedium { public RadioConnection getLastConnection() { return lastConnection; } + public Collection getConfigXML() { + Collection config = new ArrayList(); + for(Entry ent: baseRssi.entrySet()){ + Element element = new Element("BaseRSSIConfig"); + element.setAttribute("Mote", "" + ent.getKey().getMote().getID()); + element.addContent("" + ent.getValue()); + config.add(element); + } + + for(Entry ent: sendRssi.entrySet()){ + Element element = new Element("SendRSSIConfig"); + element.setAttribute("Mote", "" + ent.getKey().getMote().getID()); + element.addContent("" + ent.getValue()); + config.add(element); + } + + return config; + } + + private Collection delayedConfiguration = null; + + public boolean setConfigXML(final Collection configXML, boolean visAvailable) { + delayedConfiguration = configXML; + return true; + } + + public void simulationFinishedLoading() { + if (delayedConfiguration == null) { + return; + } + + for (Element element : delayedConfiguration) { + if (element.getName().equals("BaseRSSIConfig")) { + Radio r = simulation.getMoteWithID(Integer.parseInt(element.getAttribute("Mote").getValue())).getInterfaces().getRadio(); + setBaseRssi(r, Double.parseDouble(element.getText())); + } else if (element.getName().equals("SendRSSIConfig")) { + Radio r = simulation.getMoteWithID(Integer.parseInt(element.getAttribute("Mote").getValue())).getInterfaces().getRadio(); + setSendRssi(r, Double.parseDouble(element.getText())); + } + } + } } diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java b/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java index c9bac3f0d..b728bb1ff 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java @@ -144,21 +144,23 @@ public class DirectedGraphMedium extends AbstractRadioMedium { } } + + public void updateSignalStrengths() { - /* Reset signal strengths */ + /* Reset signal strengths (Default: SS_NOTHING) */ for (Radio radio : getRegisteredRadios()) { - radio.setCurrentSignalStrength(SS_NOTHING); + radio.setCurrentSignalStrength(getBaseRssi(radio)); } /* Set signal strengths */ RadioConnection[] conns = getActiveConnections(); for (RadioConnection conn : conns) { - /* When sending RSSI is Strong! - * TODO: is this reasonable + /* + * Set sending RSSI. (Default: SS_STRONG) */ - if (conn.getSource().getCurrentSignalStrength() < SS_STRONG) { - conn.getSource().setCurrentSignalStrength(SS_STRONG); + if (conn.getSource().getCurrentSignalStrength() < getSendRssi(conn.getSource())) { + conn.getSource().setCurrentSignalStrength(getSendRssi(conn.getSource())); } //Maximum reception signal of all possible radios received DGRMDestinationRadio dstRadios[] = getPotentialDestinations(conn.getSource()); @@ -311,10 +313,10 @@ public class DirectedGraphMedium extends AbstractRadioMedium { } public Collection getConfigXML() { - ArrayList config = new ArrayList(); - Element element; + Collection config = super.getConfigXML(); for (Edge edge: getEdges()) { + Element element; element = new Element("edge"); element.addContent(edge.getConfigXML()); config.add(element); @@ -325,6 +327,8 @@ public class DirectedGraphMedium extends AbstractRadioMedium { private Collection delayedConfiguration = null; public boolean setConfigXML(Collection configXML, boolean visAvailable) { + super.setConfigXML(configXML, visAvailable); + random = simulation.getRandomGenerator(); /* Wait until simulation has been loaded */ @@ -337,6 +341,8 @@ public void simulationFinishedLoading() { return; } + super.simulationFinishedLoading(); + boolean oldConfig = false; for (Element element : delayedConfiguration) { if (element.getName().equals("edge")) { diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java b/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java index c469bb32e..e0ff8af38 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java @@ -276,7 +276,7 @@ public class UDGM extends AbstractRadioMedium { /* Reset signal strengths */ for (Radio radio : getRegisteredRadios()) { - radio.setCurrentSignalStrength(SS_NOTHING); + radio.setCurrentSignalStrength(getBaseRssi(radio)); } /* Set signal strength to below strong on destinations */ @@ -341,7 +341,7 @@ public class UDGM extends AbstractRadioMedium { } public Collection getConfigXML() { - ArrayList config = new ArrayList(); + Collection config = super.getConfigXML(); Element element; /* Transmitting range */ @@ -368,6 +368,7 @@ public class UDGM extends AbstractRadioMedium { } public boolean setConfigXML(Collection configXML, boolean visAvailable) { + super.setConfigXML(configXML, visAvailable); for (Element element : configXML) { if (element.getName().equals("transmitting_range")) { TRANSMITTING_RANGE = Double.parseDouble(element.getText());