diff --git a/apps/rest-coap/Makefile.rest-coap b/apps/rest-coap/Makefile.rest-coap old mode 100755 new mode 100644 diff --git a/apps/rest-common/Makefile.rest-common b/apps/rest-common/Makefile.rest-common old mode 100755 new mode 100644 diff --git a/apps/rest-common/rest.c b/apps/rest-common/rest.c old mode 100755 new mode 100644 diff --git a/apps/rest-common/rest.h b/apps/rest-common/rest.h old mode 100755 new mode 100644 diff --git a/apps/rest-http/Makefile.rest-http b/apps/rest-http/Makefile.rest-http old mode 100755 new mode 100644 diff --git a/apps/rest-http/http-common.c b/apps/rest-http/http-common.c old mode 100755 new mode 100644 diff --git a/apps/rest-http/http-common.h b/apps/rest-http/http-common.h old mode 100755 new mode 100644 diff --git a/apps/rest-http/http-server.c b/apps/rest-http/http-server.c old mode 100755 new mode 100644 diff --git a/apps/rest-http/http-server.h b/apps/rest-http/http-server.h old mode 100755 new mode 100644 diff --git a/core/cfs/cfs-coffee.c b/core/cfs/cfs-coffee.c old mode 100755 new mode 100644 diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index d4963b79e..be919fadb 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -459,6 +459,8 @@ dao_input(void) uint8_t prefixlen; uint8_t flags; uint8_t subopt_type; + uint8_t pathcontrol; + uint8_t pathsequence; uip_ipaddr_t prefix; uip_ds6_route_t *rep; uint8_t buffer_length; @@ -523,7 +525,9 @@ dao_input(void) break; case RPL_DIO_SUBOPT_TRANSIT: /* path sequence and control ignored */ - lifetime = get32(buffer, i + 4); + pathcontrol = buffer[i + 3]; + pathsequence = buffer[i + 4]; + lifetime = buffer[i + 5]; /* parent address also ignored */ break; } @@ -571,7 +575,7 @@ dao_input(void) PRINTF("RPL: Could not add a route after receiving a DAO\n"); return; } else { - rep->state.lifetime = lifetime; + rep->state.lifetime = lifetime * dag->lifetime_unit; rep->state.learned_from = learned_from; } @@ -637,13 +641,13 @@ dao_output(rpl_parent_t *n, uint32_t lifetime) memcpy(buffer + pos, &prefix, (prefixlen + 7) / CHAR_BIT); pos += ((prefixlen + 7) / CHAR_BIT); - /* create a transit information subopt */ + /* create a transit information subopt (RPL-18)*/ buffer[pos++] = RPL_DIO_SUBOPT_TRANSIT; - buffer[pos++] = 6; - buffer[pos++] = 0; /* path seq - ignored */ + buffer[pos++] = 4; + buffer[pos++] = 0; /* flags - ignored */ buffer[pos++] = 0; /* path control - ignored */ - set32(buffer, pos, lifetime); - pos += 4; + buffer[pos++] = 0; /* path seq - ignored */ + buffer[pos++] = (lifetime / dag->lifetime_unit) & 0xff; if(n == NULL) { uip_create_linklocal_rplnodes_mcast(&addr); diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 5d91ba1eb..7c039712b 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -205,7 +205,8 @@ handle_dao_timer(void *ptr) fan-out as being under investigation. */ if(dag->preferred_parent != NULL) { PRINTF("RPL: handle_dao_timer - sending DAO\n"); - dao_output(dag->preferred_parent, DEFAULT_ROUTE_LIFETIME); + /* set time to maxtime */ + dao_output(dag->preferred_parent, dag->lifetime_unit * 0xffUL); } else { PRINTF("RPL: Could not find a parent to send a DAO to \n"); } diff --git a/core/net/uip-debug.h b/core/net/uip-debug.h index c8467e51f..7ee280156 100644 --- a/core/net/uip-debug.h +++ b/core/net/uip-debug.h @@ -54,14 +54,24 @@ void uip_debug_lladdr_print(const uip_lladdr_t *addr); #if (DEBUG) & DEBUG_ANNOTATE #include +#ifdef __AVR__ +#include +#define ANNOTATE(FORMAT,args...) printf_P(PSTR(FORMAT),##args) +#else #define ANNOTATE(...) printf(__VA_ARGS__) +#endif #else #define ANNOTATE(...) #endif /* (DEBUG) & DEBUG_ANNOTATE */ #if (DEBUG) & DEBUG_PRINT #include +#ifdef __AVR__ +#include +#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args) +#else #define PRINTF(...) printf(__VA_ARGS__) +#endif #define PRINT6ADDR(addr) uip_debug_ipaddr_print(addr) #define PRINTLLADDR(lladdr) uip_debug_lladdr_print(lladdr) #else diff --git a/core/net/uip-ds6.c b/core/net/uip-ds6.c old mode 100755 new mode 100644 diff --git a/core/net/uip-ds6.h b/core/net/uip-ds6.h old mode 100755 new mode 100644 diff --git a/examples/ipso-ipv6-raven/Makefile b/examples/ipso-ipv6-raven/Makefile old mode 100755 new mode 100644 diff --git a/examples/ipso-ipv6-raven/Makefile.ipso b/examples/ipso-ipv6-raven/Makefile.ipso old mode 100755 new mode 100644 diff --git a/examples/ipso-ipv6-raven/ipso.c b/examples/ipso-ipv6-raven/ipso.c old mode 100755 new mode 100644 diff --git a/examples/ipv6/rpl-udp/rpl-udp.csc b/examples/ipv6/rpl-udp/rpl-udp.csc old mode 100755 new mode 100644 diff --git a/examples/sky/test-coffee.c b/examples/sky/test-coffee.c old mode 100755 new mode 100644 diff --git a/platform/avr-raven/contiki-raven-main.c b/platform/avr-raven/contiki-raven-main.c index 2c336c44b..fe9f482e7 100644 --- a/platform/avr-raven/contiki-raven-main.c +++ b/platform/avr-raven/contiki-raven-main.c @@ -31,15 +31,13 @@ * @(#)$$ */ #define ANNOUNCE_BOOT 1 //adds about 600 bytes to program size +#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args) #define DEBUG 0 #if DEBUG -#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args) -#define PRINTSHORT(FORMAT,args...) printf_P(PSTR(FORMAT),##args) - +#define PRINTFD(FORMAT,args...) printf_P(PSTR(FORMAT),##args) #else -#define PRINTF(...) -#define PRINTSHORT(...) +#define PRINTFD(...) #endif #include @@ -95,6 +93,22 @@ #include "net/rime.h" +/* Test rtimers, also for pings, stack monitor, neighbor/route printout and time stamps */ +#define TESTRTIMER 0 +#if TESTRTIMER +//#define PINGS 64 +#define ROUTES 64 +#define STAMPS 30 +#define STACKMONITOR 128 + +uint8_t rtimerflag=1; +uint16_t rtime; +struct rtimer rt; +void rtimercycle(void) {rtimerflag=1;} +static void ipaddr_add(const uip_ipaddr_t *addr); + +#endif /* TESTRTIMER */ + /*-------------------------------------------------------------------------*/ /*----------------------Configuration of the .elf file---------------------*/ typedef struct {unsigned char B2;unsigned char B1;unsigned char B0;} __signature_t; @@ -166,13 +180,6 @@ void initialize(void) watchdog_init(); watchdog_start(); -#define CONFIG_STACK_MONITOR 1 -#if CONFIG_STACK_MONITOR -extern uint16_t __bss_end; - __bss_end = 0x4242; - *(uint16_t *)(&__bss_end+100) = 0x4242; -#endif - #ifdef RAVEN_LCD_INTERFACE /* First rs232 port for Raven 3290 port */ rs232_init(RS232_PORT_0, USART_BAUD_38400,USART_PARITY_NONE | USART_STOP_BITS_1 | USART_DATA_BITS_8); @@ -185,16 +192,31 @@ extern uint16_t __bss_end; /* Redirect stdout to second port */ rs232_redirect_stdout(RS232_PORT_1); clock_init(); + +#if STACKMONITOR + /* Simple stack pointer highwater monitor. Checks for magic numbers in the main + * loop. In conjuction with TESTRTIMER, never-used stack will be printed + * every STACKMONITOR seconds. + */ +{ +extern uint16_t __bss_end; +uint16_t p=(uint16_t)&__bss_end; + do { + *(uint16_t *)p = 0x4242; + p+=10; + } while (p //#define delay_us( us ) ( _delay_loop_2(1+(us*F_CPU)/4000000UL) ) // delay_us(50000); @@ -204,7 +226,7 @@ uint8_t i; #endif #if ANNOUNCE_BOOT - printf_P(PSTR("\n*******Booting %s*******\n"),CONTIKI_VERSION_STRING); + PRINTF("\n*******Booting %s*******\n",CONTIKI_VERSION_STRING); #endif /* rtimers needed for radio cycling */ @@ -239,7 +261,7 @@ uint8_t i; rimeaddr_set_node_addr(&addr); - PRINTF("MAC address %x:%x:%x:%x:%x:%x:%x:%x\n",addr.u8[0],addr.u8[1],addr.u8[2],addr.u8[3],addr.u8[4],addr.u8[5],addr.u8[6],addr.u8[7]); + PRINTFD("MAC address %x:%x:%x:%x:%x:%x:%x:%x\n",addr.u8[0],addr.u8[1],addr.u8[2],addr.u8[3],addr.u8[4],addr.u8[5],addr.u8[6],addr.u8[7]); /* Initialize stack protocols */ queuebuf_init(); @@ -248,27 +270,31 @@ uint8_t i; NETSTACK_NETWORK.init(); #if ANNOUNCE_BOOT - printf_P(PSTR("%s %s, channel %u"),NETSTACK_MAC.name, NETSTACK_RDC.name,rf230_get_channel()); + PRINTF("%s %s, channel %u",NETSTACK_MAC.name, NETSTACK_RDC.name,rf230_get_channel()); if (NETSTACK_RDC.channel_check_interval) {//function pointer is zero for sicslowmac unsigned short tmp; tmp=CLOCK_SECOND / (NETSTACK_RDC.channel_check_interval == 0 ? 1:\ NETSTACK_RDC.channel_check_interval()); if (tmp<65535) printf_P(PSTR(", check rate %u Hz"),tmp); } - printf_P(PSTR("\n")); + PRINTF("\n"); + +#if UIP_CONF_IPV6_RPL + PRINTF("RPL Enabled\n"); +#endif +#if UIP_CONF_ROUTER + PRINTF("Routing Enabled\n"); #endif -#if UIP_CONF_ROUTER -#if ANNOUNCE_BOOT - printf_P(PSTR("Routing Enabled\n")); -#endif -// rime_init(rime_udp_init(NULL)); +#endif /* ANNOUNCE_BOOT */ + +// rime_init(rime_udp_init(NULL)); // uip_router_register(&rimeroute); -#endif process_start(&tcpip_process, NULL); - #else +#else +/* Original RF230 combined mac/radio driver */ /* mac process must be started before tcpip process! */ process_start(&mac_process, NULL); process_start(&tcpip_process, NULL); @@ -288,13 +314,13 @@ uint8_t i; #if COFFEE_FILES int fa = cfs_open( "/index.html", CFS_READ); if (fa<0) { //Make some default web content - printf_P(PSTR("No index.html file found, creating upload.html!\n")); - printf_P(PSTR("Formatting FLASH file system for coffee...")); + PRINTF("No index.html file found, creating upload.html!\n"); + PRINTF("Formatting FLASH file system for coffee..."); cfs_coffee_format(); - printf_P(PSTR("Done!\n")); + PRINTF("Done!\n"); fa = cfs_open( "/index.html", CFS_WRITE); int r = cfs_write(fa, &"It works!", 9); - if (r<0) printf_P(PSTR("Can''t create /index.html!\n")); + if (r<0) PRINTF("Can''t create /index.html!\n"); cfs_close(fa); // fa = cfs_open("upload.html"), CFW_WRITE); //
@@ -322,53 +348,38 @@ uint8_t i; for (i=0;i>10); + PRINTF(".%s online with dynamic %u KB EEPROM file system\n",buf,size>>10); #elif COFFEE_FILES==3 - printf_P(PSTR(".%s online with static %u byte program memory file system\n"),buf,size); + PRINTF(".%s online with static %u byte program memory file system\n",buf,size); #elif COFFEE_FILES==4 - printf_P(PSTR(".%s online with dynamic %u KB program memory file system\n"),buf,size>>10); + PRINTF(".%s online with dynamic %u KB program memory file system\n",buf,size>>10); #endif /* COFFEE_FILES */ #else - printf_P(PSTR("Online\n")); + PRINTF("Online\n"); #endif /* WEBSERVER */ #endif /* ANNOUNCE_BOOT */ } -/*---------------------------------------------------------------------------*/ -void log_message(char *m1, char *m2) -{ - printf_P(PSTR("%s%s\n"), m1, m2); -} -/* Test rtimers, also useful for pings and time stamps in simulator */ -#define TESTRTIMER 0 -#if TESTRTIMER -#define PINGS 60 -#define STAMPS 30 -uint8_t rtimerflag=1; -uint16_t rtime; -struct rtimer rt; -void rtimercycle(void) {rtimerflag=1;} -#endif /* TESTRTIMER */ - #if RF230BB extern char rf230_interrupt_flag, rf230processflag; #endif + /*-------------------------------------------------------------------------*/ /*------------------------- Main Scheduler loop----------------------------*/ /*-------------------------------------------------------------------------*/ @@ -379,68 +390,130 @@ main(void) while(1) { process_run(); - -#if CONFIG_STACK_MONITOR - extern uint16_t __bss_end; - if (*(uint16_t *)(&__bss_end+100) != 0x4242) { - printf_P(PSTR("\nStack Warning, overflow within 100 bytes!\n")); - if (__bss_end != 0x4242) { - __bss_end = 0x4242; - printf_P(PSTR("\n!!!!!!!Stack Overflow!!!!!!!!\n")); - } - *(uint16_t *)(&__bss_end+100) = 0x4242; - } + watchdog_periodic(); + +#if 0 +/* Various entry points for debugging in the AVR Studio simulator. + * Set as next statement and step into the routine. + */ + NETSTACK_RADIO.send(packetbuf_hdrptr(), 42); + process_poll(&rf230_process); + packetbuf_clear(); + len = rf230_read(packetbuf_dataptr(), PACKETBUF_SIZE); + packetbuf_set_datalen(42); + NETSTACK_RDC.input(); #endif #if 0 -/* Clock.c can trigger a periodic RF PLL calibration */ -extern uint8_t rf230_calibrated; +/* Clock.c can trigger a periodic PLL calibration in the RF230BB driver. + * This can show when that happens. + */ + extern uint8_t rf230_calibrated; if (rf230_calibrated) { - printf_P(PSTR("\nRF230 calibrated!")); + PRINTF("\nRF230 calibrated!\n"); rf230_calibrated=0; } #endif -//Various entry points for debugging in AVR simulator -// NETSTACK_RADIO.send(packetbuf_hdrptr(), 42); -// process_poll(&rf230_process); -// packetbuf_clear(); -// len = rf230_read(packetbuf_dataptr(), PACKETBUF_SIZE); -// packetbuf_set_datalen(42); -// NETSTACK_RDC.input(); - watchdog_periodic(); #if TESTRTIMER - if (rtimerflag) { //8 seconds is maximum interval, my raven 6% slow +/* Timeout can be increased up to 8 seconds maximum. + * A one second cycle is convenient for triggering the various debug printouts. + * The triggers are staggered to avoid printing everything at once. + * My raven is 6% slow. + */ + if (rtimerflag) { rtimer_set(&rt, RTIMER_NOW()+ RTIMER_ARCH_SECOND*1UL, 1,(void *) rtimercycle, NULL); rtimerflag=0; + #if STAMPS - if ((rtime%STAMPS)==0) { - printf("%us ",rtime); - } +if ((rtime%STAMPS)==0) { + PRINTF("%us ",rtime); +} #endif rtime+=1; + #if PINGS - if ((rtime%PINGS)==0) { - PRINTF("**Ping\n"); - raven_ping6(); - } +if ((rtime%PINGS)==1) { + PRINTF("**Ping\n"); + raven_ping6(); +} #endif + +#if ROUTES +if ((rtime%ROUTES)==2) { + + //#if UIP_CONF_IPV6_RPL +//#include "rpl.h" +extern uip_ds6_nbr_t uip_ds6_nbr_cache[]; +extern uip_ds6_route_t uip_ds6_routing_table[]; +extern uip_ds6_netif_t uip_ds6_if; + + uint8_t i,j; + PRINTF("\nAddresses [%u max]\n",UIP_DS6_ADDR_NB); + for (i=0;i"); + PRINTF("\nRoutes [%u max]\n",UIP_DS6_ROUTE_NB); + for(i = 0,j=1; i < UIP_DS6_ROUTE_NB; i++) { + if(uip_ds6_routing_table[i].isused) { + ipaddr_add(&uip_ds6_routing_table[i].ipaddr); + PRINTF("/%u (via ", uip_ds6_routing_table[i].length); + ipaddr_add(&uip_ds6_routing_table[i].nexthop); + // if(uip_ds6_routing_table[i].state.lifetime < 600) { + PRINTF(") %lus\n", uip_ds6_routing_table[i].state.lifetime); + // } else { + // PRINTF(")\n"); + // } + j=0; + } + } + if (j) PRINTF(" "); + PRINTF("\n---------\n"); +} #endif +#if STACKMONITOR +if ((rtime%STACKMONITOR)==3) { + extern uint16_t __bss_end; + uint16_t p=(uint16_t)&__bss_end; + do { + if (*(uint16_t *)p != 0x4242) { + PRINTF("Never-used stack > %d bytes\n",p-(uint16_t)&__bss_end); + break; + } + p+=10; + } while (pu8[i] << 8) + addr->u8[i + 1]; + if(a == 0 && f >= 0) { + if(f++ == 0) PRINTF("::"); + } else { + if(f > 0) { + f = -1; + } else if(i > 0) { + PRINTF(":"); + } + PRINTF("%x",a); + } + } +} +#endif diff --git a/platform/micaz/Makefile.micaz b/platform/micaz/Makefile.micaz old mode 100755 new mode 100644 diff --git a/platform/micaz/apps/Makefile b/platform/micaz/apps/Makefile old mode 100755 new mode 100644 diff --git a/platform/micaz/apps/mts310/Makefile b/platform/micaz/apps/mts310/Makefile old mode 100755 new mode 100644 diff --git a/platform/micaz/apps/mts310/accel-test.c b/platform/micaz/apps/mts310/accel-test.c old mode 100755 new mode 100644 diff --git a/platform/micaz/apps/mts310/magnet-test.c b/platform/micaz/apps/mts310/magnet-test.c old mode 100755 new mode 100644 diff --git a/platform/micaz/apps/mts310/mic-test.c b/platform/micaz/apps/mts310/mic-test.c old mode 100755 new mode 100644 diff --git a/platform/micaz/dev/adc.c b/platform/micaz/dev/adc.c old mode 100755 new mode 100644 diff --git a/platform/micaz/dev/adc.h b/platform/micaz/dev/adc.h old mode 100755 new mode 100644 diff --git a/platform/micaz/dev/ds2401.h b/platform/micaz/dev/ds2401.h old mode 100755 new mode 100644 diff --git a/platform/micaz/dev/sensors/battery-sensor.c b/platform/micaz/dev/sensors/battery-sensor.c old mode 100755 new mode 100644 diff --git a/platform/msb430/dev/sd-arch.c b/platform/msb430/dev/sd-arch.c old mode 100755 new mode 100644 diff --git a/platform/msb430/dev/sd-arch.h b/platform/msb430/dev/sd-arch.h old mode 100755 new mode 100644 diff --git a/platform/msb430/dev/sd.c b/platform/msb430/dev/sd.c old mode 100755 new mode 100644 diff --git a/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/MicaZMote.java b/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/MicaZMote.java old mode 100755 new mode 100644 diff --git a/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/interfaces/MicaZLED.java b/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/interfaces/MicaZLED.java old mode 100755 new mode 100644 diff --git a/tools/cooja/examples/jni_test/mac_users/nmandsize b/tools/cooja/examples/jni_test/mac_users/nmandsize old mode 100644 new mode 100755 diff --git a/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java b/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java index ae363ae97..b1c47b58d 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java +++ b/tools/cooja/java/se/sics/cooja/plugins/DGRMConfigurator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Swedish Institute of Computer Science. + * Copyright (c) 2010, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,9 +32,13 @@ package se.sics.cooja.plugins; import java.awt.BorderLayout; +import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.Observable; import java.util.Observer; @@ -42,12 +46,14 @@ import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; +import javax.swing.JFileChooser; import javax.swing.JOptionPane; +import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JSpinner; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; @@ -60,8 +66,12 @@ import se.sics.cooja.Mote; import se.sics.cooja.PluginType; import se.sics.cooja.Simulation; import se.sics.cooja.VisPlugin; +import se.sics.cooja.interfaces.Radio; +import se.sics.cooja.radiomediums.AbstractRadioMedium; +import se.sics.cooja.radiomediums.DGRMDestinationRadio; import se.sics.cooja.radiomediums.DirectedGraphMedium; -import se.sics.cooja.radiomediums.DirectedGraphMedium.DGRMDestinationRadio; +import se.sics.cooja.radiomediums.DirectedGraphMedium.Edge; +import se.sics.cooja.util.StringUtils; /** * Simple user interface for configuring edges for the Directed Graph @@ -70,18 +80,19 @@ import se.sics.cooja.radiomediums.DirectedGraphMedium.DGRMDestinationRadio; * @see DirectedGraphMedium * @author Fredrik Osterlind */ -@ClassDescription("DGRM Configurator") +@ClassDescription("DGRM Links") @PluginType(PluginType.SIM_PLUGIN) public class DGRMConfigurator extends VisPlugin { - private static Logger logger = Logger.getLogger(DGRMConfigurator.class); + private static final long serialVersionUID = 4769638341635882051L; + private static Logger logger = Logger.getLogger(DGRMConfigurator.class); private final static int IDX_SRC = 0; private final static int IDX_DST = 1; private final static int IDX_RATIO = 2; - private final static int IDX_DELAY = 3; - private final static int IDX_DEL = 4; - private final static String[] columns = new String[] { - "Source", "Destination", "Success Ratio (%)", "Delay (ms)", "Delete" + private final static int IDX_SIGNAL = 3; + private final static int IDX_DELAY = 4; + private final static String[] COLUMN_NAMES = new String[] { + "Source", "Destination", "RX Ratio", "RSSI", "Delay" }; private GUI gui = null; @@ -89,12 +100,11 @@ public class DGRMConfigurator extends VisPlugin { private Observer radioMediumObserver; private JTable graphTable = null; private JComboBox combo = new JComboBox(); + private JButton removeButton; public DGRMConfigurator(Simulation sim, GUI gui) { super("DGRM Configurator", gui); - this.gui = gui; - radioMedium = (DirectedGraphMedium) sim.getRadioMedium(); /* Listen for graph updates */ @@ -106,55 +116,53 @@ public class DGRMConfigurator extends VisPlugin { /* Represent directed graph by table */ graphTable = new JTable(model) { - public TableCellEditor getCellEditor(int row, int column) { + private static final long serialVersionUID = -4680013510092815210L; + public TableCellEditor getCellEditor(int row, int column) { + combo.removeAllItems(); if (column == IDX_RATIO) { - combo.removeAllItems(); - combo.addItem(1.0); - combo.addItem(0.9); - combo.addItem(0.8); - combo.addItem(0.7); - combo.addItem(0.6); - combo.addItem(0.5); - combo.addItem(0.4); - combo.addItem(0.3); - combo.addItem(0.2); - combo.addItem(0.1); - combo.addItem(0.0); + for (double d=1.0; d >= 0.0; d -= 0.1) { + combo.addItem(d); + } + } else if (column == IDX_SIGNAL) { + for (double d=AbstractRadioMedium.SS_STRONG; d >= AbstractRadioMedium.SS_WEAK; d -= 1) { + combo.addItem((int) d); + } + } else if (column == IDX_DELAY) { + for (double d=0; d <= 5; d++) { + combo.addItem(d); + } } - if (column == IDX_DELAY) { - combo.removeAllItems(); - combo.addItem(0); - combo.addItem(1); - combo.addItem(2); - combo.addItem(3); - combo.addItem(4); - combo.addItem(5); - } - return super.getCellEditor(row, column); } - public String getToolTipText(MouseEvent e) { - java.awt.Point p = e.getPoint(); - int row = rowAtPoint(p); - int col = convertColumnIndexToModel(columnAtPoint(p)); - - /* TODO */ - return super.getToolTipText(); - } }; + graphTable.setFillsViewportHeight(true); combo.setEditable(true); + graphTable.getColumnModel().getColumn(IDX_RATIO).setCellRenderer(new DefaultTableCellRenderer() { - public void setValue(Object value) { + private static final long serialVersionUID = 4470088575039698508L; + public void setValue(Object value) { if (!(value instanceof Double)) { setText(value.toString()); return; } double v = ((Double) value).doubleValue(); - setText((Math.round(v*1000.0) / 10.0) + "%"); + setText(String.format("%1.1f%%", 100*v)); + } + }); + graphTable.getColumnModel().getColumn(IDX_SIGNAL).setCellRenderer(new DefaultTableCellRenderer() { + private static final long serialVersionUID = -7170745293267593460L; + public void setValue(Object value) { + if (!(value instanceof Long)) { + setText(value.toString()); + return; + } + double v = ((Double) value).doubleValue(); + setText(String.format("%1.1f dBm", v)); } }); graphTable.getColumnModel().getColumn(IDX_DELAY).setCellRenderer(new DefaultTableCellRenderer() { - public void setValue(Object value) { + private static final long serialVersionUID = -4669897764928372246L; + public void setValue(Object value) { if (!(value instanceof Long)) { setText(value.toString()); return; @@ -164,21 +172,50 @@ public class DGRMConfigurator extends VisPlugin { } }); graphTable.getColumnModel().getColumn(IDX_RATIO).setCellEditor(new DefaultCellEditor(combo)); + graphTable.getColumnModel().getColumn(IDX_SIGNAL).setCellEditor(new DefaultCellEditor(combo)); graphTable.getColumnModel().getColumn(IDX_DELAY).setCellEditor(new DefaultCellEditor(combo)); graphTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); graphTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - + + JPanel southPanel = new JPanel(new GridLayout(1, 3)); JButton button = new JButton("Add"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { doAddLink(); } }); - final JScrollPane scrollPane = new JScrollPane(graphTable); + southPanel.add(button); + button = new JButton("Remove"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + doRemoveSelectedLink(); + } + }); + removeButton = button; + removeButton.setEnabled(false); + southPanel.add(button); + button = new JButton("Import"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + doImportFromFile(); + } + }); + southPanel.add(button); + getContentPane().setLayout(new BorderLayout()); - add(BorderLayout.CENTER, scrollPane); - add(BorderLayout.SOUTH, button); + add(BorderLayout.CENTER, new JScrollPane(graphTable)); + add(BorderLayout.SOUTH, southPanel); + + graphTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + ListSelectionModel lsm = (ListSelectionModel)e.getSource(); + if (e.getValueIsAdjusting()) { + return; + } + removeButton.setEnabled(!lsm.isSelectionEmpty()); + } + }); model.fireTableDataChanged(); setSize(400, 300); @@ -186,29 +223,18 @@ public class DGRMConfigurator extends VisPlugin { private void doAddLink() { JComboBox source = new JComboBox(); - for (int i=0; i < gui.getSimulation().getMotesCount(); i++) { - source.addItem(gui.getSimulation().getMote(i)); - } - JComboBox dest = new JComboBox(); - for (int i=0; i < gui.getSimulation().getMotesCount(); i++) { - dest.addItem(gui.getSimulation().getMote(i)); + for (Mote m: gui.getSimulation().getMotes()) { + source.addItem(m); + dest.addItem(m); } - dest.addItem("ALL"); - - JSpinner ratio = new JSpinner(new SpinnerNumberModel(1.0, 0.0, 1.0, 0.01)); - JSpinner delay = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1)); /* User input */ Object description[] = { - columns[0], + COLUMN_NAMES[0], source, - columns[1], - dest, - columns[2], - ratio, - columns[3], - delay + COLUMN_NAMES[1], + dest }; JOptionPane optionPane = new JOptionPane(); optionPane.setMessage(description); @@ -216,34 +242,20 @@ public class DGRMConfigurator extends VisPlugin { String options[] = new String[] {"Cancel", "Add"}; optionPane.setOptions(options); optionPane.setInitialValue(options[1]); - JDialog dialog = optionPane.createDialog(gui.getTopParentContainer(), title); - dialog.setTitle("Add new link"); + JDialog dialog = optionPane.createDialog(this, title); + dialog.setTitle("Add graph edge"); dialog.setVisible(true); if (optionPane.getValue() == null || !optionPane.getValue().equals("Add")) { return; } /* Register new edge with radio medium */ - DirectedGraphMedium.Edge newEdge; - if (dest.getSelectedItem() instanceof Mote) { - newEdge = new DirectedGraphMedium.Edge( - ((Mote) source.getSelectedItem()).getInterfaces().getRadio(), - new DGRMDestinationRadio( - ((Mote) dest.getSelectedItem()).getInterfaces().getRadio(), - ((Number)ratio.getValue()).doubleValue(), - ((Number)delay.getValue()).longValue() - ) - ); - } else { - newEdge = new DirectedGraphMedium.Edge( - ((Mote) source.getSelectedItem()).getInterfaces().getRadio(), - new DGRMDestinationRadio( - null, - ((Number)ratio.getValue()).doubleValue(), - ((Number)delay.getValue()).longValue() - ) - ); - } + DirectedGraphMedium.Edge newEdge = new DirectedGraphMedium.Edge( + ((Mote) source.getSelectedItem()).getInterfaces().getRadio(), + new DGRMDestinationRadio( + ((Mote) dest.getSelectedItem()).getInterfaces().getRadio() + ) + ); radioMedium.addEdge(newEdge); model.fireTableDataChanged(); } @@ -252,98 +264,180 @@ public class DGRMConfigurator extends VisPlugin { radioMedium.removeEdge(edge); model.fireTableDataChanged(); } + private void doRemoveSelectedLink() { + int firstIndex = graphTable.getSelectedRow(); + if (firstIndex < 0) { + return; + } - final AbstractTableModel model = new AbstractTableModel() { - public String getColumnName(int column) { - if (column < 0 || column >= columns.length) { - logger.fatal("Unknown column: " + column); - return ""; + doRemoveLink(radioMedium.getEdges()[firstIndex]); + } + private void doImportFromFile() { + /* Delete existing edges */ + if (radioMedium.getEdges().length > 0) { + String[] options = new String[] { "Remove", "Cancel" }; + int n = JOptionPane.showOptionDialog( + GUI.getTopParentContainer(), + "Importing edges will remove all your existing edges.", + "Clear edge table?", JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, null, options, options[0]); + if (n != JOptionPane.YES_OPTION) { + return; + } + for (DirectedGraphMedium.Edge e: radioMedium.getEdges()) { + radioMedium.removeEdge(e); } - return columns[column]; } + /* Select file to import edges from */ + JFileChooser fc = new JFileChooser(); + File suggest = new File(GUI.getExternalToolsSetting("DGRM_IMPORT_LINKS_FILE", "cooja_dgrm_links.dat")); + fc.setSelectedFile(suggest); + int returnVal = fc.showOpenDialog(GUI.getTopParentContainer()); + if (returnVal != JFileChooser.APPROVE_OPTION) { + return; + } + File file = fc.getSelectedFile(); + if (file == null || !file.exists() || !file.canRead()) { + logger.fatal("No read access to file: " + file); + return; + } + GUI.setExternalToolsSetting("DGRM_IMPORT_LINKS_FILE", file.getPath()); + + /* Parse and import edges */ + try { + importEdges(parseDGRMLinksFile(file, gui.getSimulation())); + } catch (Exception e) { + GUI.showErrorDialog(this, "Error when importing DGRM links from " + file.getName(), e, false); + } + } + + private void importEdges(DirectedGraphMedium.Edge[] edges) { + Arrays.sort(edges, new Comparator() { + public int compare(Edge o1, Edge o2) { + return o1.source.getMote().getID() - o2.source.getMote().getID(); + } + }); + for (DirectedGraphMedium.Edge e: edges) { + radioMedium.addEdge(e); + } + logger.info("Imported " + edges.length + " DGRM edges"); + } + + static final int INDEX_SRC = 0; + static final int INDEX_DST = 1; + static final int INDEX_PRR = 2; + static final int INDEX_PRR_CI = 3; + static final int INDEX_NUM_TX = 4; + static final int INDEX_NUM_RX = 5; + static final int INDEX_RSSI_MEDIAN = 6; + static final int INDEX_RSSI_MIN = 7; + static final int INDEX_RSSI_MAX = 8; + public static DirectedGraphMedium.Edge[] parseDGRMLinksFile(File file, Simulation simulation) { + String fileContents = StringUtils.loadFromFile(file); + ArrayList edges = new ArrayList(); + + /* format: # [src] [dst] [prr] [prr_ci] [num_tx] [num_rx] [rssi] [rssi_min] [rssi_max] */ + for (String l: fileContents.split("\n")) { + l = l.trim(); + if (l.startsWith("#")) { + continue; + } + + Mote m; + String[] arr = l.split(" "); + int source = Integer.parseInt(arr[INDEX_SRC]); + m = simulation.getMoteWithID(source); + if (m == null) { + throw new RuntimeException("No simulation mote with ID " + source); + } + Radio sourceRadio = m.getInterfaces().getRadio(); + int dst = Integer.parseInt(arr[INDEX_DST]); + m = simulation.getMoteWithID(dst); + if (m == null) { + throw new RuntimeException("No simulation mote with ID " + dst); + } + DGRMDestinationRadio destRadio = new DGRMDestinationRadio(m.getInterfaces().getRadio()); + double prr = Double.parseDouble(arr[INDEX_PRR]); + /*double prrConfidence = Double.parseDouble(arr[INDEX_PRR_CI]);*/ + /*int numTX <- INDEX_NUM_TX;*/ + /*int numRX <- INDEX_NUM_RX;*/ + double rssi = Double.parseDouble(arr[INDEX_RSSI_MEDIAN]); + /*int rssiMin <- INDEX_RSSI_MIN;*/ + /*int rssiMax <- INDEX_RSSI_MAX;*/ + + DirectedGraphMedium.Edge edge = new DirectedGraphMedium.Edge(sourceRadio, destRadio); + destRadio.delay = 0; + destRadio.ratio = prr; + /*destRadio.prrConfidence = prrConfidence;*/ + destRadio.signal = rssi; + edges.add(edge); + } + return edges.toArray(new DirectedGraphMedium.Edge[0]); + } + + final AbstractTableModel model = new AbstractTableModel() { + private static final long serialVersionUID = 9101118401527171218L; + public String getColumnName(int column) { + if (column < 0 || column >= COLUMN_NAMES.length) { + return ""; + } + return COLUMN_NAMES[column]; + } public int getRowCount() { return radioMedium.getEdges().length; } - public int getColumnCount() { - return columns.length; + return COLUMN_NAMES.length; } - public Object getValueAt(int row, int column) { if (row < 0 || row >= radioMedium.getEdges().length) { - logger.fatal("Unknown row: " + row); return ""; } - if (column < 0 || column >= columns.length) { - logger.fatal("Unknown column: " + column); + if (column < 0 || column >= COLUMN_NAMES.length) { return ""; } - DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row]; if (column == IDX_SRC) { - if (edge.source == null) { - return "?"; - } return edge.source.getMote(); } if (column == IDX_DST) { - if (edge.superDest.toAll) { - return "ALL"; - } return edge.superDest.radio.getMote(); } if (column == IDX_RATIO) { return ((DGRMDestinationRadio)edge.superDest).ratio; } + if (column == IDX_SIGNAL) { + return ((DGRMDestinationRadio)edge.superDest).signal; + } if (column == IDX_DELAY) { return ((DGRMDestinationRadio)edge.superDest).delay / Simulation.MILLISECOND; } - if (column == IDX_DEL) { - return new Boolean(false); - } - - logger.debug("Column data not implemented: " + column); - return "?"; + return ""; } - public void setValueAt(Object value, int row, int column) { if (row < 0 || row >= radioMedium.getEdges().length) { - logger.fatal("Unknown row: " + row); return; } - if (column < 0 || column >= columns.length) { - logger.fatal("Unknown column: " + column); + if (column < 0 || column >= COLUMN_NAMES.length) { return; } DirectedGraphMedium.Edge edge = radioMedium.getEdges()[row]; - if (column == IDX_RATIO) { - /* Success ratio */ - try { - ((DGRMDestinationRadio)edge.superDest).ratio = - ((Number)value).doubleValue(); - radioMedium.requestEdgeAnalysis(); - } catch (ClassCastException e) { - } - return; + try { + if (column == IDX_RATIO) { + ((DGRMDestinationRadio)edge.superDest).ratio = ((Number)value).doubleValue(); + } else if (column == IDX_SIGNAL) { + ((DGRMDestinationRadio)edge.superDest).signal = ((Number)value).doubleValue(); + } else if (column == IDX_DELAY) { + ((DGRMDestinationRadio)edge.superDest).delay = + ((Number)value).longValue() * Simulation.MILLISECOND; + } else { + super.setValueAt(value, row, column); + } + radioMedium.requestEdgeAnalysis(); + } catch (ClassCastException e) { } - if (column == IDX_DELAY) { - /* Propagation delay (ms) */ - try { - ((DGRMDestinationRadio)edge.superDest).delay = - ((Number)value).longValue() * Simulation.MILLISECOND; - radioMedium.requestEdgeAnalysis(); - } catch (ClassCastException e) { - } - return; - } - if (column == IDX_DEL) { - /* Delete link */ - doRemoveLink(edge); - return; - } - super.setValueAt(value, row, column); } public boolean isCellEditable(int row, int column) { @@ -357,24 +451,22 @@ public class DGRMConfigurator extends VisPlugin { return false; } if (column == IDX_DST) { - if (!radioMedium.getEdges()[row].superDest.toAll) { - gui.signalMoteHighlight(radioMedium.getEdges()[row].superDest.radio.getMote()); - } + gui.signalMoteHighlight(radioMedium.getEdges()[row].superDest.radio.getMote()); return false; } if (column == IDX_RATIO) { return true; } - if (column == IDX_DELAY) { + if (column == IDX_SIGNAL) { return true; } - if (column == IDX_DEL) { + if (column == IDX_DELAY) { return true; } return false; } - public Class getColumnClass(int c) { + public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } }; diff --git a/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java b/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java index f0ae3595f..79ab97f76 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java +++ b/tools/cooja/java/se/sics/cooja/plugins/skins/DGRMVisualizerSkin.java @@ -48,9 +48,9 @@ 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.radiomediums.DGRMDestinationRadio; +import se.sics.cooja.radiomediums.DestinationRadio; import se.sics.cooja.radiomediums.DirectedGraphMedium; -import se.sics.cooja.radiomediums.DirectedGraphMedium.DGRMDestinationRadio; -import se.sics.cooja.radiomediums.DirectedGraphMedium.DestinationRadio; @ClassDescription("Radio environment (DGRM)") public class DGRMVisualizerSkin implements VisualizerSkin { @@ -142,16 +142,15 @@ public class DGRMVisualizerSkin implements VisualizerSkin { if (prob == 0.0d) { continue; } - msg = (double)(((int)(1000*prob))/10.0) + "%"; + msg = String.format("%1.1f%%", 100.0*prob); Position pos = r.radio.getPosition(); Point pixel = visualizer.transformPositionToPixel(pos); msgWidth = fm.stringWidth(msg); - g.setColor(Color.LIGHT_GRAY); + g.setColor(new Color(1-(float)prob, (float)prob, 0.0f)); g.drawLine(x, y, pixel.x, pixel.y); g.setColor(Color.BLACK); g.drawString(msg, pixel.x - msgWidth/2, pixel.y + 2*Visualizer.MOTE_RADIUS + 3); } - } public void paintAfterMotes(Graphics g) { diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java b/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java new file mode 100644 index 000000000..cf1dc08ba --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/radiomediums/DGRMDestinationRadio.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: DirectedGraphMedium.java,v 1.8 2010/12/02 15:25:50 fros4943 Exp $ + */ + +package se.sics.cooja.radiomediums; + +import java.util.Collection; + +import org.jdom.Element; + +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.Radio; + +public class DGRMDestinationRadio extends DestinationRadio { + public double ratio = 1.0; /* Link success ratio (per packet). */ + public double signal = AbstractRadioMedium.SS_STRONG; /* RSSI */ + public long delay = 0; /* EXPERIMENTAL: Propagation delay (us). */ + + public DGRMDestinationRadio() { + super(); + } + public DGRMDestinationRadio(Radio dest) { + super(dest); + } + + protected Object clone() { + DGRMDestinationRadio clone = new DGRMDestinationRadio(this.radio); + clone.ratio = this.ratio; + clone.delay = this.delay; + clone.signal = this.signal; + return clone; + } + + public Collection getConfigXML() { + Collection config = super.getConfigXML(); + Element element; + + element = new Element("ratio"); + element.setText("" + ratio); + config.add(element); + + element = new Element("signal"); + element.setText("" + signal); + config.add(element); + + element = new Element("delay"); + element.setText("" + delay); + config.add(element); + + return config; + } + + public boolean setConfigXML(final Collection configXML, Simulation simulation) { + if (!super.setConfigXML(configXML, simulation)) { + return false; + } + for (Element element : configXML) { + if (element.getName().equals("ratio")) { + ratio = Double.parseDouble(element.getText()); + } else if (element.getName().equals("signal")) { + signal = Double.parseDouble(element.getText()); + } else if (element.getName().equals("delay")) { + delay = Long.parseLong(element.getText()); + } + } + return true; + } +} diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/DestinationRadio.java b/tools/cooja/java/se/sics/cooja/radiomediums/DestinationRadio.java new file mode 100644 index 000000000..2613af0c6 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/radiomediums/DestinationRadio.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: DirectedGraphMedium.java,v 1.8 2010/12/02 15:25:50 fros4943 Exp $ + */ + +package se.sics.cooja.radiomediums; + +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.Radio; + +public class DestinationRadio { + private static Logger logger = Logger.getLogger(DestinationRadio.class); + + public Radio radio; /* destination radio */ + public DestinationRadio() { + } + public DestinationRadio(Radio dest) { + this.radio = dest; + } + + public String toString() { + return radio.getMote().toString(); + } + + public Collection getConfigXML() { + ArrayList config = new ArrayList(); + Element element; + + element = new Element("radio"); + element.setText("" + radio.getMote().getID()); + config.add(element); + return config; + } + + public boolean setConfigXML(Collection configXML, Simulation simulation) { + for (Element element : configXML) { + if (element.getName().equals("radio")) { + radio = simulation.getMoteWithID(Integer.parseInt(element.getText())).getInterfaces().getRadio(); + if (radio == null) { + throw new RuntimeException("No mote with ID " + element.getText()); + } + } + } + return true; + } +} diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java index adbbaac4b..b61004a48 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/DirectedGraphMedium.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Swedish Institute of Computer Science. + * Copyright (c) 2010, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,13 +36,11 @@ import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import java.util.Random; -import java.util.Vector; import org.apache.log4j.Logger; import org.jdom.Element; import se.sics.cooja.ClassDescription; -import se.sics.cooja.Mote; import se.sics.cooja.RadioConnection; import se.sics.cooja.Simulation; import se.sics.cooja.interfaces.Radio; @@ -57,496 +55,390 @@ import se.sics.cooja.plugins.skins.DGRMVisualizerSkin; * as a basis for other radio medium implementations. * * The stand-alone radio medium supports propagation delays and - * and single-value per-link transmission success ratio. + * and per-link transmission success ratio/RSSI. * - * @see UDGM + * @see AbstractRadioMedium * @author Fredrik Osterlind */ @ClassDescription("Directed Graph Radio Medium (DGRM)") public class DirectedGraphMedium extends AbstractRadioMedium { - private static Logger logger = Logger.getLogger(DirectedGraphMedium.class); - - private Simulation simulation; - private Random random; - - private ArrayList edges = new ArrayList(); - private boolean edgesDirty = true; - - /* Used for optimizing lookup time */ - private Hashtable edgesTable = new Hashtable(); - - public DirectedGraphMedium() { - /* Do not initialize radio medium: use only for hash table */ - super(null); - Visualizer.registerVisualizerSkin(DGRMVisualizerSkin.class); - } - - public DirectedGraphMedium(Simulation simulation) { - super(simulation); - this.simulation = simulation; - random = simulation.getRandomGenerator(); - - requestEdgeAnalysis(); - - /* Register plugin and visualizer skin */ - simulation.getGUI().registerPlugin(DGRMConfigurator.class); - Visualizer.registerVisualizerSkin(DGRMVisualizerSkin.class); - } - - public void removed() { - super.removed(); - - /* Unregister plugin and visualizer skin */ - simulation.getGUI().unregisterPlugin(DGRMConfigurator.class); - Visualizer.unregisterVisualizerSkin(DGRMVisualizerSkin.class); - } - - public void addEdge(Edge e) { - edges.add(e); - requestEdgeAnalysis(); - - ((AbstractRadioMedium.RadioMediumObservable) - this.getRadioMediumObservable()).setRadioMediumChangedAndNotify(); - } - - public void removeEdge(Edge edge) { - if (!edges.contains(edge)) { - logger.fatal("Cannot remove edge: " + edge); - return; - } - edges.remove(edge); - requestEdgeAnalysis(); - - ((AbstractRadioMedium.RadioMediumObservable) - this.getRadioMediumObservable()).setRadioMediumChangedAndNotify(); - } - - public void clearEdges() { - edges.clear(); - requestEdgeAnalysis(); - - ((AbstractRadioMedium.RadioMediumObservable) - this.getRadioMediumObservable()).setRadioMediumChangedAndNotify(); - } - - public Edge[] getEdges() { - return edges.toArray(new Edge[0]); - } - - /** - * Signal that the configuration changed, and needs to be re-analyzed - * before used. - */ - public void requestEdgeAnalysis() { - edgesDirty = true; - } - - public boolean needsEdgeAnalysis() { - return edgesDirty; - } - - public void registerRadioInterface(Radio radio, Simulation sim) { - super.registerRadioInterface(radio, sim); - - for (Edge edge: getEdges()) { - if (edge.delayedLoadConfig == null) { - continue; - } - - /* Try to configure edge now */ - if (edge.setConfigXML(edge.delayedLoadConfig, sim)) { - edge.delayedLoadConfig = null; - } - } - - requestEdgeAnalysis(); - } - - public void unregisterRadioInterface(Radio radio, Simulation sim) { - super.unregisterRadioInterface(radio, sim); - - if (radio == null) { - return; - } - for (Edge edge: getEdges()) { - if (edge.source == radio || edge.superDest.radio == radio) { - removeEdge(edge); - } - } - - requestEdgeAnalysis(); - } - - public void updateSignalStrengths() { - - /* Reset signal strengths */ - for (Radio radio : getRegisteredRadios()) { - radio.setCurrentSignalStrength(SS_NOTHING); - } - - /* Set signal strengths */ - RadioConnection[] conns = getActiveConnections(); - for (RadioConnection conn : conns) { - if (conn.getSource().getCurrentSignalStrength() < SS_STRONG) { - conn.getSource().setCurrentSignalStrength(SS_STRONG); - } - for (Radio dstRadio : conn.getDestinations()) { - if (dstRadio.getCurrentSignalStrength() < SS_STRONG) { - dstRadio.setCurrentSignalStrength(SS_STRONG); - } - } - } - - /* Set signal strength to weak on interfered */ - for (RadioConnection conn : conns) { - for (Radio intfRadio : conn.getInterfered()) { - if (intfRadio.getCurrentSignalStrength() < SS_STRONG) { - intfRadio.setCurrentSignalStrength(SS_STRONG); - } - - if (!intfRadio.isInterfered()) { - /*logger.warn("Radio was not interfered");*/ - intfRadio.interfereAnyReception(); - } - } - } - } - - public static class DestinationRadio { - public Radio radio; /* destination radio */ - public boolean toAll; /* to all destinations */ - - public DestinationRadio(Radio dest) { - this.radio = dest; - toAll = (radio == null); - } - - public String toString() { - return radio.getMote().toString(); - } - - protected Object clone() { - return new DestinationRadio(radio); - } - } - - public static class DGRMDestinationRadio extends DestinationRadio { - public double ratio; /* Link success ratio (per packet). */ - public long delay; /* EXPERIMENTAL: Propagation delay (us). */ - - public DGRMDestinationRadio(Radio dest, double ratio, long delay) { - super(dest); - this.ratio = ratio; - this.delay = delay; - } - - protected Object clone() { - return new DGRMDestinationRadio(radio, ratio, delay); - } - } - - /** - * Generates hash table using current edges for efficient lookup. - */ - protected void analyzeEdges() { - Hashtable> listTable = - new Hashtable>(); - - /* Fill edge hash table with all edges */ - for (Edge edge: getEdges()) { - if (edge.source == null) { - /* XXX Wait until edge configuration has been loaded */ - logger.warn("DGRM edges not loaded"); - return; - } - - ArrayList destRadios; - if (!listTable.containsKey(edge.source)) { - /* Create new source */ - destRadios = new ArrayList(); - } else { - /* Extend source radio with another destination */ - destRadios = listTable.get(edge.source); - } - - /* Explode special rule: to all radios */ - if (edge.superDest.toAll) { - for (Radio r: getRegisteredRadios()) { - if (edge.source == r) { - continue; - } - DestinationRadio d = (DestinationRadio) edge.superDest.clone(); - d.radio = r; - d.toAll = false; - destRadios.add(d); - } - } else { - destRadios.add(edge.superDest); - } - listTable.put(edge.source, destRadios); - } - - /* Convert to arrays */ - Hashtable arrTable = - new Hashtable(); - Enumeration sources = listTable.keys(); - while (sources.hasMoreElements()) { - Radio source = sources.nextElement(); - DestinationRadio[] arr = - listTable.get(source).toArray(new DestinationRadio[0]); - arrTable.put(source, arr); - } - - this.edgesTable = arrTable; - edgesDirty = false; - } - - /** - * Returns all potential destination radios, i.e. all radios "within reach". - * Does not consider radio channels, transmission success ratios etc. - * - * @param source Source radio - * @return All potential destination radios - */ - public DestinationRadio[] getPotentialDestinations(Radio source) { - if (edgesDirty) { - analyzeEdges(); - } - return edgesTable.get(source); - } - - public RadioConnection createConnections(Radio source) { - if (edgesDirty) { - analyzeEdges(); - } - if (edgesDirty) { - logger.fatal("Error when analyzing edges, aborting new radio connection"); - return new RadioConnection(source); - } - - /* Create new radio connection using edge hash table */ - RadioConnection newConn = new RadioConnection(source); - DestinationRadio[] destinations = getPotentialDestinations(source); - if (destinations == null || destinations.length == 0) { - /* No destinations */ - /*logger.info(sendingRadio + ": No dest");*/ - return newConn; - } - - /*logger.info(source + ": " + destinations.length + " potential destinations");*/ - for (DestinationRadio d: destinations) { - DGRMDestinationRadio dest = (DGRMDestinationRadio) d; - if (dest.radio == source) { - /* Fail: cannot receive our own transmission */ - /*logger.info(source + ": Fail, receiver is sender");*/ - continue; - } - - /* Fail if radios are on different (but configured) channels */ - if (source.getChannel() >= 0 && - dest.radio.getChannel() >= 0 && - source.getChannel() != dest.radio.getChannel()) { - continue; - } - - if (!dest.radio.isReceiverOn()) { - /* Fail: radio is off */ - /*logger.info(source + ": Fail, off");*/ - newConn.addInterfered(dest.radio); - continue; - } - - if (dest.ratio < 1.0 && random.nextDouble() > dest.ratio) { - /*logger.info(source + ": Fail, randomly");*/ - /* TODO Interfere now? */ - newConn.addInterfered(dest.radio); - - dest.radio.interfereAnyReception(); - RadioConnection otherConnection = null; - for (RadioConnection conn : getActiveConnections()) { - for (Radio dstRadio : conn.getDestinations()) { - if (dstRadio == dest.radio) { - otherConnection = conn; - break; - } - } - } - if (otherConnection != null) { - otherConnection.addInterfered(dest.radio); - } - continue; - } - - if (dest.radio.isReceiving()) { - /* Fail: radio is already actively receiving */ - /*logger.info(source + ": Fail, receiving");*/ - newConn.addInterfered(dest.radio); - - /* We will also interfere with the other connection */ - dest.radio.interfereAnyReception(); - RadioConnection otherConnection = null; - for (RadioConnection conn : getActiveConnections()) { - for (Radio dstRadio : conn.getDestinations()) { - if (dstRadio == dest.radio) { - otherConnection = conn; - break; - } - } - } - if (otherConnection != null) { - otherConnection.addInterfered(dest.radio); - } - continue; - } - - if (dest.radio.isInterfered()) { - /* Fail: radio is interfered in another connection */ - /*logger.info(source + ": Fail, interfered");*/ - newConn.addInterfered(dest.radio); - continue; - } - - /* Success: radio starts receiving */ - /*logger.info(source + ": OK: " + dest.radio);*/ - newConn.addDestination(dest.radio, dest.delay); - } - - return newConn; - } - - public Collection getConfigXML() { - ArrayList config = new ArrayList(); - Element element; - - for (Edge edge: getEdges()) { - element = new Element("edge"); - element.addContent(edge.getConfigXML()); - config.add(element); - } - - return config; - } - - public boolean setConfigXML(final Collection configXML, boolean visAvailable) { - random = simulation.getRandomGenerator(); - - for (Element element : configXML) { - if (element.getName().equals("edge")) { - Edge edge = new Edge(); - edge.delayedLoadConfig = element.getChildren(); - addEdge(edge); - } - } - - requestEdgeAnalysis(); - return true; - } - - public static class Edge { - public Radio source; - public DestinationRadio superDest; - - private Edge() { - /* Internal constructor: await config */ - source = null; - superDest = null; - } - - public Edge(Radio source, DestinationRadio dest) { - this.source = source; - this.superDest = dest; - } - - /* Internal methods */ - private Collection delayedLoadConfig = null; /* Used for restoring edges from config */ - private Collection getConfigXML() { - Vector config = new Vector(); - Element element; - - element = new Element("src"); - element.setText(source.getMote().toString()); - config.add(element); - - element = new Element("dest"); - if (superDest.toAll) { - element.setText("ALL"); - } else { - element.setText(superDest.radio.getMote().toString()); - } - config.add(element); - - if (superDest instanceof DGRMDestinationRadio) { - element = new Element("ratio"); - element.setText("" + ((DGRMDestinationRadio)superDest).ratio); - config.add(element); - - element = new Element("delay"); - element.setText("" + ((DGRMDestinationRadio)superDest).delay); - config.add(element); - } - - return config; - } - - private boolean setConfigXML(Collection configXML, Simulation simulation) { - Radio dest = null; - double ratio = -1; - long delay = -1; - - for (Element element : configXML) { - if (element.getName().equals("src")) { - String moteDescription = element.getText(); - - boolean foundMote = false; - for (Mote m: simulation.getMotes()) { - if (moteDescription.equals(m.toString())) { - foundMote = true; - source = m.getInterfaces().getRadio(); - break; - } - } - - if (!foundMote) { - return false; - } - } - - if (element.getName().equals("dest")) { - String moteDescription = element.getText(); - - if (moteDescription.equals("ALL")) { - dest = null; /* ALL */ - } else { - boolean foundMote = false; - for (Mote m: simulation.getMotes()) { - if (moteDescription.equals(m.toString())) { - foundMote = true; - dest = m.getInterfaces().getRadio(); - break; - } - } - if (!foundMote) { - return false; - } - } - } - - if (element.getName().equals("ratio")) { - ratio = Double.parseDouble(element.getText()); - } - - if (element.getName().equals("delay")) { - delay = Long.parseLong(element.getText()); - } - } - - if (ratio < 0 || delay < 0) { - return false; - } - - superDest = new DGRMDestinationRadio(dest, ratio, delay); - return true; - } - } - + private static Logger logger = Logger.getLogger(DirectedGraphMedium.class); + + private Simulation simulation; + private Random random; + + private ArrayList edges = new ArrayList(); + private boolean edgesDirty = true; + + /* Used for optimizing lookup time */ + private Hashtable edgesTable = new Hashtable(); + + public DirectedGraphMedium() { + /* Do not initialize radio medium: use only for hash table */ + super(null); + Visualizer.registerVisualizerSkin(DGRMVisualizerSkin.class); + } + + public DirectedGraphMedium(Simulation simulation) { + super(simulation); + this.simulation = simulation; + random = simulation.getRandomGenerator(); + + requestEdgeAnalysis(); + + /* Register plugin and visualizer skin */ + simulation.getGUI().registerPlugin(DGRMConfigurator.class); + Visualizer.registerVisualizerSkin(DGRMVisualizerSkin.class); + } + + public void removed() { + super.removed(); + + /* Unregister plugin and visualizer skin */ + simulation.getGUI().unregisterPlugin(DGRMConfigurator.class); + Visualizer.unregisterVisualizerSkin(DGRMVisualizerSkin.class); + } + + public void addEdge(Edge e) { + edges.add(e); + requestEdgeAnalysis(); + + ((AbstractRadioMedium.RadioMediumObservable) + this.getRadioMediumObservable()).setRadioMediumChangedAndNotify(); + } + + public void removeEdge(Edge edge) { + if (!edges.contains(edge)) { + logger.fatal("Cannot remove edge: " + edge); + return; + } + edges.remove(edge); + requestEdgeAnalysis(); + + ((AbstractRadioMedium.RadioMediumObservable) + this.getRadioMediumObservable()).setRadioMediumChangedAndNotify(); + } + + public void clearEdges() { + edges.clear(); + requestEdgeAnalysis(); + + ((AbstractRadioMedium.RadioMediumObservable) + this.getRadioMediumObservable()).setRadioMediumChangedAndNotify(); + } + + public Edge[] getEdges() { + return edges.toArray(new Edge[0]); + } + + /** + * Signal that the configuration changed, and needs to be re-analyzed + * before used. + */ + public void requestEdgeAnalysis() { + edgesDirty = true; + } + + public boolean needsEdgeAnalysis() { + return edgesDirty; + } + + public void unregisterRadioInterface(Radio radio, Simulation sim) { + super.unregisterRadioInterface(radio, sim); + + for (Edge edge: getEdges()) { + if (edge.source == radio || edge.superDest.radio == radio) { + removeEdge(edge); + requestEdgeAnalysis(); + } + } + } + + public void updateSignalStrengths() { + + /* Reset signal strengths */ + for (Radio radio : getRegisteredRadios()) { + radio.setCurrentSignalStrength(SS_NOTHING); + } + + /* Set signal strengths */ + RadioConnection[] conns = getActiveConnections(); + for (RadioConnection conn : conns) { + if (conn.getSource().getCurrentSignalStrength() < SS_STRONG) { + conn.getSource().setCurrentSignalStrength(SS_STRONG); + } + for (Radio dstRadio : conn.getDestinations()) { + if (dstRadio.getCurrentSignalStrength() < SS_STRONG) { + dstRadio.setCurrentSignalStrength(SS_STRONG); + } + } + } + + /* Set signal strength to weak on interfered */ + for (RadioConnection conn : conns) { + for (Radio intfRadio : conn.getInterfered()) { + if (intfRadio.getCurrentSignalStrength() < SS_STRONG) { + intfRadio.setCurrentSignalStrength(SS_STRONG); + } + + if (!intfRadio.isInterfered()) { + /*logger.warn("Radio was not interfered");*/ + intfRadio.interfereAnyReception(); + } + } + } + } + + + + /** + * Generates hash table using current edges for efficient lookup. + */ + protected void analyzeEdges() { + Hashtable> listTable = + new Hashtable>(); + + /* Fill edge hash table with all edges */ + for (Edge edge: getEdges()) { + ArrayList destRadios; + if (!listTable.containsKey(edge.source)) { + destRadios = new ArrayList(); + } else { + destRadios = listTable.get(edge.source); + } + + destRadios.add(edge.superDest); + listTable.put(edge.source, destRadios); + } + + /* Convert to arrays */ + Hashtable arrTable = new Hashtable(); + Enumeration sources = listTable.keys(); + while (sources.hasMoreElements()) { + Radio source = sources.nextElement(); + DestinationRadio[] arr = listTable.get(source).toArray(new DestinationRadio[0]); + arrTable.put(source, arr); + } + + this.edgesTable = arrTable; + edgesDirty = false; + } + + /** + * Returns all potential destination radios, i.e. all radios "within reach". + * Does not consider radio channels, transmission success ratios etc. + * + * @param source Source radio + * @return All potential destination radios + */ + public DestinationRadio[] getPotentialDestinations(Radio source) { + if (edgesDirty) { + analyzeEdges(); + } + return edgesTable.get(source); + } + + public RadioConnection createConnections(Radio source) { + if (edgesDirty) { + analyzeEdges(); + } + if (edgesDirty) { + logger.fatal("Error when analyzing edges, aborting new radio connection"); + return new RadioConnection(source); + } + + /* Create new radio connection using edge hash table */ + RadioConnection newConn = new RadioConnection(source); + DestinationRadio[] destinations = getPotentialDestinations(source); + if (destinations == null || destinations.length == 0) { + /* No destinations */ + /*logger.info(sendingRadio + ": No dest");*/ + return newConn; + } + + /*logger.info(source + ": " + destinations.length + " potential destinations");*/ + for (DestinationRadio d: destinations) { + DGRMDestinationRadio dest = (DGRMDestinationRadio) d; + if (dest.radio == source) { + /* Fail: cannot receive our own transmission */ + /*logger.info(source + ": Fail, receiver is sender");*/ + continue; + } + + /* Fail if radios are on different (but configured) channels */ + if (source.getChannel() >= 0 && + dest.radio.getChannel() >= 0 && + source.getChannel() != dest.radio.getChannel()) { + continue; + } + + if (!dest.radio.isReceiverOn()) { + /* Fail: radio is off */ + /*logger.info(source + ": Fail, off");*/ + newConn.addInterfered(dest.radio); + continue; + } + + if (dest.ratio < 1.0 && random.nextDouble() > dest.ratio) { + /*logger.info(source + ": Fail, randomly");*/ + /* TODO Interfere now? */ + newConn.addInterfered(dest.radio); + + dest.radio.interfereAnyReception(); + RadioConnection otherConnection = null; + for (RadioConnection conn : getActiveConnections()) { + for (Radio dstRadio : conn.getDestinations()) { + if (dstRadio == dest.radio) { + otherConnection = conn; + break; + } + } + } + if (otherConnection != null) { + otherConnection.addInterfered(dest.radio); + } + continue; + } + + if (dest.radio.isReceiving()) { + /* Fail: radio is already actively receiving */ + /*logger.info(source + ": Fail, receiving");*/ + newConn.addInterfered(dest.radio); + + /* We will also interfere with the other connection */ + dest.radio.interfereAnyReception(); + RadioConnection otherConnection = null; + for (RadioConnection conn : getActiveConnections()) { + for (Radio dstRadio : conn.getDestinations()) { + if (dstRadio == dest.radio) { + otherConnection = conn; + break; + } + } + } + if (otherConnection != null) { + otherConnection.addInterfered(dest.radio); + } + continue; + } + + if (dest.radio.isInterfered()) { + /* Fail: radio is interfered in another connection */ + /*logger.info(source + ": Fail, interfered");*/ + newConn.addInterfered(dest.radio); + continue; + } + + /* Success: radio starts receiving */ + /*logger.info(source + ": OK: " + dest.radio);*/ + newConn.addDestination(dest.radio, dest.delay); + } + + return newConn; + } + + public Collection getConfigXML() { + ArrayList config = new ArrayList(); + Element element; + + for (Edge edge: getEdges()) { + element = new Element("edge"); + element.addContent(edge.getConfigXML()); + config.add(element); + } + + return config; + } + + private Collection delayedConfiguration = null; + public boolean setConfigXML(Collection configXML, boolean visAvailable) { + random = simulation.getRandomGenerator(); + + /* Wait until simulation has been loaded */ + delayedConfiguration = configXML; + return true; + } + public void simulationFinishedLoading() { + if (delayedConfiguration == null) { + return; + } + + boolean warnedOldConfig = false; + for (Element element : delayedConfiguration) { + if (element.getName().equals("edge")) { + Collection edgeConfig = element.getChildren(); + Radio source = null; + DestinationRadio dest = null; + for (Element edgeElement : edgeConfig) { + if (edgeElement.getName().equals("src")) { + /* Old version, ignore edge */ + if (!warnedOldConfig) { + logger.fatal("Old simulation config detected: DGRM links will not be imported"); + warnedOldConfig = true; + } + return; + } else if (edgeElement.getName().equals("source")) { + source = simulation.getMoteWithID( + Integer.parseInt(edgeElement.getText())).getInterfaces().getRadio(); + } else if (edgeElement.getName().equals("dest")) { + String destClassName = edgeElement.getText().trim(); + if (destClassName == null || destClassName.isEmpty()) { + continue; + } + Class destClass = + simulation.getGUI().tryLoadClass(this, DestinationRadio.class, destClassName); + if (destClass == null) { + throw new RuntimeException("Could not load class: " + destClassName); + } + try { + dest = destClass.newInstance(); + dest.setConfigXML(edgeElement.getChildren(), simulation); + } catch (Exception e) { + throw (RuntimeException) + new RuntimeException("Unknown class: " + destClassName).initCause(e); + } + } + } + if (source == null || dest == null) { + if (!warnedOldConfig) { + logger.fatal("Old simulation config detected: DGRM links will not be imported"); + warnedOldConfig = true; + } + } else { + addEdge(new Edge(source, dest)); + } + } + } + requestEdgeAnalysis(); + delayedConfiguration = null; + } + + public static class Edge { + public Radio source = null; + public DestinationRadio superDest = null; + + public Edge(Radio source, DestinationRadio dest) { + this.source = source; + this.superDest = dest; + } + + private Collection getConfigXML() { + ArrayList config = new ArrayList(); + Element element; + + element = new Element("source"); + element.setText("" + source.getMote().getID()); + config.add(element); + + element = new Element("dest"); + element.setText(superDest.getClass().getName()); + Collection destConfig = superDest.getConfigXML(); + if (destConfig != null) { + element.addContent(destConfig); + config.add(element); + } + + return config; + } + } } diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java index a9b2d6ab3..24ecdc6fd 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/UDGM.java @@ -43,13 +43,12 @@ import org.jdom.Element; import se.sics.cooja.ClassDescription; import se.sics.cooja.Mote; import se.sics.cooja.RadioConnection; -import se.sics.cooja.Simulation; import se.sics.cooja.SimEventCentral.MoteCountListener; +import se.sics.cooja.Simulation; import se.sics.cooja.interfaces.Position; import se.sics.cooja.interfaces.Radio; import se.sics.cooja.plugins.Visualizer; import se.sics.cooja.plugins.skins.UDGMVisualizerSkin; -import se.sics.cooja.radiomediums.DirectedGraphMedium.DestinationRadio; /** * The Unit Disk Graph Radio Medium abstracts radio transmission range as circles. @@ -184,7 +183,6 @@ public class UDGM extends AbstractRadioMedium { Position senderPos = sender.getPosition(); for (DestinationRadio dest: potentialDestinations) { Radio recv = dest.radio; - Position recvPos = recv.getPosition(); /* Fail if radios are on different (but configured) channels */ if (sender.getChannel() >= 0 && @@ -192,6 +190,7 @@ public class UDGM extends AbstractRadioMedium { sender.getChannel() != recv.getChannel()) { continue; } + Position recvPos = recv.getPosition(); /* Fail if radio is turned off */ // if (!recv.isReceiverOn()) { diff --git a/tools/sensinode/nano_usb_programmer/ftdi_win32/ftd2xx.h b/tools/sensinode/nano_usb_programmer/ftdi_win32/ftd2xx.h old mode 100755 new mode 100644