From b949a036f255007b1b18e5919413eb91f07f960f Mon Sep 17 00:00:00 2001 From: fros4943 Date: Tue, 24 Mar 2009 15:46:29 +0000 Subject: [PATCH] a few simple visualizer skins --- .../plugins/skins/BasicVisualizerSkin.java | 71 ++++ .../plugins/skins/LEDVisualizerSkin.java | 139 +++++++ .../plugins/skins/LogLEDVisualizerSkin.java | 75 ++++ .../plugins/skins/LogVisualizerSkin.java | 130 ++++++ .../plugins/skins/UDGMVisualizerSkin.java | 390 ++++++++++++++++++ 5 files changed, 805 insertions(+) create mode 100644 tools/cooja/java/se/sics/cooja/plugins/skins/BasicVisualizerSkin.java create mode 100644 tools/cooja/java/se/sics/cooja/plugins/skins/LEDVisualizerSkin.java create mode 100644 tools/cooja/java/se/sics/cooja/plugins/skins/LogLEDVisualizerSkin.java create mode 100644 tools/cooja/java/se/sics/cooja/plugins/skins/LogVisualizerSkin.java create mode 100644 tools/cooja/java/se/sics/cooja/plugins/skins/UDGMVisualizerSkin.java diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/BasicVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/BasicVisualizerSkin.java new file mode 100644 index 000000000..bfa59f6d7 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/BasicVisualizerSkin.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: BasicVisualizerSkin.java,v 1.1 2009/03/24 15:46:29 fros4943 Exp $ + */ + +package se.sics.cooja.plugins.skins; + +import java.awt.Color; +import java.awt.Graphics; + +import org.apache.log4j.Logger; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.Simulation; +import se.sics.cooja.plugins.Visualizer; +import se.sics.cooja.plugins.VisualizerSkin; + +/** + * Basic visualizer skin. Paints all motes black. + * + * @author Fredrik Osterlind + */ +@ClassDescription("[select visualizer skin]") +public class BasicVisualizerSkin implements VisualizerSkin { + private static Logger logger = Logger.getLogger(BasicVisualizerSkin.class); + + private Visualizer visualizer = null; + + public void setActive(Simulation simulation, Visualizer vis) { + this.visualizer = vis; + } + + public void setInactive() { + } + + public Color[] getColorOf(Mote mote) { + return new Color[] { Color.BLACK }; + } + + public void paintSkin(Graphics g) { + /* Just paint motes */ + visualizer.paintSkinGeneric(g); + } +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/LEDVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/LEDVisualizerSkin.java new file mode 100644 index 000000000..3aabfc3e7 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/LEDVisualizerSkin.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: LEDVisualizerSkin.java,v 1.1 2009/03/24 15:46:29 fros4943 Exp $ + */ + +package se.sics.cooja.plugins.skins; + +import java.awt.Color; +import java.awt.Graphics; +import java.util.Observable; +import java.util.Observer; + +import org.apache.log4j.Logger; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.LED; +import se.sics.cooja.plugins.Visualizer; +import se.sics.cooja.plugins.VisualizerSkin; + +/** + * Visualizer skin for LEDs. + * + * Colors motes according to current LED state. + * + * @author Fredrik Osterlind + */ +@ClassDescription("LEDs") +public class LEDVisualizerSkin implements VisualizerSkin { + private static Logger logger = Logger.getLogger(LEDVisualizerSkin.class); + + private Simulation simulation = null; + private Visualizer visualizer = null; + + private Observer ledObserver = new Observer() { + public void update(Observable obs, Object obj) { + visualizer.repaint(); + } + }; + private Observer simObserver = new Observer() { + public void update(Observable obs, Object obj) { + + /* Observe LEDs */ + for (Mote mote: simulation.getMotes()) { + LED led = mote.getInterfaces().getLED(); + if (led != null) { + led.addObserver(ledObserver); + } + } + visualizer.repaint(); + } + }; + + public void setActive(Simulation simulation, Visualizer vis) { + this.simulation = simulation; + this.visualizer = vis; + + simulation.addObserver(simObserver); + simObserver.update(null, null); + } + + public void setInactive() { + simulation.deleteObserver(simObserver); + for (Mote mote: simulation.getMotes()) { + LED led = mote.getInterfaces().getLED(); + if (led != null) { + led.deleteObserver(ledObserver); + } + } + } + + public Color[] getColorOf(Mote mote) { + LED led = mote.getInterfaces().getLED(); + if (led == null) { + return new Color[] { Color.GRAY }; + } + if (!led.isAnyOn()) { + return new Color[] { Color.BLACK }; + } + + if (led.isGreenOn() && led.isRedOn() && led.isYellowOn()) { + return new Color[] { Color.WHITE }; + } + + if (led.isRedOn()) { + if (led.isGreenOn()) { + return new Color[] { Color.RED, Color.GREEN }; + } + if (led.isYellowOn()) { + return new Color[] { Color.RED, Color.YELLOW }; + } + return new Color[] { Color.RED }; + } + + if (led.isGreenOn()) { + if (led.isYellowOn()) { + return new Color[] { Color.YELLOW, Color.GREEN }; + } + return new Color[] { Color.GREEN }; + } + + if (led.isYellowOn()) { + return new Color[] { Color.YELLOW }; + } + + return new Color[] { Color.BLACK }; + } + + public void paintSkin(Graphics g) { + visualizer.paintSkinGeneric(g); + } +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/LogLEDVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/LogLEDVisualizerSkin.java new file mode 100644 index 000000000..25bb94d8b --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/LogLEDVisualizerSkin.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: LogLEDVisualizerSkin.java,v 1.1 2009/03/24 15:46:29 fros4943 Exp $ + */ + +package se.sics.cooja.plugins.skins; + +import java.awt.Color; +import java.awt.Graphics; +import org.apache.log4j.Logger; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.Simulation; +import se.sics.cooja.plugins.Visualizer; +import se.sics.cooja.plugins.VisualizerSkin; + +/** + * Visualizer skin for both Log output and LEDs. + * + * @see LEDVisualizerSkin + * @see LogVisualizerSkin + * @author Fredrik Osterlind + */ +@ClassDescription("printf()'s + LEDs") +public class LogLEDVisualizerSkin implements VisualizerSkin { + private static Logger logger = Logger.getLogger(LogLEDVisualizerSkin.class); + + private LEDVisualizerSkin ledSkin = new LEDVisualizerSkin(); + private LogVisualizerSkin logSkin = new LogVisualizerSkin(); + + public void setActive(Simulation simulation, Visualizer vis) { + ledSkin.setActive(simulation, vis); + logSkin.setActive(simulation, vis); + } + + public void setInactive() { + ledSkin.setInactive(); + logSkin.setInactive(); + } + + public Color[] getColorOf(Mote mote) { + return ledSkin.getColorOf(mote); + } + + public void paintSkin(Graphics g) { + logSkin.paintSkin(g); + } +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/LogVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/LogVisualizerSkin.java new file mode 100644 index 000000000..7642f917f --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/LogVisualizerSkin.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: LogVisualizerSkin.java,v 1.1 2009/03/24 15:46:29 fros4943 Exp $ + */ + +package se.sics.cooja.plugins.skins; + +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; +import java.util.Observable; +import java.util.Observer; + +import org.apache.log4j.Logger; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.Log; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.plugins.Visualizer; +import se.sics.cooja.plugins.VisualizerSkin; + +/** + * Visualizer skin for Log output. + * + * Paints the last log message above each mote. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Log output: printf()'s") +public class LogVisualizerSkin implements VisualizerSkin { + private static Logger logger = Logger.getLogger(LogVisualizerSkin.class); + + private Simulation simulation = null; + private Visualizer visualizer = null; + + private Observer logObserver = new Observer() { + public void update(Observable obs, Object obj) { + visualizer.repaint(); + } + }; + private Observer simObserver = new Observer() { + public void update(Observable obs, Object obj) { + + /* Observe logs */ + for (Mote mote: simulation.getMotes()) { + Log log = mote.getInterfaces().getLog(); + if (log != null) { + log.addObserver(logObserver); + } + } + visualizer.repaint(); + } + }; + + public void setActive(Simulation simulation, Visualizer vis) { + this.simulation = simulation; + this.visualizer = vis; + + simulation.addObserver(simObserver); + simObserver.update(null, null); + } + + public void setInactive() { + simulation.deleteObserver(simObserver); + for (Mote mote: simulation.getMotes()) { + Log log = mote.getInterfaces().getLog(); + if (log != null) { + log.deleteObserver(logObserver); + } + } + } + + public Color[] getColorOf(Mote mote) { + return new Color[] { Color.BLACK }; + } + + public void paintSkin(Graphics g) { + visualizer.paintSkinGeneric(g); + + FontMetrics fm = g.getFontMetrics(); + + /* Paint last output below motes */ + Mote[] allMotes = simulation.getMotes(); + for (Mote mote: allMotes) { + Log log = mote.getInterfaces().getLog(); + if (log == null) { + continue; + } + String msg = log.getLastLogMessage(); + if (msg == null) { + continue; + } + + Position pos = mote.getInterfaces().getPosition(); + Point pixel = visualizer.transformPositionToPixel(pos); + + int msgWidth = fm.stringWidth(msg); + g.drawString(msg, pixel.x - msgWidth/2, pixel.y - Visualizer.MOTE_RADIUS); + } + } +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/UDGMVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/UDGMVisualizerSkin.java new file mode 100644 index 000000000..8aaea1e11 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/UDGMVisualizerSkin.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: UDGMVisualizerSkin.java,v 1.1 2009/03/24 15:46:29 fros4943 Exp $ + */ + +package se.sics.cooja.plugins.skins; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.Observable; +import java.util.Observer; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.apache.log4j.Logger; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.RadioConnection; +import se.sics.cooja.Simulation; +import se.sics.cooja.contikimote.interfaces.ContikiRadio; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; +import se.sics.cooja.plugins.Visualizer; +import se.sics.cooja.plugins.VisualizerSkin; +import se.sics.cooja.plugins.Visualizer.SimulationMenuAction; +import se.sics.cooja.radiomediums.UDGM; + +/** + * Visualizer skin for Unit Disk Graph radio medium. + * + * Allows a user to change the collective TX/interference ranges, + * and the TX/RX success ratio. + * + * Transmitting motes are painted blue. + * Receiving motes are painted green. + * Interfered motes are painted red. + * Motes without radios are painted gray. + * All other motes are painted white. + * + * @see UDGM + * @author Fredrik Osterlind + */ +@ClassDescription("Radio environment (UDGM)") +public class UDGMVisualizerSkin implements VisualizerSkin { + private static Logger logger = Logger.getLogger(UDGMVisualizerSkin.class); + + private Simulation simulation = null; + private Visualizer visualizer = null; + private UDGM radioMedium = null; + private Observer radioMediumObserver; + + private JSpinner txRangeSpinner = null; + private JSpinner interferenceRangeSpinner = null; + private JSpinner successRatioTxSpinner = null; + private JSpinner successRatioRxSpinner = null; + + private Mote selectedMote = null; + + private MouseListener selectMoteMouseListener = new MouseListener() { + public void mouseExited(MouseEvent e) { } + public void mouseEntered(MouseEvent e) { } + public void mouseReleased(MouseEvent e) { } + public void mouseClicked(MouseEvent e) { } + + public void mousePressed(MouseEvent e) { + Mote[] motes = visualizer.findMotesAtPosition(e.getX(), e.getY()); + if (motes == null || motes.length == 0) { + selectedMote = null; + txRangeSpinner.setVisible(false); + interferenceRangeSpinner.setVisible(false); + successRatioTxSpinner.setVisible(false); + successRatioRxSpinner.setVisible(false); + visualizer.repaint(); + return; + } + + selectedMote = motes[0]; + visualizer.repaint(); + } + }; + + public void setActive(Simulation simulation, Visualizer vis) { + this.simulation = simulation; + this.visualizer = vis; + this.radioMedium = (UDGM) simulation.getRadioMedium(); + + /* Spinner GUI components */ + SpinnerNumberModel transmissionModel = new SpinnerNumberModel(); + transmissionModel.setValue(new Double(radioMedium.TRANSMITTING_RANGE)); + transmissionModel.setStepSize(new Double(1.0)); // 1m + transmissionModel.setMinimum(new Double(0.0)); + + SpinnerNumberModel interferenceModel = new SpinnerNumberModel(); + interferenceModel.setValue(new Double(radioMedium.INTERFERENCE_RANGE)); + interferenceModel.setStepSize(new Double(1.0)); // 1m + interferenceModel.setMinimum(new Double(0.0)); + + SpinnerNumberModel successRatioTxModel = new SpinnerNumberModel(); + successRatioTxModel.setValue(new Double(radioMedium.SUCCESS_RATIO_TX)); + successRatioTxModel.setStepSize(new Double(0.001)); // 0.1% + successRatioTxModel.setMinimum(new Double(0.0)); + successRatioTxModel.setMaximum(new Double(1.0)); + + SpinnerNumberModel successRatioRxModel = new SpinnerNumberModel(); + successRatioRxModel.setValue(new Double(radioMedium.SUCCESS_RATIO_RX)); + successRatioRxModel.setStepSize(new Double(0.001)); // 0.1% + successRatioRxModel.setMinimum(new Double(0.0)); + successRatioRxModel.setMaximum(new Double(1.0)); + + JSpinner.NumberEditor editor; + txRangeSpinner = new JSpinner(transmissionModel); + editor = new JSpinner.NumberEditor(txRangeSpinner, "0m"); + txRangeSpinner.setEditor(editor); + interferenceRangeSpinner = new JSpinner(interferenceModel); + editor = new JSpinner.NumberEditor(interferenceRangeSpinner, "0m"); + interferenceRangeSpinner.setEditor(editor); + successRatioTxSpinner = new JSpinner(successRatioTxModel); + editor = new JSpinner.NumberEditor(successRatioTxSpinner, "0.0%"); + successRatioTxSpinner.setEditor(editor); + successRatioRxSpinner = new JSpinner(successRatioRxModel); + editor = new JSpinner.NumberEditor(successRatioRxSpinner, "0.0%"); + successRatioRxSpinner.setEditor(editor); + + ((JSpinner.DefaultEditor) txRangeSpinner.getEditor()).getTextField().setColumns(5); + ((JSpinner.DefaultEditor) interferenceRangeSpinner.getEditor()).getTextField().setColumns(5); + ((JSpinner.DefaultEditor) successRatioTxSpinner.getEditor()).getTextField().setColumns(5); + ((JSpinner.DefaultEditor) successRatioRxSpinner.getEditor()).getTextField().setColumns(5); + txRangeSpinner.setToolTipText("Transmitting range (m)"); + interferenceRangeSpinner.setToolTipText("Interference range (m)"); + successRatioTxSpinner.setToolTipText("Transmission success ratio (%)"); + successRatioRxSpinner.setToolTipText("Reception success ratio (%)"); + + txRangeSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + radioMedium.TRANSMITTING_RANGE = ((SpinnerNumberModel) + txRangeSpinner.getModel()).getNumber().doubleValue(); + visualizer.repaint(); + } + }); + + interferenceRangeSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + radioMedium.INTERFERENCE_RANGE = ((SpinnerNumberModel) + interferenceRangeSpinner.getModel()).getNumber().doubleValue(); + visualizer.repaint(); + } + }); + + successRatioTxSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + radioMedium.SUCCESS_RATIO_TX = ((SpinnerNumberModel) + successRatioTxSpinner.getModel()).getNumber().doubleValue(); + visualizer.repaint(); + } + }); + + successRatioRxSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + radioMedium.SUCCESS_RATIO_RX = ((SpinnerNumberModel) + successRatioRxSpinner.getModel()).getNumber().doubleValue(); + visualizer.repaint(); + } + }); + + txRangeSpinner.setVisible(false); + interferenceRangeSpinner.setVisible(false); + successRatioTxSpinner.setVisible(false); + successRatioRxSpinner.setVisible(false); + + /* Register mouse listener */ + visualizer.getCurrentCanvas().addMouseListener(selectMoteMouseListener); + + /* Register menu actions */ + visualizer.registerSimulationMenuAction(RangeMenuAction.class); + visualizer.registerSimulationMenuAction(SuccessRatioMenuAction.class); + + /* Add (currently invisible) spinners */ + visualizer.getCurrentCanvas().add(txRangeSpinner); + visualizer.getCurrentCanvas().add(interferenceRangeSpinner); + visualizer.getCurrentCanvas().add(successRatioTxSpinner); + visualizer.getCurrentCanvas().add(successRatioRxSpinner); + + /* Start observing radio medium */ + radioMedium.addRadioMediumObserver(radioMediumObserver = new Observer() { + public void update(Observable obs, Object obj) { + visualizer.repaint(); + } + }); + } + + public void setInactive() { + /* Remove mouse listener */ + visualizer.getCurrentCanvas().removeMouseListener(selectMoteMouseListener); + + /* Stop observing radio medium */ + radioMedium.deleteRadioMediumObserver(radioMediumObserver); + radioMediumObserver = null; + radioMedium = null; + + /* Remove spinners */ + visualizer.getCurrentCanvas().remove(txRangeSpinner); + visualizer.getCurrentCanvas().remove(interferenceRangeSpinner); + visualizer.getCurrentCanvas().remove(successRatioTxSpinner); + visualizer.getCurrentCanvas().remove(successRatioRxSpinner); + + /* Unregister menu actions */ + visualizer.unregisterSimulationMenuAction(RangeMenuAction.class); + visualizer.unregisterSimulationMenuAction(SuccessRatioMenuAction.class); + } + + public Color[] getColorOf(Mote mote) { + Radio moteRadio = mote.getInterfaces().getRadio(); + if (moteRadio == null) { + return new Color[] { Color.BLACK }; + } + + if (mote.getState() == Mote.State.DEAD) { + return new Color[] { Color.BLACK }; + } + + if (selectedMote != null && mote == selectedMote) { + return new Color[] { Color.CYAN }; + } + + if (moteRadio instanceof ContikiRadio && !((ContikiRadio) moteRadio).isOn()) { + return new Color[] { Color.GRAY }; + } + + if (moteRadio.isTransmitting()) { + return new Color[] { Color.BLUE }; + } + + if (moteRadio.isInterfered()) { + return new Color[] { Color.RED }; + } + + if (moteRadio.isReceiving()) { + return new Color[] { Color.GREEN }; + } + + return new Color[] { Color.WHITE }; + } + + public void paintSkin(Graphics g) { + /* Paint transmission and interference range for select mote */ + if (selectedMote != null) { + Position motePos = selectedMote.getInterfaces().getPosition(); + + Point pixelCoord = visualizer.transformPositionToPixel(motePos); + int x = pixelCoord.x; + int y = pixelCoord.y; + + // Fetch current output power indicator (scale with as percent) + if (selectedMote.getInterfaces().getRadio() != null) { + Radio selectedRadio = selectedMote.getInterfaces().getRadio(); + double moteInterferenceRange = + radioMedium.INTERFERENCE_RANGE + * ((double) selectedRadio.getCurrentOutputPowerIndicator() + / (double) selectedRadio.getOutputPowerIndicatorMax()); + double moteTransmissionRange = + radioMedium.TRANSMITTING_RANGE + * ((double) selectedRadio.getCurrentOutputPowerIndicator() + / (double) selectedRadio.getOutputPowerIndicatorMax()); + + Point translatedZero = visualizer.transformPositionToPixel(0.0, 0.0, 0.0); + Point translatedInterference = visualizer.transformPositionToPixel(moteInterferenceRange, moteInterferenceRange, 0.0); + Point translatedTransmission = visualizer.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); + + /* Interference range */ + g.setColor(Color.DARK_GRAY); + g.fillOval( + x - translatedInterference.x, + y - translatedInterference.y, + 2 * translatedInterference.x, + 2 * translatedInterference.y); + + /* Transmission range */ + g.setColor(Color.GREEN); + g.fillOval( + x - translatedTransmission.x, + y - translatedTransmission.y, + 2 * translatedTransmission.x, + 2 * translatedTransmission.y); + } + } + + /* Skin generic visualization */ + visualizer.paintSkinGeneric(g); + + /* Paint active connections in black */ + RadioConnection[] conns = radioMedium.getActiveConnections(); + if (conns != null) { + g.setColor(Color.BLACK); + for (RadioConnection conn : conns) { + Point sourcePoint = visualizer.transformPositionToPixel(conn.getSource().getPosition()); + for (Radio destRadio : conn.getDestinations()) { + Position destPos = destRadio.getPosition(); + Point destPoint = visualizer.transformPositionToPixel(destPos); + g.drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y); + } + } + } + + /* Paint past connections in gray */ + conns = radioMedium.getLastTickConnections(); + if (conns != null) { + g.setColor(Color.GRAY); + for (RadioConnection conn : conns) { + Point sourcePoint = visualizer.transformPositionToPixel(conn.getSource().getPosition()); + for (Radio dest : conn.getDestinations()) { + Position destPos = dest.getPosition(); + Point destPoint = visualizer.transformPositionToPixel(destPos); + g.drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y); + } + } + } + } + + protected static class RangeMenuAction implements SimulationMenuAction { + public boolean isEnabled(Simulation simulation) { + return true; + } + + public String getDescription(Simulation simulation) { + return "Change transmission ranges"; + } + + public void doAction(Visualizer visualizer, Simulation simulation) { + UDGMVisualizerSkin skin = (UDGMVisualizerSkin) visualizer.getCurrentSkin(); + skin.txRangeSpinner.setVisible(true); + skin.interferenceRangeSpinner.setVisible(true); + visualizer.repaint(); + } + }; + + protected static class SuccessRatioMenuAction implements SimulationMenuAction { + public boolean isEnabled(Simulation simulation) { + return true; + } + + public String getDescription(Simulation simulation) { + return "Change TX/RX success ratio"; + } + + public void doAction(Visualizer visualizer, Simulation simulation) { + UDGMVisualizerSkin skin = (UDGMVisualizerSkin) visualizer.getCurrentSkin(); + skin.successRatioTxSpinner.setVisible(true); + skin.successRatioRxSpinner.setVisible(true); + visualizer.repaint(); + } + }; + +}