diff --git a/core/dev/radio.h b/core/dev/radio.h index b530f9c09..f4e6bdd09 100644 --- a/core/dev/radio.h +++ b/core/dev/radio.h @@ -96,6 +96,7 @@ enum { RADIO_TX_OK, RADIO_TX_ERR, RADIO_TX_COLLISION, + RADIO_TX_NOACK, }; #endif /* __RADIO_H__ */ diff --git a/core/net/mac/nullrdc.c b/core/net/mac/nullrdc.c index 1a7483e4c..6b8cbe2e3 100644 --- a/core/net/mac/nullrdc.c +++ b/core/net/mac/nullrdc.c @@ -42,6 +42,7 @@ #include "net/mac/nullrdc.h" #include "net/packetbuf.h" #include "net/netstack.h" +#include #define DEBUG 0 #if DEBUG @@ -59,6 +60,14 @@ #endif /* NULLRDC_CONF_802154_AUTOACK */ #endif /* NULLRDC_802154_AUTOACK */ +#ifndef NULLRDC_802154_AUTOACK_HW +#ifdef NULLRDC_CONF_802154_AUTOACK_HW +#define NULLRDC_802154_AUTOACK_HW NULLRDC_CONF_802154_AUTOACK_HW +#else +#define NULLRDC_802154_AUTOACK_HW 0 +#endif /* NULLRDC_CONF_802154_AUTOACK_HW */ +#endif /* NULLRDC_802154_AUTOACK_HW */ + #if NULLRDC_802154_AUTOACK #include "sys/rtimer.h" #include "dev/watchdog.h" @@ -66,7 +75,9 @@ #define ACK_WAIT_TIME RTIMER_SECOND / 2500 #define AFTER_ACK_DETECTED_WAIT_TIME RTIMER_SECOND / 1500 #define ACK_LEN 3 +#endif /* NULLRDC_802154_AUTOACK */ +#if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW struct seqno { rimeaddr_t sender; uint8_t seqno; @@ -79,7 +90,7 @@ struct seqno { #endif /* NETSTACK_CONF_MAC_SEQNO_HISTORY */ static struct seqno received_seqnos[MAX_SEQNOS]; -#endif /* NULLRDC_802154_AUTOACK */ +#endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */ /*---------------------------------------------------------------------------*/ static void @@ -87,9 +98,9 @@ send_packet(mac_callback_t sent, void *ptr) { int ret; packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); -#if NULLRDC_802154_AUTOACK +#if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); -#endif /* NULLRDC_802154_AUTOACK */ +#endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */ if(NETSTACK_FRAMER.create() == 0) { /* Failed to allocate space for headers */ @@ -171,6 +182,9 @@ send_packet(mac_callback_t sent, void *ptr) case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; + case RADIO_TX_NOACK: + ret = MAC_TX_NOACK; + break; default: ret = MAC_TX_ERR; break; @@ -193,7 +207,7 @@ packet_input(void) if(NETSTACK_FRAMER.parse() == 0) { PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen()); } else { -#if NULLRDC_802154_AUTOACK +#if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW /* Check for duplicate packet by comparing the sequence number of the incoming packet with the last few ones we saw. */ int i; diff --git a/cpu/mc1322x/contiki-maca.c b/cpu/mc1322x/contiki-maca.c index d90598673..886b15ac2 100644 --- a/cpu/mc1322x/contiki-maca.c +++ b/cpu/mc1322x/contiki-maca.c @@ -62,6 +62,7 @@ #endif static volatile uint8_t tx_complete; +static volatile uint8_t tx_status; /* contiki mac driver */ @@ -98,11 +99,11 @@ static process_event_t event_data_ready; static volatile packet_t prepped_p; int contiki_maca_init(void) { - trim_xtal(); - vreg_init(); - contiki_maca_init(); - set_channel(0); /* channel 11 */ - set_power(0x12); /* 0x12 is the highest, not documented */ +// trim_xtal(); +// vreg_init(); +// contiki_maca_init(); +// set_channel(0); /* channel 11 */ +// set_power(0x12); /* 0x12 is the highest, not documented */ return 1; } @@ -228,8 +229,6 @@ int contiki_maca_transmit(unsigned short transmit_len) { #if BLOCKING_TX /* block until tx_complete, set by contiki_maca_tx_callback */ - /* there are many places in contiki that rely on the */ - /* transmit call to block */ while(!tx_complete && (tx_head != 0)); #endif } @@ -237,7 +236,18 @@ int contiki_maca_transmit(unsigned short transmit_len) { int contiki_maca_send(const void *payload, unsigned short payload_len) { contiki_maca_prepare(payload, payload_len); contiki_maca_transmit(payload_len); - return RADIO_TX_OK; + switch(tx_status) { + case SUCCESS: + case CRC_FAILED: /* CRC_FAILED is usually an ack */ + PRINTF("TXOK\n\r"); + return RADIO_TX_OK; + case NO_ACK: + PRINTF("NOACK\n\r"); + return RADIO_TX_NOACK; + default: + PRINTF("TXERR\n\r"); + return RADIO_TX_ERR; + } } PROCESS(contiki_maca_process, "maca process"); @@ -254,12 +264,12 @@ PROCESS_THREAD(contiki_maca_process, ev, data) /* check if there is a request to turn the radio on or off */ if(contiki_maca_request_on == 1) { contiki_maca_request_on = 0; - maca_on(); +// maca_on(); } if(contiki_maca_request_off == 1) { contiki_maca_request_off = 0; - maca_off(); +// maca_off(); } if (rx_head != NULL) { @@ -270,6 +280,10 @@ PROCESS_THREAD(contiki_maca_process, ev, data) NETSTACK_RDC.input(); } } + /* Call ourself again to handle remaining packets in the queue */ + if (rx_head != NULL) { + process_poll(&contiki_maca_process); + } }; @@ -284,5 +298,6 @@ void maca_rx_callback(volatile packet_t *p __attribute((unused))) { #if BLOCKING_TX void maca_tx_callback(volatile packet_t *p __attribute((unused))) { tx_complete = 1; + tx_status = p->status; } #endif diff --git a/cpu/mc1322x/mc1322x.lds b/cpu/mc1322x/mc1322x.lds index df3ca8895..2e6dddf75 100644 --- a/cpu/mc1322x/mc1322x.lds +++ b/cpu/mc1322x/mc1322x.lds @@ -18,7 +18,7 @@ FIQ_STACK_SIZE = 256; SVC_STACK_SIZE = 256; ABT_STACK_SIZE = 16; UND_STACK_SIZE = 16; -HEAP_SIZE = 1024; +HEAP_SIZE = 2048; /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = 0x00400000); . = 0x00400000; diff --git a/platform/redbee-econotag/contiki-conf.h b/platform/redbee-econotag/contiki-conf.h index 6f9edc11e..0839607f9 100644 --- a/platform/redbee-econotag/contiki-conf.h +++ b/platform/redbee-econotag/contiki-conf.h @@ -84,7 +84,8 @@ #define CONTIKI_MACA_RAW_MODE 0 #define USE_32KHZ_XTAL 0 -#define BLOCKING_TX 0 +#define BLOCKING_TX 1 +#define NULLRDC_CONF_802154_AUTOACK_HW 1 /* end of mc1322x specific config. */ diff --git a/platform/redbee-econotag/contiki-mc1322x-main.c b/platform/redbee-econotag/contiki-mc1322x-main.c index 7d822d4bb..a8b53e6c4 100644 --- a/platform/redbee-econotag/contiki-mc1322x-main.c +++ b/platform/redbee-econotag/contiki-mc1322x-main.c @@ -66,7 +66,7 @@ #include "contiki-maca.h" #include "contiki-uart.h" -#define DEBUG 1 +#define DEBUG 0 #if DEBUG #include #define PRINTF(...) printf(__VA_ARGS__) @@ -86,14 +86,6 @@ #define RIMEADDR_NBYTES 8 #endif -#define PLATFORM_DEBUG 1 -#if PLATFORM_DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif - - #if UIP_CONF_ROUTER #ifndef UIP_ROUTER_MODULE @@ -236,30 +228,27 @@ void iab_to_eui64(rimeaddr_t *eui64, uint32_t oui, uint16_t iab, uint32_t ext) { eui64->u8[1] = 0x50; eui64->u8[2] = 0xc2; - /* EUI64 field */ - eui64->u8[3] = 0xff; - eui64->u8[4] = 0xfe; - /* IAB */ - eui64->u8[5] = (iab >> 4) & 0xff; - eui64->u8[6] = (iab & 0xf) << 4; + eui64->u8[3] = (iab >> 4) & 0xff; + eui64->u8[4] = (iab & 0xf) << 4; /* EXT */ - eui64->u8[6] |= ((ext >> 8) & 0xf); - eui64->u8[7] = ext & 0xff; + + eui64->u8[4] = (ext >> 24) & 0xff; + eui64->u8[5] = (ext >> 16) & 0xff; + eui64->u8[6] = (ext >> 8) & 0xff; + eui64->u8[7] = ext & 0xff; } -void oui_to_eui64(rimeaddr_t *eui64, uint32_t oui, uint32_t ext) { +void oui_to_eui64(rimeaddr_t *eui64, uint32_t oui, uint64_t ext) { /* OUI */ eui64->u8[0] = (oui >> 16) & 0xff; eui64->u8[1] = (oui >> 8) & 0xff; eui64->u8[2] = oui & 0xff; - /* EUI64 field */ - eui64->u8[3] = 0xff; - eui64->u8[4] = 0xfe; - /* EXT */ + eui64->u8[3] = (ext >> 32) & 0xff; + eui64->u8[4] = (ext >> 24) & 0xff; eui64->u8[5] = (ext >> 16) & 0xff; eui64->u8[6] = (ext >> 8) & 0xff; eui64->u8[7] = ext & 0xff; @@ -293,7 +282,7 @@ set_rimeaddr(rimeaddr_t *addr) iab_to_eui64(&eui64, OUI, IAB, EXT_ID); #else /* ifdef EXT_ID */ PRINTF("address in flash blank, setting to defined IAB with a random extension.\n\r"); - iab_to_eui64(&eui64, OUI, IAB, *MACA_RANDOM & 0xfff); + iab_to_eui64(&eui64, OUI, IAB, *MACA_RANDOM); #endif /* ifdef EXT_ID */ #else /* ifdef IAB */ @@ -303,7 +292,7 @@ set_rimeaddr(rimeaddr_t *addr) oui_to_eui64(&eui64, OUI, EXT_ID); #else /*ifdef EXT_ID */ PRINTF("address in flash blank, setting to defined OUI with a random extension.\n\r"); - oui_to_eui64(&eui64, OUI, *MACA_RANDOM & 0xffffff); + oui_to_eui64(&eui64, OUI, ((*MACA_RANDOM << 32) | *MACA_RANDOM)); #endif /*endif EXTID */ #endif /* ifdef IAB */ @@ -422,6 +411,27 @@ main(void) RF_CHANNEL); #endif /* WITH_UIP6 */ + *MACA_MACPANID = 0xcdab; /* this is the hardcoded contiki pan, register is PACKET order */ + *MACA_MAC16ADDR = 0xffff; /* short addressing isn't used, set this to 0xffff for now */ + + *MACA_MAC64HI = + addr.u8[0] << 24 | + addr.u8[1] << 16 | + addr.u8[2] << 8 | + addr.u8[3]; + *MACA_MAC64LO = + addr.u8[4] << 24 | + addr.u8[5] << 16 | + addr.u8[6] << 8 | + addr.u8[7]; + PRINTF("setting panid 0x%04x\n\r", *MACA_MACPANID); + PRINTF("setting short mac 0x%04x\n\r", *MACA_MAC16ADDR); + PRINTF("setting long mac 0x%08x_%08x\n\r", *MACA_MAC64HI, *MACA_MAC64LO); + +#if NULLRDC_CONF_802154_AUTOACK_HW + set_prm_mode(AUTOACK); +#endif + #if PROFILE_CONF_ON profile_init(); #endif /* PROFILE_CONF_ON */ diff --git a/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java b/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java index dc5d7020a..b90d6de0e 100644 --- a/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java +++ b/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java @@ -31,22 +31,79 @@ package se.sics.mrm; -import java.awt.*; -import java.awt.event.*; -import java.awt.geom.*; +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.io.File; import java.net.URL; import java.text.DecimalFormat; import java.text.NumberFormat; -import java.util.*; -import javax.swing.*; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Observable; +import java.util.Observer; +import java.util.Random; +import java.util.Vector; + +import javax.swing.AbstractButton; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFormattedTextField; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JSeparator; +import javax.swing.JSlider; +import javax.swing.JToolTip; +import javax.swing.Popup; +import javax.swing.PopupFactory; +import javax.swing.ProgressMonitor; import javax.swing.filechooser.FileFilter; + import org.apache.log4j.Logger; import org.jdom.Element; -import se.sics.cooja.*; -import se.sics.cooja.interfaces.*; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.GUI; +import se.sics.cooja.PluginType; +import se.sics.cooja.RadioConnection; +import se.sics.cooja.Simulation; +import se.sics.cooja.VisPlugin; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; /** * The class AreaViewer belongs to the MRM package. @@ -128,7 +185,7 @@ public class AreaViewer extends VisPlugin { private boolean inSelectMode = true; private boolean inTrackMode = false; - private Vector trackedComponents = null; + private ChannelModel.TrackedSignalComponents trackedComponents = null; // Coloring variables private JPanel coloringIntervalPanel = null; @@ -148,6 +205,8 @@ public class AreaViewer extends VisPlugin { private JRadioButton noneButton = null; + private JRadioButton trackModeButton; + /** * Initializes an AreaViewer. * @@ -196,12 +255,13 @@ public class AreaViewer extends VisPlugin { zoomModeButton.setActionCommand("set zoom mode"); zoomModeButton.addActionListener(canvasModeHandler); - JRadioButton trackModeButton = new JRadioButton ("track rays"); + trackModeButton = new JRadioButton ("track rays"); trackModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT); trackModeButton.setContentAreaFilled(false); trackModeButton.setActionCommand("set track rays mode"); trackModeButton.addActionListener(canvasModeHandler); - + trackModeButton.setEnabled(false); + ButtonGroup group = new ButtonGroup(); group.add(selectModeButton); group.add(panModeButton); @@ -565,19 +625,36 @@ public class AreaViewer extends VisPlugin { /** * Listens to mouse event on canvas */ - private MouseListener canvasMouseHandler = new MouseListener() { + private MouseAdapter canvasMouseHandler = new MouseAdapter() { + private Popup popUpToolTip = null; + public void mouseReleased(MouseEvent e) { + if (popUpToolTip != null) { + popUpToolTip.hide(); + popUpToolTip = null; + } } - public void mouseExited(MouseEvent e) { - } - public void mouseClicked(MouseEvent e) { + + public void mousePressed(MouseEvent e) { + if (popUpToolTip != null) { + popUpToolTip.hide(); + popUpToolTip = null; + } + + /* Zoom & Pan */ + lastHandledPosition = new Point(e.getX(), e.getY()); + zoomCenterX = e.getX() / currentZoomX - currentPanX; + zoomCenterY = e.getY() / currentZoomY - currentPanY; + zoomCenterPoint = e.getPoint(); + + /* Select */ if (inSelectMode) { Vector hitRadios = trackClickedRadio(e.getPoint()); - if (hitRadios == null || hitRadios.size() == 0) { if (e.getButton() != MouseEvent.BUTTON1) { selectedRadio = null; channelImage = null; + trackModeButton.setEnabled(false); canvas.repaint(); } return; @@ -589,39 +666,47 @@ public class AreaViewer extends VisPlugin { if (selectedRadio == null || !hitRadios.contains(selectedRadio)) { selectedRadio = hitRadios.firstElement(); + trackModeButton.setEnabled(true); } else { - // Select next in list selectedRadio = hitRadios.get( (hitRadios.indexOf(selectedRadio)+1) % hitRadios.size() ); + trackModeButton.setEnabled(true); } channelImage = null; canvas.repaint(); - } else if (inTrackMode && selectedRadio != null) { - // Calculate real clicked position + return; + } + + /* Track */ + if (inTrackMode && selectedRadio != null) { double realClickedX = e.getX() / currentZoomX - currentPanX; double realClickedY = e.getY() / currentZoomY - currentPanY; - Position radioPosition = currentRadioMedium.getRadioPosition(selectedRadio); + Position radioPosition = selectedRadio.getPosition(); final double radioX = radioPosition.getXCoordinate(); final double radioY = radioPosition.getYCoordinate(); trackedComponents = currentChannelModel.getRaysOfTransmission(radioX, radioY, realClickedX, realClickedY); - canvas.repaint(); + + /* Show popup */ + JToolTip t = AreaViewer.this.createToolTip(); + + String logHtml = + "" + + trackedComponents.log.replace("\n", "
").replace(" pi", " π") + + ""; + t.setTipText(logHtml); + + if (t.getTipText() == null || t.getTipText().equals("")) { + return; + } + popUpToolTip = PopupFactory.getSharedInstance().getPopup( + AreaViewer.this, t, e.getXOnScreen(), e.getYOnScreen()); + popUpToolTip.show(); } - - } - public void mouseEntered(MouseEvent e) { - } - public void mousePressed(MouseEvent e) { - lastHandledPosition = new Point(e.getX(), e.getY()); - - // Set zoom center (real world) - zoomCenterX = e.getX() / currentZoomX - currentPanX; - zoomCenterY = e.getY() / currentZoomY - currentPanY; - zoomCenterPoint = e.getPoint(); } }; @@ -1523,6 +1608,7 @@ public class AreaViewer extends VisPlugin { // Clear selected radio (if any selected) and radio medium coverage selectedRadio = null; channelImage = null; + trackModeButton.setEnabled(false); canvas.repaint(); } }; @@ -1616,7 +1702,7 @@ public class AreaViewer extends VisPlugin { final double height = canvas.getHeight() / currentZoomY; // Get sending radio position - Position radioPosition = currentRadioMedium.getRadioPosition(selectedRadio); + Position radioPosition = selectedRadio.getPosition(); final double radioX = radioPosition.getXCoordinate(); final double radioY = radioPosition.getYCoordinate(); @@ -1990,7 +2076,7 @@ public class AreaViewer extends VisPlugin { // Translate to real world radio position Radio radio = currentRadioMedium.getRegisteredRadio(i); - Position radioPosition = currentRadioMedium.getRadioPosition(radio); + Position radioPosition = radio.getPosition(); g2d.translate( radioPosition.getXCoordinate(), radioPosition.getYCoordinate() @@ -2129,16 +2215,14 @@ public class AreaViewer extends VisPlugin { g2d.setStroke(new BasicStroke((float) 0.0)); Random random = new Random(); /* Do not use main random generator */ - for (int i=0; i < trackedComponents.size(); i++) { + for (Line2D l: trackedComponents.components) { g2d.setColor(new Color(255, random.nextInt(255), random.nextInt(255), 255)); - Line2D originalLine = trackedComponents.get(i); Line2D newLine = new Line2D.Double( - originalLine.getX1()*100.0, - originalLine.getY1()*100.0, - originalLine.getX2()*100.0, - originalLine.getY2()*100.0 + l.getX1()*100.0, + l.getY1()*100.0, + l.getX2()*100.0, + l.getY2()*100.0 ); - g2d.draw(newLine); } } @@ -2167,7 +2251,7 @@ public class AreaViewer extends VisPlugin { for (int i=0; i < currentRadioMedium.getRegisteredRadioCount(); i++) { Radio testRadio = currentRadioMedium.getRegisteredRadio(i); - Position testPosition = currentRadioMedium.getRadioPosition(testRadio); + Position testPosition = testRadio.getPosition(); if (realClickedX > testPosition.getXCoordinate() - realIconHalfWidth && realClickedX < testPosition.getXCoordinate() + realIconHalfWidth && diff --git a/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java b/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java index 70032119c..0babcf6e2 100644 --- a/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java +++ b/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java @@ -33,6 +33,7 @@ package se.sics.mrm; import java.awt.geom.*; import java.util.*; + import javax.swing.tree.DefaultMutableTreeNode; import org.apache.log4j.Logger; import org.jdom.Element; @@ -65,9 +66,13 @@ public class ChannelModel { private ObstacleWorld myObstacleWorld = new ObstacleWorld(); + /* Log mode: visualize signal components */ + private boolean logMode = false; + private StringBuilder logInfo = null; + private ArrayList loggedRays = null; + + // Ray tracing components temporary vector - private boolean inLoggingMode = false; - private Vector savedRays = null; private Vector> calculatedVisibleSides = new Vector>(); private Vector calculatedVisibleSidesSources = new Vector(); private Vector calculatedVisibleSidesLines = new Vector(); @@ -1322,11 +1327,14 @@ public class ChannelModel { * the random variable mean, and the second is the variance. */ public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY) { - return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH); + return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, null); } - + public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY, Double txPower) { + return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, txPower); + } + // TODO Fix better data type support - private double[] getTransmissionData(double sourceX, double sourceY, double destX, double destY, TransmissionData dataType) { + private double[] getTransmissionData(double sourceX, double sourceY, double destX, double destY, TransmissionData dataType, Double txPower) { Point2D source = new Point2D.Double(sourceX, sourceY); Point2D dest = new Point2D.Double(destX, destY); double accumulatedVariance = 0; @@ -1352,14 +1360,14 @@ public class ChannelModel { // Calculate all paths from source to destination, using above calculated tree Vector allPaths = getConnectingPaths(source, dest, visibleLinesTree); - if (inLoggingMode) { - logger.info("Saved rays:"); + if (logMode) { + logInfo.append("Signal components:\n"); Enumeration pathsEnum = allPaths.elements(); while (pathsEnum.hasMoreElements()) { RayPath currentPath = pathsEnum.nextElement(); - logger.info("* " + currentPath); + logInfo.append("* " + currentPath + "\n"); for (int i=0; i < currentPath.getSubPathCount(); i++) { - savedRays.add(currentPath.getSubPath(i)); + loggedRays.add(currentPath.getSubPath(i)); } } } @@ -1481,12 +1489,13 @@ public class ChannelModel { // Using Rician fading approach, TODO Only one best signal considered - combine these? (need two limits) totalPathGain += Math.pow(10, pathGain[i]/10.0)*Math.cos(2*Math.PI * pathModdedLengths[i]/wavelength); - if (inLoggingMode) { - logger.info("Adding ray path with gain " + pathGain[i] + " and phase " + (2*Math.PI * pathModdedLengths[i]/wavelength)); + if (logMode) { + logInfo.append("Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n"); } - } else if (inLoggingMode) { + } else if (logMode) { + /* TODO Log mode affects result? */ pathModdedLengths[i] = (pathLengths[i] - pathLengths[bestSignalNr]) % wavelength; - logger.info("Not adding ray path with gain " + pathGain[i] + " and phase " + (2*Math.PI * pathModdedLengths[i]/wavelength)); + logInfo.append("(IGNORED) Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n"); } } @@ -1499,17 +1508,22 @@ public class ChannelModel { // Convert back to dB totalPathGain = 10*Math.log10(Math.abs(totalPathGain)); - if (inLoggingMode) { - logger.info("Total path gain:\t" + totalPathGain); - logger.info("Delay spread:\t" + delaySpread); - logger.info("RMS Delay spread:\t" + delaySpreadRMS); + if (logMode) { + logInfo.append("\nTotal path gain: " + String.format("%2.3f", totalPathGain) + " dB\n"); + logInfo.append("Delay spread: " + String.format("%2.3f", delaySpread) + "\n"); + logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n"); } // - Calculate received power - // Using formula (dB) // Received power = Output power + System gain + Transmitter gain + Path Loss + Receiver gain // TODO Update formulas - double outputPower = getParameterDoubleValue("tx_power"); + double outputPower; + if (txPower == null) { + outputPower = getParameterDoubleValue("tx_power"); + } else { + outputPower = txPower; + } double systemGain = getParameterDoubleValue("system_gain_mean"); if (getParameterBooleanValue("apply_random")) { Random random = new Random(); /* TODO Use main random generator? */ @@ -1520,8 +1534,8 @@ public class ChannelModel { double transmitterGain = getParameterDoubleValue("tx_antenna_gain"); // TODO Should depend on angle double receivedPower = outputPower + systemGain + transmitterGain + totalPathGain; - if (inLoggingMode) { - logger.info("Resulting received signal strength:\t" + receivedPower + " (" + accumulatedVariance + ")"); + if (logMode) { + logInfo.append("\nReceived signal strength: " + String.format("%2.3f", receivedPower) + " dB (variance " + accumulatedVariance + ")\n"); } if (dataType == TransmissionData.DELAY_SPREAD || dataType == TransmissionData.DELAY_SPREAD_RMS) { @@ -1531,6 +1545,11 @@ public class ChannelModel { return new double[] {receivedPower, accumulatedVariance}; } + public class TrackedSignalComponents { + ArrayList components; + String log; + } + /** * Returns all rays from given source to given destination if a transmission * were to be made. The resulting rays depend on the current settings and may @@ -1540,20 +1559,26 @@ public class ChannelModel { * @param sourceY Source position Y * @param destX Destination position X * @param destY Destination position Y - * @return All resulting rays of a simulated transmission from source to destination + * @return Signal components and printable description */ - public Vector getRaysOfTransmission(double sourceX, double sourceY, double destX, double destY) { + public TrackedSignalComponents getRaysOfTransmission(double sourceX, double sourceY, double destX, double destY) { + TrackedSignalComponents tsc = new TrackedSignalComponents(); - // Reset current rays vector - inLoggingMode = true; - savedRays = new Vector(); + logInfo = new StringBuilder(); + loggedRays = new ArrayList(); - // Calculate rays, ignore power + /* TODO Include background noise? */ + logMode = true; getProbability(sourceX, sourceY, destX, destY, -Double.MAX_VALUE); + logMode = false; - inLoggingMode = false; - - return savedRays; + tsc.log = logInfo.toString(); + tsc.components = loggedRays; + + logInfo = null; + loggedRays = null; + + return tsc; } /** @@ -1562,19 +1587,19 @@ public class ChannelModel { * variable. This method uses current parameters such as transmitted power, * obstacles, overall system loss etc. * - * @param sourceX - * Source position X - * @param sourceY - * Source position Y - * @param destX - * Destination position X - * @param destY - * Destination position Y - * @return Received SNR (dB) random variable. The first value is the random - * variable mean, and the second is the variance. The third value is the received signal strength which may be used in comparison with interference etc. + * @param sourceX Source position X + * @param sourceY Source position Y + * @param destX Destination position X + * @param destY Destination position Y + * @return Received SNR (dB) random variable: + * The first value in the array is the random variable mean. + * The second is the variance. + * The third value is the received signal strength which may be used in comparison with interference etc. */ public double[] getSINR(double sourceX, double sourceY, double destX, double destY, double interference) { - + /* TODO Cache values: called repeatedly with noise sources. */ + + // Calculate received signal strength double[] signalStrength = getReceivedSignalStrength(sourceX, sourceY, destX, destY); @@ -1601,28 +1626,27 @@ public class ChannelModel { snrData[0] -= noiseMean; snrData[1] += noiseVariance; - if (inLoggingMode) { - logger.info("SNR at receiver:\t" + snrData[0] + " (" + snrData[1] + ")"); + if (logMode) { + logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " dB (variance " + snrData[1] + ")\n"); } return snrData; } /** - * Calculates and returns probability that a receiver at given destination receives a packet from a transmitter at given source. + * Calculates probability that a receiver at given destination receives + * a packet from a transmitter at given source. * This method uses current parameters such as transmitted power, - * obstacles, overall system loss, packet size etc. TODO Packet size?! TODO Interfering signal strength + * obstacles, overall system loss, packet size etc. + * + * TODO Packet size + * TODO External interference/Background noise * - * @param sourceX - * Source position X - * @param sourceY - * Source position Y - * @param destX - * Destination position X - * @param destY - * Destination position Y - * @param interference - * Current interference at destination (dBm) + * @param sourceX Source position X + * @param sourceY Source position Y + * @param destX Destination position X + * @param destY Destination position Y + * @param interference Current interference at destination (dBm) * @return [Probability of reception, signal strength at destination] */ public double[] getProbability(double sourceX, double sourceY, double destX, double destY, double interference) { @@ -1634,9 +1658,10 @@ public class ChannelModel { double rxSensitivity = getParameterDoubleValue("rx_sensitivity"); // Check signal strength against receiver sensitivity and interference - if (rxSensitivity > signalStrength - snrMean && threshold < rxSensitivity + snrMean - signalStrength) { - if (inLoggingMode) { - logger.info("Signal to low for receiver sensitivity, increasing threshold"); + if (rxSensitivity > signalStrength - snrMean && + threshold < rxSensitivity + snrMean - signalStrength) { + if (logMode) { + logInfo.append("Weak signal: increasing threshold\n"); } // Keeping snr variance but increasing theshold to sensitivity @@ -1657,11 +1682,10 @@ public class ChannelModel { // current threshold. // (Using error algorithm method, much faster than taylor approximation!) - double probReception = 1 - GaussianWrapper.cdfErrorAlgo( - threshold, snrMean, snrStdDev); + double probReception = 1 - GaussianWrapper.cdfErrorAlgo(threshold, snrMean, snrStdDev); - if (inLoggingMode) { - logger.info("Probability of reception: " + probReception); + if (logMode) { + logInfo.append("Reception probability: " + String.format("%1.1f%%", 100*probReception) + "\n"); } // Returns probabilities @@ -1684,7 +1708,7 @@ public class ChannelModel { * @return RMS delay spread */ public double getRMSDelaySpread(double sourceX, double sourceY, double destX, double destY) { - return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.DELAY_SPREAD)[1]; + return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.DELAY_SPREAD, null)[1]; } /** diff --git a/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java b/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java index e44264579..ba9e45d0a 100644 --- a/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java +++ b/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java @@ -43,13 +43,14 @@ import org.jdom.Element; import se.sics.cooja.ClassDescription; import se.sics.cooja.RadioConnection; import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.NoiseSourceRadio; +import se.sics.cooja.interfaces.NoiseSourceRadio.NoiseLevelListener; import se.sics.cooja.interfaces.Position; import se.sics.cooja.interfaces.Radio; import se.sics.cooja.radiomediums.AbstractRadioMedium; /** - * This is the main class of the COOJA Multi-path Ray-tracing Medium (MRM) - * package. + * Multi-path Ray-tracing radio medium (MRM). * * MRM is an alternative to the simpler radio mediums available in * COOJA. It is packet based and uses a 2D ray-tracing approach to approximate @@ -57,22 +58,27 @@ import se.sics.cooja.radiomediums.AbstractRadioMedium; * ray-tracing only supports reflections and refractions through homogeneous * obstacles. * - * MRM registers two plugins: a plugin for visualizing the radio - * environments, and a plugin for configuring the radio medium parameters. + * MRM provides two plugins: one for visualizing the radio environment, + * and one for configuring the radio medium parameters. * * Future work includes adding support for diffraction and scattering. * + * MRM supports noise source radios. + * + * @see NoiseSourceRadio * @author Fredrik Osterlind */ @ClassDescription("Multi-path Ray-tracer Medium (MRM)") public class MRM extends AbstractRadioMedium { private static Logger logger = Logger.getLogger(MRM.class); - private ChannelModel currentChannelModel = null; - - private Random random = null; + public final static boolean WITH_NOISE = true; /* NoiseSourceRadio:s */ + public final static boolean WITH_CAPTURE_EFFECT = true; private Simulation sim; + private Random random = null; + private ChannelModel currentChannelModel = null; + /** * Notifies observers when this radio medium has changed settings. */ @@ -83,11 +89,9 @@ public class MRM extends AbstractRadioMedium { */ public MRM(Simulation simulation) { super(simulation); - sim = simulation; - - random = simulation.getRandomGenerator(); - // Create the channel model + sim = simulation; + random = simulation.getRandomGenerator(); currentChannelModel = new ChannelModel(); /* Register plugins */ @@ -95,6 +99,26 @@ public class MRM extends AbstractRadioMedium { sim.getGUI().registerPlugin(FormulaViewer.class); } + private NoiseLevelListener noiseListener = new NoiseLevelListener() { + public void noiseLevelChanged(NoiseSourceRadio radio, int signal) { + updateSignalStrengths(); + }; + }; + public void registerRadioInterface(Radio radio, Simulation sim) { + super.registerRadioInterface(radio, sim); + + if (radio instanceof NoiseSourceRadio) { + ((NoiseSourceRadio)radio).addNoiseLevelListener(noiseListener); + } + } + public void unregisterRadioInterface(Radio radio, Simulation sim) { + super.unregisterRadioInterface(radio, sim); + + if (radio instanceof NoiseSourceRadio) { + ((NoiseSourceRadio)radio).removeNoiseLevelListener(noiseListener); + } + } + public void removed() { super.removed(); @@ -103,90 +127,82 @@ public class MRM extends AbstractRadioMedium { sim.getGUI().unregisterPlugin(FormulaViewer.class); } - public MRMRadioConnection createConnections(Radio sendingRadio) { - Position sendingPosition = sendingRadio.getPosition(); - MRMRadioConnection newConnection = new MRMRadioConnection(sendingRadio); + public MRMRadioConnection createConnections(Radio sender) { + MRMRadioConnection newConnection = new MRMRadioConnection(sender); + Position senderPos = sender.getPosition(); - // Loop through all radios - for (Radio listeningRadio: getRegisteredRadios()) { - // Ignore sending radio and radios on different channels - if (sendingRadio == listeningRadio) { - continue; - } - if (sendingRadio.getChannel() >= 0 && - listeningRadio.getChannel() >= 0 && - sendingRadio.getChannel() != listeningRadio.getChannel()) { + /* TODO Cache potential destination in DGRM */ + /* Loop through all potential destinations */ + for (Radio recv: getRegisteredRadios()) { + if (sender == recv) { continue; } - /* TODO Use DGRM to cache link information. - * (No need to loop over all receivers) */ - - double listeningPositionX = listeningRadio.getPosition().getXCoordinate(); - double listeningPositionY = listeningRadio.getPosition().getYCoordinate(); + /* Fail if radios are on different (but configured) channels */ + if (sender.getChannel() >= 0 && + recv.getChannel() >= 0 && + sender.getChannel() != recv.getChannel()) { + continue; + } + Position recvPos = recv.getPosition(); - // Calculate probability of reception of listening radio + /* Calculate receive probability */ double[] probData = currentChannelModel.getProbability( - sendingPosition.getXCoordinate(), - sendingPosition.getYCoordinate(), - listeningPositionX, - listeningPositionY, - -Double.MAX_VALUE + senderPos.getXCoordinate(), + senderPos.getYCoordinate(), + recvPos.getXCoordinate(), + recvPos.getYCoordinate(), + -Double.MAX_VALUE /* TODO Include interference */ ); - //logger.info("Probability of reception is " + probData[0]); - //logger.info("Signal strength at destination is " + probData[1]); - if (random.nextFloat() < probData[0]) { - // Check if this radio is able to receive transmission - if (listeningRadio.isInterfered()) { - // Keep interfering radio - newConnection.addInterfered(listeningRadio, probData[1]); + double recvProb = probData[0]; + double recvSignalStrength = probData[1]; + if (recvProb == 1.0 || random.nextDouble() < recvProb) { + /* Yes, the receiver *may* receive this packet (it's strong enough) */ + if (!recv.isReceiverOn()) { + newConnection.addInterfered(recv); + recv.interfereAnyReception(); + } else if (recv.isInterfered()) { + /* Was interfered: keep interfering */ + newConnection.addInterfered(recv, recvSignalStrength); + } else if (recv.isTransmitting()) { + newConnection.addInterfered(recv, recvSignalStrength); + } else if (recv.isReceiving()) { + /* Was already receiving: start interfering. + * Assuming no continuous preambles checking */ + + double currSignal = recv.getCurrentSignalStrength(); + /* Capture effect: recv-radio is already receiving. + * Are we strong enough to interfere? */ + if (WITH_CAPTURE_EFFECT && + recvSignalStrength < currSignal - 3 /* config */) { + /* No, we are too weak */ + } else { + newConnection.addInterfered(recv, recvSignalStrength); + recv.interfereAnyReception(); - } else if (listeningRadio.isReceiving()) { - newConnection.addInterfered(listeningRadio, probData[1]); - - // Start interfering radio - listeningRadio.interfereAnyReception(); - - // Update connection that is transmitting to this radio - MRMRadioConnection existingConn = null; - for (RadioConnection conn : getActiveConnections()) { - for (Radio dstRadio : ((MRMRadioConnection) conn).getDestinations()) { - if (dstRadio == listeningRadio) { - existingConn = (MRMRadioConnection) conn; - break; + /* Interfere receiver in all other active radio connections */ + for (RadioConnection conn : getActiveConnections()) { + if (conn.isDestination(recv)) { + conn.addInterfered(recv); } } - } - if (existingConn != null) { - /* Flag radio as interfered */ - existingConn.addInterfered(listeningRadio); - listeningRadio.interfereAnyReception(); - } + } + } else { - // Radio OK to receive - //logger.info("OK, creating connection and starting to transmit"); - newConnection.addDestination(listeningRadio, probData[1]); + /* Success: radio starts receiving */ + newConnection.addDestination(recv, recvSignalStrength); } - } else if (probData[1] > currentChannelModel.getParameterDoubleValue("bg_noise_mean")) { - // Interfere radio - newConnection.addInterfered(listeningRadio, probData[1]); - listeningRadio.interfereAnyReception(); - - // TODO Radios always get interfered right now, should recalculate probability -// if (maxInterferenceSignalStrength + SOME_RELEVANT_LIMIT > transmissionSignalStrength) { -// // Recalculating probability of delivery -// double[] probData = currentChannelModel.getProbability( -// mySource.source.position.getXCoordinate(), -// mySource.source.position.getYCoordinate(), -// myDestination.position.getXCoordinate(), -// myDestination.position.getYCoordinate(), -// maxInterferenceSignalStrength); -// -// if (new Random().nextFloat() >= probData[0]) { -// return true; -// } + } else if (recvSignalStrength > currentChannelModel.getParameterDoubleValue("bg_noise_mean")) { + /* The incoming signal is strong, but strong enough to interfere? */ + if (!WITH_CAPTURE_EFFECT) { + newConnection.addInterfered(recv, recvSignalStrength); + recv.interfereAnyReception(); + } else { + /* TODO Implement new type: newConnection.addNoise()? + * Currently, this connection will never disturb this radio... */ + } } } @@ -195,57 +211,92 @@ public class MRM extends AbstractRadioMedium { } public void updateSignalStrengths() { - // // Save old signal strengths - // double[] oldSignalStrengths = new double[registeredRadios.size()]; - // for (int i = 0; i < registeredRadios.size(); i++) { - // oldSignalStrengths[i] = registeredRadios.get(i) - // .getCurrentSignalStrength(); - // } - // Reset signal strength on all radios + /* Reset: Background noise */ + double background = + currentChannelModel.getParameterDoubleValue(("bg_noise_mean")); for (Radio radio : getRegisteredRadios()) { - radio.setCurrentSignalStrength(currentChannelModel.getParameterDoubleValue(("bg_noise_mean"))); + radio.setCurrentSignalStrength(background); } - // Set signal strength on all OK transmissions - for (RadioConnection conn : getActiveConnections()) { -// ((MRMRadioConnection) conn).getSource().setCurrentSignalStrength(12345); // TODO Set signal strength on source? + /* Active radio connections */ + RadioConnection[] conns = getActiveConnections(); + for (RadioConnection conn : conns) { for (Radio dstRadio : ((MRMRadioConnection) conn).getDestinations()) { double signalStrength = ((MRMRadioConnection) conn).getDestinationSignalStrength(dstRadio); - if (signalStrength > dstRadio.getCurrentSignalStrength()) { + if (dstRadio.getCurrentSignalStrength() < signalStrength) { dstRadio.setCurrentSignalStrength(signalStrength); } } } - // Set signal strength on all interferences - for (RadioConnection conn : getActiveConnections()) { - for (Radio interferedRadio : ((MRMRadioConnection) conn).getInterfered()) { - double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(interferedRadio); - if (signalStrength > interferedRadio.getCurrentSignalStrength()) { - interferedRadio.setCurrentSignalStrength(signalStrength); + /* Interfering/colliding radio connections */ + for (RadioConnection conn : conns) { + for (Radio intfRadio : ((MRMRadioConnection) conn).getInterfered()) { + double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio); + if (intfRadio.getCurrentSignalStrength() < signalStrength) { + intfRadio.setCurrentSignalStrength(signalStrength); } - if (!interferedRadio.isInterfered()) { - // Set to interfered again - interferedRadio.interfereAnyReception(); + if (!intfRadio.isInterfered()) { + /*logger.warn("Radio was not interfered: " + intfRadio);*/ + intfRadio.interfereAnyReception(); } } } - // // Fetch new signal strengths - // double[] newSignalStrengths = new double[registeredRadios.size()]; - // for (int i = 0; i < registeredRadios.size(); i++) { - // newSignalStrengths[i] = registeredRadios.get(i) - // .getCurrentSignalStrength(); - // } - // - // // Compare new and old signal strengths - // for (int i = 0; i < registeredRadios.size(); i++) { - // if (oldSignalStrengths[i] != newSignalStrengths[i]) - // logger.warn("Signal strengths changed on radio[" + i + "]: " - // + oldSignalStrengths[i] + " -> " + newSignalStrengths[i]); - // } + /* Check for noise sources */ + if (!WITH_NOISE) return; + for (Radio noiseRadio: getRegisteredRadios()) { + if (!(noiseRadio instanceof NoiseSourceRadio)) { + continue; + } + NoiseSourceRadio radio = (NoiseSourceRadio) noiseRadio; + int signalStrength = radio.getNoiseLevel(); + if (signalStrength == Integer.MIN_VALUE) { + continue; + } + + /* Calculate how noise source affects surrounding radios */ + for (Radio affectedRadio : getRegisteredRadios()) { + if (noiseRadio == affectedRadio) { + continue; + } + + /* Update noise levels */ + double[] signalMeanVar = currentChannelModel.getReceivedSignalStrength( + noiseRadio.getPosition().getXCoordinate(), + noiseRadio.getPosition().getYCoordinate(), + affectedRadio.getPosition().getXCoordinate(), + affectedRadio.getPosition().getYCoordinate(), + (double) signalStrength); /* TODO Convert to dBm */ + double signal = signalMeanVar[0]; + if (signal < background) { + continue; + } + + /* TODO Additive signals strengths? */ + /* TODO XXX Consider radio channels */ + /* TODO XXX Potentially interfere even when signal is weaker (~3dB)... + * (we may alternatively just use the getSINR method...) */ + if (affectedRadio.getCurrentSignalStrength() < signal) { + affectedRadio.setCurrentSignalStrength(signal); + + /* TODO Interfere with radio connections? */ + if (affectedRadio.isReceiving() && !affectedRadio.isInterfered()) { + for (RadioConnection conn : conns) { + if (conn.isDestination(affectedRadio)) { + /* Intefere with current reception, mark radio as interfered */ + conn.addInterfered(affectedRadio); + if (!affectedRadio.isInterfered()) { + affectedRadio.interfereAnyReception(); + } + } + } + } + } + } + } } public Collection getConfigXML() { @@ -279,20 +330,11 @@ public class MRM extends AbstractRadioMedium { settingsObservable.deleteObserver(obs); } - /** - * Returns position of given radio. - * - * @param radio Registered radio - * @return Position of given radio - */ - public Position getRadioPosition(Radio radio) { - return radio.getPosition(); - } - /** * @return Number of registered radios. */ public int getRegisteredRadioCount() { + /* TODO Expensive operation */ return getRegisteredRadios().length; } @@ -341,10 +383,16 @@ public class MRM extends AbstractRadioMedium { } public double getDestinationSignalStrength(Radio radio) { + if (signalStrengths.get(radio) == null) { + return Double.MIN_VALUE; + } return signalStrengths.get(radio); } public double getInterferenceSignalStrength(Radio radio) { + if (signalStrengths.get(radio) == null) { + return Double.MIN_VALUE; + } return signalStrengths.get(radio); } } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyButton.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyButton.java index 8e3f13cca..0bd8ca82c 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyButton.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyButton.java @@ -100,7 +100,7 @@ public class SkyButton extends Button { } public boolean isPressed() { - logger.warn("Not implemented"); + /* Not implemented */ return false; } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyByteRadio.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyByteRadio.java old mode 100755 new mode 100644 index 26043cf48..d73a75270 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyByteRadio.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyByteRadio.java @@ -31,17 +31,7 @@ package se.sics.cooja.mspmote.interfaces; -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collection; -import java.util.Observable; -import java.util.Observer; - -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; import org.apache.log4j.Logger; import org.jdom.Element; @@ -385,84 +375,6 @@ public class SkyByteRadio extends Radio implements CustomDataRadio { rssiLastCounter = 8; } - public JPanel getInterfaceVisualizer() { - // Location - JPanel wrapperPanel = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(5, 2)); - - final JLabel statusLabel = new JLabel(""); - final JLabel lastEventLabel = new JLabel(""); - final JLabel channelLabel = new JLabel(""); - final JLabel powerLabel = new JLabel(""); - final JLabel ssLabel = new JLabel(""); - final JButton updateButton = new JButton("Update"); - - panel.add(new JLabel("STATE:")); - panel.add(statusLabel); - - panel.add(new JLabel("LAST EVENT:")); - panel.add(lastEventLabel); - - panel.add(new JLabel("CHANNEL:")); - panel.add(channelLabel); - - panel.add(new JLabel("OUTPUT POWER:")); - panel.add(powerLabel); - - panel.add(new JLabel("SIGNAL STRENGTH:")); - JPanel smallPanel = new JPanel(new GridLayout(1, 2)); - smallPanel.add(ssLabel); - smallPanel.add(updateButton); - panel.add(smallPanel); - - updateButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - channelLabel.setText(getChannel() + " (freq=" + getFrequency() + " MHz)"); - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - Observer observer; - this.addObserver(observer = new Observer() { - public void update(Observable obs, Object obj) { - if (isTransmitting()) { - statusLabel.setText("transmitting"); - } else if (isReceiving()) { - statusLabel.setText("receiving"); - } else if (isReceiverOn()) { - statusLabel.setText("listening for traffic"); - } else { - statusLabel.setText("HW off"); - } - - lastEventLabel.setText(lastEvent + " @ time=" + lastEventTime); - - channelLabel.setText(getChannel() + " (freq=" + getFrequency() + " MHz)"); - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - observer.update(null, null); - - wrapperPanel.add(BorderLayout.NORTH, panel); - - // Saving observer reference for releaseInterfaceVisualizer - wrapperPanel.putClientProperty("intf_obs", observer); - return wrapperPanel; - } - - public void releaseInterfaceVisualizer(JPanel panel) { - Observer observer = (Observer) panel.getClientProperty("intf_obs"); - if (observer == null) { - logger.fatal("Error when releasing panel, observer is null"); - return; - } - - this.deleteObserver(observer); - } - public Mote getMote() { return mote; } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java index 6d71a9ae2..03d7cbe1e 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java @@ -355,86 +355,6 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio } }; - public JPanel getInterfaceVisualizer() { - // Location - JPanel wrapperPanel = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(5, 2)); - - final JLabel statusLabel = new JLabel(""); - final JLabel lastEventLabel = new JLabel(""); - final JLabel channelLabel = new JLabel("ALL CHANNELS (-1)"); - final JLabel powerLabel = new JLabel(""); - final JLabel ssLabel = new JLabel(""); - final JButton updateButton = new JButton("Update"); - - panel.add(new JLabel("STATE:")); - panel.add(statusLabel); - - panel.add(new JLabel("LAST EVENT:")); - panel.add(lastEventLabel); - - panel.add(new JLabel("CHANNEL:")); - panel.add(channelLabel); - - panel.add(new JLabel("OUTPUT POWER:")); - panel.add(powerLabel); - - panel.add(new JLabel("SIGNAL STRENGTH:")); - JPanel smallPanel = new JPanel(new GridLayout(1, 2)); - smallPanel.add(ssLabel); - smallPanel.add(updateButton); - panel.add(smallPanel); - - updateButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" - + getCurrentOutputPowerIndicator() + "/" - + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - Observer observer; - this.addObserver(observer = new Observer() { - public void update(Observable obs, Object obj) { - if (isTransmitting()) { - statusLabel.setText("transmitting"); - } else if (isReceiving()) { - statusLabel.setText("receiving"); - } else if (radioOn) { - statusLabel.setText("listening for traffic"); - } else { - statusLabel.setText("HW off"); - } - - lastEventLabel.setText(lastEvent + " @ time=" + lastEventTime); - - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" - + getCurrentOutputPowerIndicator() + "/" - + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - observer.update(null, null); - - // Saving observer reference for releaseInterfaceVisualizer - panel.putClientProperty("intf_obs", observer); - - wrapperPanel.add(BorderLayout.NORTH, panel); - return wrapperPanel; - } - - public void releaseInterfaceVisualizer(JPanel panel) { - Observer observer = (Observer) panel.getClientProperty("intf_obs"); - if (observer == null) { - logger.fatal("Error when releasing panel, observer is null"); - return; - } - - this.deleteObserver(observer); - } - public Collection getConfigXML() { return null; } diff --git a/tools/cooja/java/se/sics/cooja/Simulation.java b/tools/cooja/java/se/sics/cooja/Simulation.java index 0fbe1297f..6cad2a24b 100644 --- a/tools/cooja/java/se/sics/cooja/Simulation.java +++ b/tools/cooja/java/se/sics/cooja/Simulation.java @@ -685,6 +685,12 @@ public class Simulation extends Observable implements Runnable { setChanged(); notifyObservers(this); + + /* Execute simulation thread events now, before simulation starts */ + while (hasPollRequests) { + popSimulationInvokes().run(); + } + return true; } 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 ca756bec7..b301c2114 100644 --- a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java @@ -345,84 +345,6 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA } } - public JPanel getInterfaceVisualizer() { - // Location - JPanel wrapperPanel = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(5, 2)); - - final JLabel statusLabel = new JLabel(""); - final JLabel lastEventLabel = new JLabel(""); - final JLabel channelLabel = new JLabel(""); - final JLabel powerLabel = new JLabel(""); - final JLabel ssLabel = new JLabel(""); - final JButton updateButton = new JButton("Update"); - - panel.add(new JLabel("STATE:")); - panel.add(statusLabel); - - panel.add(new JLabel("LAST EVENT:")); - panel.add(lastEventLabel); - - panel.add(new JLabel("CHANNEL:")); - panel.add(channelLabel); - - panel.add(new JLabel("OUTPUT POWER:")); - panel.add(powerLabel); - - panel.add(new JLabel("SIGNAL STRENGTH:")); - JPanel smallPanel = new JPanel(new GridLayout(1, 2)); - smallPanel.add(ssLabel); - smallPanel.add(updateButton); - panel.add(smallPanel); - - updateButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - channelLabel.setText("" + getChannel()); - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - Observer observer; - this.addObserver(observer = new Observer() { - public void update(Observable obs, Object obj) { - if (isTransmitting()) { - statusLabel.setText("transmitting"); - } else if (isReceiving()) { - statusLabel.setText("receiving"); - } else if (radioOn) { - statusLabel.setText("listening for traffic"); - } else { - statusLabel.setText("HW off"); - } - - lastEventLabel.setText(lastEvent + " @ time=" + lastEventTime); - - channelLabel.setText("" + getChannel()); - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - observer.update(null, null); - - wrapperPanel.add(BorderLayout.NORTH, panel); - - // Saving observer reference for releaseInterfaceVisualizer - wrapperPanel.putClientProperty("intf_obs", observer); - return wrapperPanel; - } - - public void releaseInterfaceVisualizer(JPanel panel) { - Observer observer = (Observer) panel.getClientProperty("intf_obs"); - if (observer == null) { - logger.fatal("Error when releasing panel, observer is null"); - return; - } - - this.deleteObserver(observer); - } - public Collection getConfigXML() { return null; } diff --git a/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java b/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java index 48632ad3b..3fa13a9d2 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java @@ -346,7 +346,10 @@ public abstract class SerialUI extends Log implements SerialPort { } else { newMessage.append((char) data); if (newMessage.length() > MAX_LENGTH) { - logger.warn("Dropping too large log message (>" + MAX_LENGTH + " bytes)."); + /*logger.warn("Dropping too large log message (>" + MAX_LENGTH + " bytes).");*/ + lastLogMessage = "# [1024 bytes binary data]"; + this.setChanged(); + this.notifyObservers(getMote()); newMessage.setLength(0); } } diff --git a/tools/cooja/java/se/sics/cooja/emulatedmote/Radio802154.java b/tools/cooja/java/se/sics/cooja/emulatedmote/Radio802154.java index 678169ff9..8fc187310 100644 --- a/tools/cooja/java/se/sics/cooja/emulatedmote/Radio802154.java +++ b/tools/cooja/java/se/sics/cooja/emulatedmote/Radio802154.java @@ -250,84 +250,6 @@ public abstract class Radio802154 extends Radio implements CustomDataRadio { notifyObservers(); } - public JPanel getInterfaceVisualizer() { - // Location - JPanel wrapperPanel = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(5, 2)); - - final JLabel statusLabel = new JLabel(""); - final JLabel lastEventLabel = new JLabel(""); - final JLabel channelLabel = new JLabel(""); - final JLabel powerLabel = new JLabel(""); - final JLabel ssLabel = new JLabel(""); - final JButton updateButton = new JButton("Update"); - - panel.add(new JLabel("STATE:")); - panel.add(statusLabel); - - panel.add(new JLabel("LAST EVENT:")); - panel.add(lastEventLabel); - - panel.add(new JLabel("CHANNEL:")); - panel.add(channelLabel); - - panel.add(new JLabel("OUTPUT POWER:")); - panel.add(powerLabel); - - panel.add(new JLabel("SIGNAL STRENGTH:")); - JPanel smallPanel = new JPanel(new GridLayout(1, 2)); - smallPanel.add(ssLabel); - smallPanel.add(updateButton); - panel.add(smallPanel); - - updateButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - channelLabel.setText(getChannel() + " (freq=" + getFrequency() + " MHz)"); - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - Observer observer; - this.addObserver(observer = new Observer() { - public void update(Observable obs, Object obj) { - if (isTransmitting()) { - statusLabel.setText("transmitting"); - } else if (isReceiving()) { - statusLabel.setText("receiving"); - } else if (radioOn /* mode != CC2420.MODE_TXRX_OFF */) { - statusLabel.setText("listening for traffic"); - } else { - statusLabel.setText("HW off"); - } - - lastEventLabel.setText(lastEvent + " @ time=" + lastEventTime); - - channelLabel.setText(getChannel() + " (freq=" + getFrequency() + " MHz)"); - powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")"); - ssLabel.setText(getCurrentSignalStrength() + " dBm"); - } - }); - - observer.update(null, null); - - wrapperPanel.add(BorderLayout.NORTH, panel); - - // Saving observer reference for releaseInterfaceVisualizer - wrapperPanel.putClientProperty("intf_obs", observer); - return wrapperPanel; - } - - public void releaseInterfaceVisualizer(JPanel panel) { - Observer observer = (Observer) panel.getClientProperty("intf_obs"); - if (observer == null) { - logger.fatal("Error when releasing panel, observer is null"); - return; - } - - this.deleteObserver(observer); - } - public Mote getMote() { return mote; } diff --git a/tools/cooja/java/se/sics/cooja/interfaces/ApplicationRadio.java b/tools/cooja/java/se/sics/cooja/interfaces/ApplicationRadio.java index 17fa1b5cf..6a10f7195 100644 --- a/tools/cooja/java/se/sics/cooja/interfaces/ApplicationRadio.java +++ b/tools/cooja/java/se/sics/cooja/interfaces/ApplicationRadio.java @@ -34,6 +34,7 @@ package se.sics.cooja.interfaces; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; import java.util.Collection; import java.util.Observable; import java.util.Observer; @@ -61,7 +62,7 @@ import se.sics.cooja.Simulation; * * @author Fredrik Osterlind */ -public class ApplicationRadio extends Radio { +public class ApplicationRadio extends Radio implements NoiseSourceRadio { private static Logger logger = Logger.getLogger(ApplicationRadio.class); private Simulation simulation; @@ -321,7 +322,7 @@ public class ApplicationRadio extends Radio { updateButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ssLabel.setText("Signal strength (not auto-updated): " - + getCurrentSignalStrength() + " dBm"); + + String.format("%1.1f", getCurrentSignalStrength()) + " dBm"); } }); @@ -337,7 +338,7 @@ public class ApplicationRadio extends Radio { lastEventLabel.setText("Last event (time=" + lastEventTime + "): " + lastEvent); ssLabel.setText("Signal strength (not auto-updated): " - + getCurrentSignalStrength() + " dBm"); + + String.format("%1.1f", getCurrentSignalStrength()) + " dBm"); if (getChannel() == -1) { channelLabel.setText("Current channel: ALL"); } else { @@ -354,17 +355,8 @@ public class ApplicationRadio extends Radio { return panel; } - public void releaseInterfaceVisualizer(JPanel panel) { - Observer observer = (Observer) panel.getClientProperty("intf_obs"); - if (observer == null) { - logger.fatal("Error when releasing panel, observer is null"); - return; - } - - this.deleteObserver(observer); - } - public Collection getConfigXML() { + /* TODO Save channel info? */ return null; } @@ -390,4 +382,27 @@ public class ApplicationRadio extends Radio { public boolean isReceiverOn() { return radioOn; } + + /* Noise source radio support */ + public int getNoiseLevel() { + return noiseSignal; + } + public void addNoiseLevelListener(NoiseLevelListener l) { + noiseListeners.add(l); + } + public void removeNoiseLevelListener(NoiseLevelListener l) { + noiseListeners.remove(l); + } + + /* Noise source radio support (app mote API) */ + private int noiseSignal = Integer.MIN_VALUE; + private ArrayList noiseListeners = new ArrayList(); + public void setNoiseLevel(int signal) { + this.noiseSignal = signal; + for (NoiseLevelListener l: noiseListeners) { + l.noiseLevelChanged(this, signal); + } + } + + } diff --git a/tools/cooja/java/se/sics/cooja/interfaces/NoiseSourceRadio.java b/tools/cooja/java/se/sics/cooja/interfaces/NoiseSourceRadio.java new file mode 100644 index 000000000..80d8b1685 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/NoiseSourceRadio.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 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 se.sics.cooja.interfaces; + +/** + * The noise source radio is used to simulate ambient background noise or + * point-sources of external interference (e.g. Wifi basestations). + * + * Note that interference generated from these radios are different from + * transmissions; they will not appear in the radio logger but may still + * hinder or interfere with ongoing transmissions. + * + * Noise source radios require significant processing resources in comparison + * to only transmission radios. + * + * COOJA's radio mediums may or may not choose to respect noise source radios. + * + * @see MRM + * @author Fredrik Osterlind + */ +public interface NoiseSourceRadio { + public int getNoiseLevel(); + + public void addNoiseLevelListener(NoiseLevelListener l); + public void removeNoiseLevelListener(NoiseLevelListener l); + + public interface NoiseLevelListener { + public void noiseLevelChanged(NoiseSourceRadio radio, int signal); + } +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java index 34fd835ae..0800774b7 100644 --- a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java +++ b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java @@ -29,21 +29,37 @@ package se.sics.cooja.interfaces; +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import org.apache.log4j.Logger; + import se.sics.cooja.ClassDescription; import se.sics.cooja.Mote; import se.sics.cooja.MoteInterface; import se.sics.cooja.RadioPacket; +import se.sics.cooja.contikimote.interfaces.ContikiRadio; /** - * A Radio represents a mote radio transceiver. + * A mote radio transceiver. * - * @see RadioPacket + * @see ContikiRadio * @see CustomDataRadio + * @see NoiseSourceRadio * * @author Fredrik Osterlind */ @ClassDescription("Radio") public abstract class Radio extends MoteInterface { + private static Logger logger = Logger.getLogger(Radio.class); /** * Events that radios should notify observers about. @@ -191,4 +207,66 @@ public abstract class Radio extends MoteInterface { */ public abstract Mote getMote(); + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(new BorderLayout()); + Box box = Box.createVerticalBox(); + + final JLabel statusLabel = new JLabel(""); + final JLabel lastEventLabel = new JLabel(""); + final JLabel channelLabel = new JLabel(""); + final JLabel ssLabel = new JLabel(""); + final JButton updateButton = new JButton("Update SS"); + + box.add(statusLabel); + box.add(lastEventLabel); + box.add(ssLabel); + box.add(updateButton); + box.add(channelLabel); + + updateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ssLabel.setText("Signal strength (not auto-updated): " + + String.format("%1.1f", getCurrentSignalStrength()) + " dBm"); + } + }); + + final Observer observer = new Observer() { + public void update(Observable obs, Object obj) { + if (isTransmitting()) { + statusLabel.setText("Transmitting"); + } else if (isReceiving()) { + statusLabel.setText("Receiving"); + } else { + statusLabel.setText("Listening"); + } + + lastEventLabel.setText("Last event: " + getLastEvent()); + ssLabel.setText("Signal strength (not auto-updated): " + + String.format("%1.1f", getCurrentSignalStrength()) + " dBm"); + if (getChannel() == -1) { + channelLabel.setText("Current channel: ALL"); + } else { + channelLabel.setText("Current channel: " + getChannel()); + } + } + }; + this.addObserver(observer); + + observer.update(null, null); + + panel.add(BorderLayout.NORTH, box); + panel.putClientProperty("intf_obs", observer); + return panel; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + Observer observer = (Observer) panel.getClientProperty("intf_obs"); + if (observer == null) { + logger.fatal("Error when releasing panel, observer is null"); + return; + } + + this.deleteObserver(observer); + } } diff --git a/tools/csc/csc-compute-neighbor-stats b/tools/csc/csc-compute-neighbor-stats index 4ccaa1461..a62990d92 100755 --- a/tools/csc/csc-compute-neighbor-stats +++ b/tools/csc/csc-compute-neighbor-stats @@ -9,6 +9,9 @@ while() { if(/\([\d.]+)\<\//) { $range = $1; } + if(/\([\d.]+)\<\//) { + $success_ratio_rx = $1; + } if(/\([\d.]+)\) { $num++; } } -print "Range $range num $num override range $override_range\n"; if($override_range) { $range = $override_range; @@ -27,15 +29,26 @@ if($override_range) { $no_neighbors = 0; $all_neighbors = 0; $total_neighbors = 0; -# Go through all nodes, find how many are in their range. + +# Go through all nodes, find how many are in their range and compute +# the average reception probability. Make sure we only count each neighbor once. for($i = 0; $i < $num; $i++) { $neighbors = 0; for($j = 0; $j < $num; $j++) { if($i != $j) { - if(($x[$i] - $x[$j]) * ($x[$i] - $x[$j]) + - ($y[$i] - $y[$j]) * ($y[$i] - $y[$j]) <= - $range * $range) { + $distance2 = ($x[$i] - $x[$j]) * ($x[$i] - $x[$j]) + + ($y[$i] - $y[$j]) * ($y[$i] - $y[$j]); + $range2 = $range * $range; + if($distance2 <= $range2) { $neighbors++; + + $ratio = $distance2 / $range2; + if($ratio > 1) { + $reception_probability = 0; + } else { + $reception_probability = 1 - $ratio * (1 - $success_ratio_rx); + } + $reception_probability_sum += $reception_probability; } } } @@ -47,8 +60,16 @@ for($i = 0; $i < $num; $i++) { } $total_neighbors += $neighbors; } -print "Num nodes $num, average neighbors " . ($total_neighbors / $num) . + +print "$num $range " . ($total_neighbors / $num) . + " " . ($no_neighbors / $num) . + " " . ($all_neighbors / $num) . + " " . ($reception_probability_sum / $total_neighbors) . + "\n"; +print "# Range $range number of nodes $num override range $override_range\n"; +print "# Num nodes $num, average neighbors " . ($total_neighbors / $num) . ", $no_neighbors nodes (" . (100 * $no_neighbors / $num) . "%) have no neighbors, $all_neighbors (" . (100 * $all_neighbors / $num) . - "%) have all nodes as neighbors\n"; - + "%) have all other nodes as neighbors\n"; +print "# Average reception probability " . + ($reception_probability_sum / $total_neighbors) . "\n";