diff --git a/platform/cooja/Makefile.cooja b/platform/cooja/Makefile.cooja new file mode 100644 index 000000000..cda810837 --- /dev/null +++ b/platform/cooja/Makefile.cooja @@ -0,0 +1,122 @@ +## The COOJA Simulator - cooja platform makefile +## +## This makefile's main purpose is to compile source files +## generated by the COOJA Simulator and should +## only be called from inside the simulator... +## +## However, it can also be used as a shortcut to startup the +## simulator from a customized user platform. +## See the user platform examples. + +########################################################### +ifndef COMPILE_MAIN # << shortcut, startup simulator >> + +# The COOJA Simulator jar-file location (default) +ifndef COOJA_JAR + COOJA_JAR=$(CONTIKI)/tools/cooja/dist/cooja.jar +endif + +# Java binary (default) +ifndef JAVA + JAVA=java +endif + +ifndef WINDIR + ifdef OS + ifneq (,$(findstring Windows,$(OS))) + WINDIR := Windows + endif + endif +endif + +ifndef WINDIR + # This settings are for UNIX + SEPARATOR=: +else + # These setting are for MS-DOS/Windows 95/Windows NT + SEPARATOR=; +endif + +# Command to start simulator with a source file argument +COMMAND = $(JAVA) -DPATH_CONTIKI=$(CONTIKI) -DQUICKSTART_APP=$@ \ + -cp "$(COOJA_JAR)$(SEPARATOR)$(COOJA_JAVA)" se.sics.cooja.GUI $(CLASS_CONFIGS) + +# Delete pre-defined project sourcefiles (messes up make execution) +PROJECT_SOURCEFILES = # OBS! Ugly fix + +%: + @echo "Starting simulator (using shortcut)" + $(COMMAND) + +########################################################### +else # << compile generated source file >> + +### Check/create COOJA parameters (output files) + +ifndef CONTIKI + $(error CONTIKI not defined!) +endif + +ifndef TYPEID + $(error TYPEID not defined!) +endif + +OUTPUT_DIR = obj_cooja +LIBFILE = $(OUTPUT_DIR)/$(TYPEID).library +DEPFILE = $(OUTPUT_DIR)/$(TYPEID).a +MAPFILE = $(OUTPUT_DIR)/$(TYPEID).map +MAINFILE = $(OUTPUT_DIR)/$(TYPEID).co + +COOJA = $(CONTIKI)/platform/$(TARGET) +CONTIKI_TARGET_DIRS = . dev lib sys + +COOJA_APPS = testbutton.c testetimer.c testserial.c cooyah.c + +COOJA_DEV = $(patsubst $(COOJA)/dev/%.c,%.c,$(wildcard $(COOJA)/dev/*.c)) + +COOJA_LIB = $(patsubst $(COOJA)/lib/%.c,%.c,$(wildcard $(COOJA)/lib/*.c)) + +COOJA_SYS = $(patsubst $(COOJA)/sys/%.c,%.c,$(wildcard $(COOJA)/sys/*.c)) + +CORE_FILES = random.c sensors.c leds.c serial.c + +CONTIKI_TARGET_SOURCEFILES = \ +$(COOJA_APPS) $(COOJA_DEV) $(COOJA_LIB) $(COOJA_SYS) $(CORE_FILES) + +CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) + +.SUFFIXES: + +### Define the CPU directory +CONTIKI_CPU=$(CONTIKI)/cpu/x86 + +### Compiler definitions (search contiki core last) +CC = gcc +LD = ld +AS = as +OBJCOPY = objcopy +STRIP = strip +CFLAGSNO = -I. -I$(CONTIKI_CPU) \ + $(EXTRA_CC_ARGS) \ + -I$(COOJA) \ + -I$(CONTIKI)/core \ + -DWITH_UIP -DWITH_ASCII \ + -Wall -g -I. -I/usr/local/include +CFLAGS = $(CFLAGSNO) + +### Setup directory search path for source files + +CONTIKI_TARGET_DIRS_CONCAT = ${addprefix $(COOJA)/, \ + $(CONTIKI_TARGET_DIRS)} + +vpath %.c $(PROJECTDIRS) \ + $(CONTIKIDIRS) $(APPDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \ + $(CONTIKI_CPU) + +$(LIBFILE): $(MAINFILE) $(PROJECT_OBJECTFILES) $(DEPFILE) + $(LD) -Map=$(MAPFILE) -shared $(LD_ARGS_1) -o $@ $^ $(LD_ARGS_2) + +$(DEPFILE): ${addprefix $(OBJECTDIR)/, $(CONTIKI_SOURCEFILES:.c=.o)} + $(AR) rcf $@ $^ + +endif ## END OF 'COMPILE GENERATED CONTIKI MAIN SOURCE FILE' diff --git a/platform/cooja/contiki-conf.h b/platform/cooja/contiki-conf.h new file mode 100644 index 000000000..437ede89b --- /dev/null +++ b/platform/cooja/contiki-conf.h @@ -0,0 +1,296 @@ +#ifndef __CONTIKI_CONF_H__ +#define __CONTIKI_CONF_H__ + +/* + * Copyright (c) 2005, Adam Dunkels. + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the Contiki desktop OS + * + * $Id: contiki-conf.h,v 1.1 2006/08/21 12:11:17 fros4943 Exp $ + * + */ + +#define CC_CONF_REGISTER_ARGS 1 +#define CC_CONF_FUNCTION_POINTER_ARGS 1 +#define CC_CONF_FASTCALL + +#define CC_CONF_VA_ARGS 1 + +/*------------------------------------------------------------------------------*/ +/** + * \defgroup uipopttypedef uIP type definitions + * @{ + */ + +#include + +/** + * The 8-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * char" works for most compilers. + */ +typedef uint8_t u8_t; + +/** + * The 16-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef uint16_t u16_t; + +/** + * The 32-bit unsigned data type. + * + * This may have to be tweaked for your particular compiler. "unsigned + * short" works for most compilers. + */ +typedef uint32_t u32_t; + +/** + * The statistics data type. + * + * This datatype determines how high the statistics counters are able + * to count. + */ +typedef unsigned short uip_stats_t; + +/** @} */ + + +/*------------------------------------------------------------------------------*/ + +typedef unsigned long clock_time_t; +#define CLOCK_CONF_SECOND 1000 + + +/*------------------------------------------------------------------------------*/ + +#include "ctk/ctk-vncarch.h" + +/* + * This file is used for setting various compile time settings for the + * CTK GUI toolkit. +*/ + +/* Toggles mouse support (must have support functions in the +architecture specific files to work). */ +#define CTK_CONF_MOUSE_SUPPORT 1 + +/* Defines which key that is to be used for activating the menus */ +#define CTK_CONF_MENU_KEY CH_F1 + +/* Defines which key that is to be used for switching the frontmost + window. */ +#define CTK_CONF_WINDOWSWITCH_KEY CH_F3 + +/* Defines which key that is to be used for switching to the next + widget. */ +#define CTK_CONF_WIDGETDOWN_KEY CH_TAB + +/* Defines which key that is to be used for switching to the prevoius + widget. */ +#define CTK_CONF_WIDGETUP_KEY CH_F5 + +/* Toggles support for icons. */ +#define CTK_CONF_ICONS 1 /* 107 bytes */ + +/* Toggles support for icon bitmaps. */ +#define CTK_CONF_ICON_BITMAPS 1 + +/* Toggles support for icon textmaps. */ +#define CTK_CONF_ICON_TEXTMAPS 1 + +/* Toggles support for movable windows. */ +#define CTK_CONF_WINDOWMOVE 1 /* 333 bytes */ + +/* Toggles support for closable windows. */ +#define CTK_CONF_WINDOWCLOSE 1 /* 14 bytes */ + +/* Toggles support for menus. */ +#define CTK_CONF_MENUS 1 /* 1384 bytes */ + +/* Defines the default width of a menu. */ +#define CTK_CONF_MENUWIDTH 16 +/* The maximum number of menu items in each menu. */ +#define CTK_CONF_MAXMENUITEMS 10 + +#define CTK_CONF_WIDGET_FLAGS 1 + + +/*------------------------------------------------------------------------------*/ + +#define COLOR_BLACK 0 +#define COLOR_WHITE 1 + +#define BORDERCOLOR COLOR_BLACK +#define SCREENCOLOR COLOR_BLACK + +#define WINDOWCOLOR_FOCUS COLOR_WHITE +#define WINDOWCOLOR COLOR_WHITE + +#define DIALOGCOLOR COLOR_WHITE + +#define WIDGETCOLOR_HLINK COLOR_WHITE +#define WIDGETCOLOR_FWIN COLOR_WHITE +#define WIDGETCOLOR COLOR_WHITE +#define WIDGETCOLOR_DIALOG COLOR_WHITE +#define WIDGETCOLOR_FOCUS COLOR_WHITE + +#define MENUCOLOR COLOR_WHITE +#define OPENMENUCOLOR COLOR_WHITE +#define ACTIVEMENUITEMCOLOR COLOR_WHITE + + +/*------------------------------------------------------------------------------*/ + +/* Maximum number of clients to the telnet server */ +#define CTK_TERM_CONF_MAX_TELNET_CLIENTS 3 + +/* Telnet server port */ +#define CTK_TERM_CONF_TELNET_PORT 23 + +/* Serial server output buffer size */ +#define CTK_TERM_CONF_SERIAL_BUFFER_SIZE 300 + +/* Maximum number of clients to the terminal module. + Should be set to CTK_TERM_CONF_MAX_TELNET_CLIENTS or + CTK_TERM_CONF_MAX_TELNET_CLIENTS+1 if the serial server is used too +*/ +#define CTK_TERM_CONF_MAX_CLIENTS (CTK_TERM_CONF_MAX_TELNET_CLIENTS+1) + + +/*------------------------------------------------------------------------------*/ + +#define CTK_VNCSERVER_CONF_NUMCONNS 10 + +#define CTK_VNCSERVER_CONF_MAX_ICONS 16 + + +/*------------------------------------------------------------------------------*/ + +#define EMAIL_CONF_WIDTH 36 +#define EMAIL_CONF_HEIGHT 16 + + +/*------------------------------------------------------------------------------*/ + +#define IRC_CONF_WIDTH 78 +#define IRC_CONF_HEIGHT 21 + +#define IRC_CONF_SYSTEM_STRING "GTK simulation" + + +/*------------------------------------------------------------------------------*/ + +#define LIBCONIO_CONF_SCREEN_WIDTH 80 +#define LIBCONIO_CONF_SCREEN_HEIGHT 45 + + +/*------------------------------------------------------------------------------*/ + +#define LOG_CONF_ENABLED 1 + + +/*------------------------------------------------------------------------------*/ + +#define PROGRAM_HANDLER_CONF_MAX_NUMDSCS 10 + + +/*------------------------------------------------------------------------------*/ + +#define SHELL_GUI_CONF_XSIZE 46 +#define SHELL_GUI_CONF_YSIZE 22 + + +/*------------------------------------------------------------------------------*/ + +#define TELNETD_CONF_LINELEN 80 +#define TELNETD_CONF_NUMLINES 16 + + +/*------------------------------------------------------------------------------*/ + +#define UIP_CONF_MAX_CONNECTIONS 40 +#define UIP_CONF_MAX_LISTENPORTS 40 +#define UIP_CONF_BUFFER_SIZE 420 + +#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN + +#define UIP_CONF_BROADCAST 1 + +#define UIP_CONF_TCP_SPLIT 1 + +#define UIP_CONF_LOGGING 0 + +#define UIP_CONF_UDP_CHECKSUMS 0 + + +/*------------------------------------------------------------------------------*/ + +#define VNC_CONF_VIEWPORT_WIDTH (32*8) +#define VNC_CONF_VIEWPORT_HEIGHT (16*8) + +#define VNC_CONF_REFRESH_ROWS 8 + + +/*------------------------------------------------------------------------------*/ + +/* The size of the HTML viewing area. */ +#define WWW_CONF_WEBPAGE_WIDTH 76 +#define WWW_CONF_WEBPAGE_HEIGHT 30 + +/* The size of the "Back" history. */ +#define WWW_CONF_HISTORY_SIZE 40 + +/* Defines the maximum length of an URL */ +#define WWW_CONF_MAX_URLLEN 200 + +/* The maxiumum number of widgets (i.e., hyperlinks, form elements) on + a page. */ +#define WWW_CONF_MAX_NUMPAGEWIDGETS 80 + +/* Turns
support on or off; must be on for forms to work. */ +#define WWW_CONF_RENDERSTATE 1 + +/* Toggles support for HTML forms. */ +#define WWW_CONF_FORMS 1 + +/* Maximum lengths for various HTML form parameters. */ +#define WWW_CONF_MAX_FORMACTIONLEN 200 +#define WWW_CONF_MAX_FORMNAMELEN 200 +#define WWW_CONF_MAX_INPUTNAMELEN 200 +#define WWW_CONF_MAX_INPUTVALUELEN 240 + +#define WWW_CONF_PAGEVIEW 1 + +#define LOADER_CONF_ARCH "loader/dlloader.h" + +#endif /* __CONTIKI_CONF_H__ */ diff --git a/platform/cooja/cooyah.c b/platform/cooja/cooyah.c new file mode 100644 index 000000000..508f8fe18 --- /dev/null +++ b/platform/cooja/cooyah.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2006, 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: cooyah.c,v 1.1 2006/08/21 12:11:16 fros4943 Exp $ + */ + +#include +#include +#include "net/uip.h" +#include "lib/sensors.h" +#include "dev/leds.h" +#include "dev/button-sensor.h" +#include "sys/log.h" +#include "node-id.h" + +#define COOYAH_PORT 1234 + +PROCESS(cooyah_example_process, "Example process for report"); +AUTOSTART_PROCESSES(&cooyah_example_process); + +static struct uip_udp_conn *broadcast_conn; +/*---------------------------------------------------------------------*/ +PROCESS_THREAD(cooyah_example_process, ev, data) +{ + PROCESS_BEGIN(); + + log_message("Example process started", ""); + + broadcast_conn = udp_broadcast_new(COOYAH_PORT , NULL); + + button_sensor.activate(); + + while(1) { + PROCESS_WAIT_EVENT(); + log_message("An event occured: ", ""); + + if(ev == PROCESS_EVENT_EXIT) { + log_message("shutting down\n", ""); + break; + } + + if(ev == sensors_event && data == &button_sensor && button_sensor.value(0)) { + log_message("the button is pressed, sending packet\n", ""); + + tcpip_poll_udp(broadcast_conn); + PROCESS_WAIT_UNTIL(ev == tcpip_event && uip_poll()); + uip_send("cooyah COOJA", 12); + } + + if(ev == sensors_event && data == &button_sensor && !button_sensor.value(0)) { + log_message("the button was released again, doing nothing\n", ""); + } + + if(ev == tcpip_event && uip_newdata()) { + log_message("a packet was received, turning on leds\n", ""); + log_message("PACKET DATA: ", uip_appdata); + leds_on(LEDS_ALL); + } + + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------*/ diff --git a/platform/cooja/dev/beep.c b/platform/cooja/dev/beep.c new file mode 100644 index 000000000..2ef56b42b --- /dev/null +++ b/platform/cooja/dev/beep.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006, 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: beep.c,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#include "dev/beep.h" +#include "lib/simEnvChange.h" + +const struct simInterface beep_interface; + +// COOJA variables +char simBeeped; + +/*-----------------------------------------------------------------------------------*/ +void +beep_alarm(int alarmmode, int len) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep_beep(int i) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep(void) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep_down(int d) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep_on(void) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep_off(void) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep_spinup(void) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +beep_quick(int n) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +void beep_long(clock_time_t len) +{ + simBeeped = 1; +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(beep_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/dev/beep.h b/platform/cooja/dev/beep.h new file mode 100644 index 000000000..fbe6bcab8 --- /dev/null +++ b/platform/cooja/dev/beep.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006, 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: beep.h,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#ifndef __BEEP_H__ +#define __BEEP_H__ + +#include "sys/clock.h" + +#define BEEP_ON 1 +#define BEEP_OFF 0 + +#define BEEP_ALARM1 1 +#define BEEP_ALARM2 2 + +void beep_beep(int len); + +void beep_alarm(int alarmmode, int len); + +void beep(void); + +void beep_down(int len); + +void beep_on(void); + +void beep_off(void); + +void beep_spinup(void); + +void beep_long(clock_time_t len); + +void beep_quick(int num); + +#endif /* __BEEP_H__ */ diff --git a/platform/cooja/dev/button-sensor.c b/platform/cooja/dev/button-sensor.c new file mode 100644 index 000000000..e487bc99b --- /dev/null +++ b/platform/cooja/dev/button-sensor.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2006, 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: button-sensor.c,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#include "lib/sensors.h" +#include "dev/button-sensor.h" +#include "lib/simEnvChange.h" + +const struct simInterface button_interface; +const struct sensors_sensor button_sensor; + +// COOJA variables +char simButtonChanged; +char simButtonIsDown; +char simButtonIsActive; + +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + simButtonIsActive = 1; +} +/*---------------------------------------------------------------------------*/ +static int +irq(void) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +activate(void) +{ + simButtonIsActive = 1; +} +/*---------------------------------------------------------------------------*/ +static void +deactivate(void) +{ + simButtonIsActive = 0; +} +/*---------------------------------------------------------------------------*/ +static int +active(void) +{ + return simButtonIsActive; +} +/*---------------------------------------------------------------------------*/ +static unsigned int +value(int type) +{ + return simButtonIsDown; +} +/*---------------------------------------------------------------------------*/ +static int +configure(int type, void *c) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void * +status(int type) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + // Check if button value has changed + if (simButtonChanged && simButtonIsActive) { + sensors_changed(&button_sensor); + simButtonChanged = 0; + } +} +/*---------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*---------------------------------------------------------------------------*/ + +SIM_INTERFACE(button_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); + +SENSORS_SENSOR(button_sensor, BUTTON_SENSOR, + init, irq, activate, deactivate, active, + value, configure, status); diff --git a/platform/cooja/dev/button-sensor.h b/platform/cooja/dev/button-sensor.h new file mode 100644 index 000000000..3d39ec59a --- /dev/null +++ b/platform/cooja/dev/button-sensor.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006, 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: button-sensor.h,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#ifndef __BUTTON_H__ +#define __BUTTON_H__ + +extern const struct sensors_sensor button_sensor; + +#define BUTTON_SENSOR "Button" + +#endif /* __BUTTON_H__ */ diff --git a/platform/cooja/dev/ip.c b/platform/cooja/dev/ip.c new file mode 100644 index 000000000..cf5ba5401 --- /dev/null +++ b/platform/cooja/dev/ip.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006, 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: ip.c,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#include "dev/ip.h" +#include "lib/simEnvChange.h" + +#include "net/uip.h" + +const struct simInterface ip_interface; + +// COOJA variables +char simIPa; +char simIPb; +char simIPc; +char simIPd; +char simIPChanged; + +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + uip_ipaddr_t hostaddr; + if (simIPChanged) { + uip_ipaddr(&hostaddr, simIPa, simIPb, simIPc, simIPd); + + uip_sethostaddr(&hostaddr); + simIPChanged = 0; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(ip_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/dev/ip.h b/platform/cooja/dev/ip.h new file mode 100644 index 000000000..f9b33ca35 --- /dev/null +++ b/platform/cooja/dev/ip.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2006, 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: ip.h,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#ifndef __IP_H__ +#define __IP_H__ + +#endif /* __IP_H__ */ diff --git a/platform/cooja/dev/irq.c b/platform/cooja/dev/irq.c new file mode 100644 index 000000000..d1e2ae169 --- /dev/null +++ b/platform/cooja/dev/irq.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006, 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: irq.c,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +void +irq_init(void) +{ +} + diff --git a/platform/cooja/dev/leds-arch.c b/platform/cooja/dev/leds-arch.c new file mode 100644 index 000000000..12344309c --- /dev/null +++ b/platform/cooja/dev/leds-arch.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006, 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: leds-arch.c,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +#include "dev/leds.h" +#include "lib/simEnvChange.h" + +const struct simInterface leds_interface; + +// COOJA variables +unsigned char simLedsValue; + +/*-----------------------------------------------------------------------------------*/ +void leds_arch_init() { + simLedsValue = 0; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char leds_arch_get() { + return simLedsValue; +} +/*-----------------------------------------------------------------------------------*/ +void leds_arch_set(unsigned char leds) { + if(leds != simLedsValue) { + simLedsValue = leds; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(leds_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/dev/moteid.c b/platform/cooja/dev/moteid.c new file mode 100644 index 000000000..8de4f813b --- /dev/null +++ b/platform/cooja/dev/moteid.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: moteid.c,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#include "dev/moteid.h" +#include "lib/simEnvChange.h" +#include "lib/random.h" + +const struct simInterface moteid_interface; + +// COOJA variables +int simMoteID; +char simMoteIDChanged; + +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + if (simMoteIDChanged) { + simMoteIDChanged = 0; + random_init((simMoteID+1) * 100 % 99); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(moteid_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/dev/moteid.h b/platform/cooja/dev/moteid.h new file mode 100644 index 000000000..2d9f2c6c6 --- /dev/null +++ b/platform/cooja/dev/moteid.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2006, 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: moteid.h,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#ifndef __MOTEID_H__ +#define __MOTEID_H__ + +extern int simMoteID; + +#endif /* __MOTEID_H__ */ diff --git a/platform/cooja/dev/pir-sensor.c b/platform/cooja/dev/pir-sensor.c new file mode 100644 index 000000000..73842a90b --- /dev/null +++ b/platform/cooja/dev/pir-sensor.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2006, 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: pir-sensor.c,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#include "lib/sensors.h" +#include "dev/pir-sensor.h" +#include "lib/simEnvChange.h" + +const struct simInterface pir_interface; +const struct sensors_sensor pir_sensor; + +// COOJA variables +char simPirChanged; +char simPirIsActive; +char simPirValue = 0; + +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + simPirIsActive = 1; +} +/*---------------------------------------------------------------------------*/ +static int +irq(void) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +activate(void) +{ + simPirIsActive = 1; +} +/*---------------------------------------------------------------------------*/ +static void +deactivate(void) +{ + simPirIsActive = 0; +} +/*---------------------------------------------------------------------------*/ +static int +active(void) +{ + return simPirIsActive; +} +/*---------------------------------------------------------------------------*/ +static unsigned int +value(int type) +{ + return simPirValue; +} +/*---------------------------------------------------------------------------*/ +static int +configure(int type, void *c) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void * +status(int type) +{ + return NULL; +} +/*---------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + // Check if PIR value has changed + if (simPirIsActive && simPirChanged) { + simPirValue = !simPirValue; + + sensors_changed(&pir_sensor); + simPirChanged = 0; + } +} +/*---------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*---------------------------------------------------------------------------*/ + +SIM_INTERFACE(pir_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); + +SENSORS_SENSOR(pir_sensor, PIR_SENSOR, + init, irq, activate, deactivate, active, + value, configure, status); diff --git a/platform/cooja/dev/pir-sensor.h b/platform/cooja/dev/pir-sensor.h new file mode 100644 index 000000000..e3aa95ea4 --- /dev/null +++ b/platform/cooja/dev/pir-sensor.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006, 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: pir-sensor.h,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#ifndef __PIR_H__ +#define __PIR_H__ + +extern const struct sensors_sensor pir_sensor; + +#define PIR_SENSOR "PIR" + +#endif /* __PIR_H__ */ diff --git a/platform/cooja/dev/radio-arch.c b/platform/cooja/dev/radio-arch.c new file mode 100644 index 000000000..b5370546c --- /dev/null +++ b/platform/cooja/dev/radio-arch.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2006, 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: radio-arch.c,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +#include "dev/radio-arch.h" +#include "dev/radio.h" + +#include "lib/simEnvChange.h" + +#include +#include +#include +#include "net/uip.h" +#include "net/uip-fw.h" +#include "sys/etimer.h" + +#include "sys/log.h" + +const struct simInterface radio_interface; + +// COOJA variables +char simReceivedPacket; +char simSentPacket; +char simReceivedPacketData[UIP_BUFSIZE]; +char simSentPacketData[UIP_BUFSIZE]; +int simSentPacketSize; +int simReceivedPacketSize; +char simEtherBusy; +int retryCounter; +char simRadioHWOn = 1; + + +// Ether process +PROCESS(ether_process, "Simulated Ether"); + +PROCESS_THREAD(ether_process, ev, data) +{ + static struct etimer send_timer; + + PROCESS_BEGIN(); + + // All outgoing messages pass through this process + // By using the COOJA variables simEtherBusy and !!!!TODO signalstrength!!!! + // this may be used to imitate a simple MAC protocol. + while(1) { + PROCESS_WAIT_EVENT(); + + // MAC protocol imitiation + // (this process is polled from simDoSend()) + + // Confirm we actually have data to send and radio hardware is on + if (simRadioHWOn && simSentPacketSize > 0) { + + // Wait some random time to avoid initial collisions + // MAC uses external random generator to get stochastic radio behaviour + etimer_set(&send_timer, rand() % 20); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&send_timer)); + + retryCounter = 0; + while (simEtherBusy && retryCounter < 5) { + retryCounter++; + + // Wait some random time hoping ether will free + // MAC uses external random generator to get stochastic radio behaviour + etimer_set(&send_timer, rand() % 20); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&send_timer)); + } + + if (simEtherBusy) { + log_message("MAC layer skipping packet", ""); + } else { + // Tell COOJA about our new packet + simSentPacket = 1; + } + } + } + + PROCESS_END(); +} + + +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + // Handle incoming network packets if any + if (simReceivedPacket) { + + + // If hardware is turned off, just remove packet + if (!simRadioHWOn) { + simReceivedPacket = 0; + simReceivedPacketSize = 0; + return; + } + + // Reset flag + simReceivedPacket = 0; + + if (simReceivedPacketSize == 0) { + fprintf(stderr, "simReceivedPacketSize == 0: Didn't I receive a packet?\n"); + return; + } + + // Copy incoming data to correct buffers and call handling routines + uip_len = simReceivedPacketSize; + + if(uip_len > UIP_BUFSIZE) { + fprintf(stderr, "doInterfaceActionsBeforeTick>> uip_len too large - dropping\n"); + uip_len = 0; + } else { + memcpy(&uip_buf[UIP_LLH_LEN], &simReceivedPacketData[0], simReceivedPacketSize); + simReceivedPacketSize = 0; + + // Handle new packet + tcpip_input(); + } + } +} + +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ + // Nothing to do +} +/*-----------------------------------------------------------------------------------*/ +u8_t +simDoSend(void) +{ + // If hardware is turned off, just remove packet + if (!simRadioHWOn) { + // Should we reset uip_len if radio is off? + uip_len = 0; + return UIP_FW_DROPPED; + } + + // If outgoing data, but too large, drop it + if(uip_len > UIP_BUFSIZE) { + fprintf(stderr, "simDoSend>> uip_len too large - dropping\n"); + uip_len = 0; + return UIP_FW_TOOLARGE; + } + + // If outgoing data, back it up, and wake ether process + if (uip_len > 0) { + // Backup packet data/size + memcpy(&simSentPacketData[0], &uip_buf[UIP_LLH_LEN], uip_len); + simSentPacketSize = uip_len; + + process_poll(ðer_process); + return UIP_FW_OK; + } + return UIP_FW_ZEROLEN; +} +/*-----------------------------------------------------------------------------------*/ +/** + * \brief Turn radio on. + * + * This function turns the radio hardware on. + */ +void +radio_on(void) { + simRadioHWOn = 1; +} +/*-----------------------------------------------------------------------------------*/ +/** + * \brief Turn radio off. + * + * This function turns the radio hardware off. + */ +void radio_off(void) { + simRadioHWOn = 0; +} +/*-----------------------------------------------------------------------------------*/ +SIM_INTERFACE(radio_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/dev/radio-arch.h b/platform/cooja/dev/radio-arch.h new file mode 100644 index 000000000..2af20505a --- /dev/null +++ b/platform/cooja/dev/radio-arch.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006, 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: radio-arch.h,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#ifndef __RADIO_ARCH_H__ +#define __RADIO_ARCH_H__ + +#include "contiki.h" +#include "net/uip.h" + +PROCESS_NAME(ether_process); +u8_t simDoSend(void); + +#endif /* __RADIO_ARCH_H__ */ diff --git a/platform/cooja/dev/rs232.c b/platform/cooja/dev/rs232.c new file mode 100644 index 000000000..734b6591e --- /dev/null +++ b/platform/cooja/dev/rs232.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006, 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: rs232.c,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +#include "lib/sensors.h" +#include "dev/rs232.h" +#include "dev/serial.h" +#include "lib/simEnvChange.h" +#include +#include + +const struct simInterface rs232_interface; + +#define SERIAL_BUF_SIZE 1024 + +// COOJA variables +char simSerialReceivingData[SERIAL_BUF_SIZE]; +int simSerialReceivingLength; +char simSerialReceivingFlag; +char simSerialSendingData[SERIAL_BUF_SIZE]; +int simSerialSendingLength; +char simSerialSendingFlag; + +static int (* input_handler)(unsigned char) = NULL; + +/*-----------------------------------------------------------------------------------*/ +void rs232_init(void) { } +/*-----------------------------------------------------------------------------------*/ +void rs232_set_speed(unsigned char speed) { } +/*-----------------------------------------------------------------------------------*/ +void +rs232_set_input(int (*f)(unsigned char)) +{ + input_handler = f; +} +/*-----------------------------------------------------------------------------------*/ +void rs232_send(char c) { + simSerialSendingData[simSerialSendingLength] = c; + simSerialSendingLength += 1; + simSerialSendingFlag = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +rs232_print(char *message) +{ + memcpy(&simSerialSendingData[0] + simSerialSendingLength, &message[0], strlen(message)); + simSerialSendingLength += strlen(message); + simSerialSendingFlag = 1; +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + int i; + + // Check if this mote has received data on RS232 + if (simSerialReceivingFlag && simSerialReceivingLength > 0) { + // Tell user specified poll function + if(input_handler != NULL) + for (i=0; i < simSerialReceivingLength; i++) + input_handler(simSerialReceivingData[i]); + + // Tell serial process + for (i=0; i < simSerialReceivingLength; i++) + serial_input_byte(simSerialReceivingData[i]); + + serial_input_byte(0x0a); + + simSerialReceivingLength = 0; + simSerialReceivingFlag = 0; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(rs232_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/dev/rs232.h b/platform/cooja/dev/rs232.h new file mode 100644 index 000000000..166243a24 --- /dev/null +++ b/platform/cooja/dev/rs232.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2005, 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. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: rs232.h,v 1.1 2006/08/21 12:11:19 fros4943 Exp $ + */ + +/** \addtogroup esb + * @{ */ + +/** + * \defgroup esbrs232 ESB RS232 + * + * @{ + */ + +/** + * \file + * Header file for MSP430 RS232 driver. + * \author Adam Dunkels + * + */ +#ifndef __RS232_H__ +#define __RS232_H__ + + +#define RS232_19200 1 +#define RS232_38400 2 +#define RS232_57600 3 +#define RS232_115200 4 + +/** + * \brief Initialize the RS232 module + * + * This function is called from the boot up code to + * initalize the RS232 module. + */ +void rs232_init(void); + +/** + * \brief Set an input handler for incoming RS232 data + * \param f A pointer to a byte input handler + * + * This function sets the input handler for incoming RS232 + * data. The input handler function is called for every + * incoming data byte. The function is called from the + * RS232 interrupt handler, so care must be taken when + * implementing the input handler to avoid race + * conditions. + * + * The return value of the input handler affects the sleep + * mode of the CPU: if the input handler returns non-zero + * (true), the CPU is awakened to let other processing + * take place. If the input handler returns zero, the CPU + * is kept sleeping. + */ +void rs232_set_input(int (* f)(unsigned char)); + +/** + * \brief Configure the speed of the RS232 hardware + * \param speed The speed + * + * This function configures the speed of the RS232 + * hardware. The allowed parameters are RS232_19200, + * RS232_38400, RS232_57600, and RS232_115200. + */ +void rs232_set_speed(unsigned char speed); + +/** + * \brief Print a text string on RS232 + * \param str A pointer to the string that is to be printed + * + * This function prints a string to RS232. The string must + * be terminated by a null byte. The RS232 module must be + * correctly initalized and configured for this function + * to work. + */ +void rs232_print(char *text); + +/** + * \brief Print a character on RS232 + * \param c The character to be printed + * + * This function prints a character to RS232. The RS232 + * module must be correctly initalized and configured for + * this function to work. + */ +void rs232_send(char c); + +#endif /* __RS232_H__ */ + +/** @} */ /** @} */ diff --git a/platform/cooja/dev/vib-sensor.c b/platform/cooja/dev/vib-sensor.c new file mode 100644 index 000000000..3228c8e1e --- /dev/null +++ b/platform/cooja/dev/vib-sensor.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2006, 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: vib-sensor.c,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#include "lib/sensors.h" +#include "dev/vib-sensor.h" +#include "lib/simEnvChange.h" + +const struct simInterface vib_interface; +const struct sensors_sensor vib_sensor; + +// COOJA variables +char simVibChanged; +char simVibIsActive; +char simVibValue = 0; + +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + simVibIsActive = 1; +} +/*---------------------------------------------------------------------------*/ +static int +irq(void) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +activate(void) +{ + simVibIsActive = 1; +} +/*---------------------------------------------------------------------------*/ +static void +deactivate(void) +{ + simVibIsActive = 0; +} +/*---------------------------------------------------------------------------*/ +static int +active(void) +{ + return simVibIsActive; +} +/*---------------------------------------------------------------------------*/ +static unsigned int +value(int type) +{ + return simVibValue; +} +/*---------------------------------------------------------------------------*/ +static int +configure(int type, void *c) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void * +status(int type) +{ + return NULL; +} +/*---------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + // Check if Vib value has changed + if (simVibIsActive && simVibChanged) { + simVibValue = !simVibValue; + + sensors_changed(&vib_sensor); + simVibChanged = 0; + } +} +/*---------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*---------------------------------------------------------------------------*/ + +SIM_INTERFACE(vib_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); + +SENSORS_SENSOR(vib_sensor, VIB_SENSOR, + init, irq, activate, deactivate, active, + value, configure, status); diff --git a/platform/cooja/dev/vib-sensor.h b/platform/cooja/dev/vib-sensor.h new file mode 100644 index 000000000..beaa05e5f --- /dev/null +++ b/platform/cooja/dev/vib-sensor.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006, 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: vib-sensor.h,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#ifndef __VIB_H__ +#define __VIB_H__ + +extern const struct sensors_sensor vib_sensor; + +#define VIB_SENSOR "Vibration sensor" + +#endif /* __VIB_H__ */ diff --git a/platform/cooja/lib/simEnvChange.c b/platform/cooja/lib/simEnvChange.c new file mode 100644 index 000000000..0aa5829f0 --- /dev/null +++ b/platform/cooja/lib/simEnvChange.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006, 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: simEnvChange.c,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +#include +#include + +#include "lib/simEnvChange.h" + +// All registered interfaces +extern const struct simInterface *simInterfaces[]; + +int simProcessRunValue; +int simEtimerPending; +int simNextExpirationTime; + +void doActionsBeforeTick() { + // Poll all interfaces to do their thing before the tick + int i; + for(i = 0; simInterfaces[i] != NULL; ++i) { + simInterfaces[i]->doActionsBeforeTick(); + } +} + +void doActionsAfterTick() { + // Poll all interfaces to do their thing after the tick + int i; + for(i = 0; simInterfaces[i] != NULL; ++i) { + simInterfaces[i]->doActionsAfterTick(); + } +} diff --git a/platform/cooja/lib/simEnvChange.h b/platform/cooja/lib/simEnvChange.h new file mode 100644 index 000000000..15d4c7f4c --- /dev/null +++ b/platform/cooja/lib/simEnvChange.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006, 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: simEnvChange.h,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +#ifndef __SIMENVCHANGE_H__ +#define __SIMENVCHANGE_H__ + +// Simulation interface structure +struct simInterface { + void (* doActionsBeforeTick) (void); + void (* doActionsAfterTick) (void); +}; + +// Variable for keeping the last process_run() return value +extern int simProcessRunValue; +extern int simEtimerPending; +extern int simNextExpirationTime; + +// Definition for registering an interface +#define SIM_INTERFACE(name, doActionsBeforeTick, doActionsAfterTick) \ +const struct simInterface name = { doActionsBeforeTick, doActionsAfterTick } + +// Definition for getting access to simulation interface +#define SIM_INTERFACE_NAME(name) \ +extern const struct simInterface name + +// Definition for creating all interface (from main file) +#define SIM_INTERFACES(...) \ +const struct simInterface *simInterfaces[] = {__VA_ARGS__, NULL}; + +// Functions which polls all interfaces +void doActionsBeforeTick(); +void doActionsAfterTick(); + +#endif /* __SIMENVCHANGE_H__ */ diff --git a/platform/cooja/node-id.h b/platform/cooja/node-id.h new file mode 100644 index 000000000..75c6b7436 --- /dev/null +++ b/platform/cooja/node-id.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005, 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. + * + * This file is part of the Configurable Sensor Network Application + * Architecture for sensor nodes running the Contiki operating system. + * + * $Id: node-id.h,v 1.1 2006/08/21 12:11:16 fros4943 Exp $ + * + * ----------------------------------------------------------------- + * + * Author : Adam Dunkels, Joakim Eriksson, Niclas Finne + * Created : 2005-12-09 + * Updated : $Date: 2006/08/21 12:11:16 $ + * $Revision: 1.1 $ + */ + +#ifndef __NODE_ID_H__ +#define __NODE_ID_H__ + +#include "dev/moteid.h" + +#define node_id simMoteID + +#endif /* __NODE_ID_H__ */ diff --git a/platform/cooja/sys/clock.c b/platform/cooja/sys/clock.c new file mode 100644 index 000000000..754a018f6 --- /dev/null +++ b/platform/cooja/sys/clock.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006, 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: clock.c,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +#include "sys/clock.h" +#include "lib/simEnvChange.h" + +const struct simInterface clock_interface; + +// COOJA variables +clock_time_t simCurrentTime; + +/*-----------------------------------------------------------------------------------*/ +void +clock_init(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +clock_time_t +clock_time(void) +{ + return simCurrentTime; +} +/*-----------------------------------------------------------------------------------*/ +void +clock_delay(unsigned int delay_time) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(clock_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/sys/log.c b/platform/cooja/sys/log.c new file mode 100644 index 000000000..fc3a5902a --- /dev/null +++ b/platform/cooja/sys/log.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006, 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: log.c,v 1.1 2006/08/21 12:11:20 fros4943 Exp $ + */ + +#include "sys/log.h" +#include "lib/simEnvChange.h" +#include + +const struct simInterface simlog_interface; + +// COOJA variables +char simLoggedData[1024]; +int simLoggedLength; +char simLoggedFlag; + +void simlog(const char *message); + +/*-----------------------------------------------------------------------------------*/ +void +log_message(const char *part1, const char *part2) +{ + simlog(part1); + simlog(part2); +} +/*-----------------------------------------------------------------------------------*/ +void +simlog(const char *message) +{ + memcpy(&simLoggedData[0] + simLoggedLength, &message[0], strlen(message)); + simLoggedLength += strlen(message); + simLoggedFlag = 1; +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(simlog_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/platform/cooja/testbutton.c b/platform/cooja/testbutton.c new file mode 100644 index 000000000..c11b350d2 --- /dev/null +++ b/platform/cooja/testbutton.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006, 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: testbutton.c,v 1.1 2006/08/21 12:11:16 fros4943 Exp $ + */ + + +#include "contiki.h" +#include "sys/loader.h" + +#include + +#include "lib/list.h" +#include "lib/random.h" + +#include "net/uip.h" + +#include "lib/sensors.h" +#include "sys/log.h" +#include "dev/button-sensor.h" + + +PROCESS(button_process, "Button test process"); + +PROCESS_THREAD(button_process, ev, data) +{ + static int custom_counter = 0; + static char logMess[100]; + + PROCESS_BEGIN(); + + sprintf(logMess, "Starting Button test process (counter=%i)\n", custom_counter); + log_message(logMess, ""); + + while(1) { + PROCESS_WAIT_EVENT(); + + if (button_sensor.value(0)) { + custom_counter++; + + sprintf(logMess, "button> Button pressed (counter=%i)\n", custom_counter); + log_message(logMess, ""); + } + } + + PROCESS_END(); +} diff --git a/platform/cooja/testbutton.h b/platform/cooja/testbutton.h new file mode 100644 index 000000000..8bd966d86 --- /dev/null +++ b/platform/cooja/testbutton.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006, 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: testbutton.h,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#ifndef __BUTTON_TEST_H__ +#define __BUTTON_TEST_H__ + +#include "contiki.h" + +PROCESS_NAME(button_test_process); + +#endif /* __BUTTON_TEST_H__ */ diff --git a/platform/cooja/testetimer.c b/platform/cooja/testetimer.c new file mode 100644 index 000000000..44b1cea91 --- /dev/null +++ b/platform/cooja/testetimer.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006, 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: testetimer.c,v 1.1 2006/08/21 12:11:17 fros4943 Exp $ + */ + + +#include +#include "contiki.h" +#include "sys/loader.h" + +#include "lib/list.h" +#include "lib/random.h" + +#include "net/uip.h" + +#include "sys/etimer.h" +#include "sys/clock.h" + +#include "lib/sensors.h" +#include "sys/log.h" + + +PROCESS(etimer_test_process, "ETimer test process"); + +PROCESS_THREAD(etimer_test_process, ev, data) +{ + static struct etimer mytimer; + + static int custom_counter = 0; + static char logMess[100]; + + PROCESS_BEGIN(); + + etimer_set(&mytimer, 1111); + + sprintf(logMess, "Starting ETimer test process (counter=%i)\n", custom_counter); + log_message(logMess, ""); + + while(1) { + PROCESS_WAIT_EVENT(); + + if (etimer_expired(&mytimer)) { + custom_counter++; + sprintf(logMess, "etimer> Timed out(counter=%i)\n", custom_counter); + log_message(logMess, ""); + + etimer_restart(&mytimer); + } + } + + PROCESS_END(); +} diff --git a/platform/cooja/testetimer.h b/platform/cooja/testetimer.h new file mode 100644 index 000000000..46b2c1382 --- /dev/null +++ b/platform/cooja/testetimer.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006, 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: testetimer.h,v 1.1 2006/08/21 12:11:17 fros4943 Exp $ + */ + +#ifndef __ETIMER_TEST_H__ +#define __ETIMER_TEST_H__ + +#include "contiki.h" + +PROCESS_NAME(etimer_test_process); + +#endif /* __ETIMER_TEST_H__ */ diff --git a/platform/cooja/testserial.c b/platform/cooja/testserial.c new file mode 100644 index 000000000..3d316948f --- /dev/null +++ b/platform/cooja/testserial.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006, 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: testserial.c,v 1.1 2006/08/21 12:11:16 fros4943 Exp $ + */ + + +#include "contiki.h" +#include "sys/loader.h" + +#include + +#include "lib/list.h" +#include "lib/random.h" + +#include "net/uip.h" + +#include "lib/sensors.h" +#include "sys/log.h" +#include "dev/serial.h" +#include "dev/rs232.h" + + +PROCESS(serial_test_process, "Serial test process"); + +AUTOSTART_PROCESSES(&serial_test_process); + +PROCESS_THREAD(serial_test_process, ev, data) +{ + static struct etimer mytimer; + + PROCESS_BEGIN(); + + etimer_set(&mytimer, CLOCK_SECOND); + + /* Starts the serial process among other */ + serial_init(); + + log_message("serial> Starting test process\n", ""); + + while(1) { + PROCESS_WAIT_EVENT(); + + if (etimer_expired(&mytimer)) { + log_message("serial> Sending serial data now\n", ""); + etimer_restart(&mytimer); + rs232_print("GNU's not Unix\n"); + } + + if(ev == serial_event_message) { + log_message("serial> Message received: ", data); + } + } + + PROCESS_END(); +} diff --git a/platform/cooja/testserial.h b/platform/cooja/testserial.h new file mode 100644 index 000000000..d7c757350 --- /dev/null +++ b/platform/cooja/testserial.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006, 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: testserial.h,v 1.1 2006/08/21 12:11:18 fros4943 Exp $ + */ + +#ifndef __BUTTON_TEST_H__ +#define __BUTTON_TEST_H__ + +#include "contiki.h" + +PROCESS_NAME(button_test_process); + +#endif /* __BUTTON_TEST_H__ */ diff --git a/tools/cooja/build.xml b/tools/cooja/build.xml new file mode 100644 index 000000000..cd034b152 --- /dev/null +++ b/tools/cooja/build.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + +The COOJA Simulator + +> ant run + Starts COOJA simulator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/cooja/config/code_main_template b/tools/cooja/config/code_main_template new file mode 100644 index 000000000..74a738945 --- /dev/null +++ b/tools/cooja/config/code_main_template @@ -0,0 +1,219 @@ +/** + * \defgroup coojacore COOJA Simulator Core + * @{ + */ + +/** + * \file + * C code template for generating contiki source code files from COOJA + * Simulator. This file should not be compiled directly. + * \author + * Fredrik Osterlind + */ + +/*---------------------------------------------------------------------------*/ +/** + * \page coojacore COOJA Simulator Core + * + * COOJA Simulator Core ("the Core") represents the entire C code part of COOJA + * Simulator. + * This part shortly consists of simulated sensors and actuators and code for + * communicating with the Java part. + * + * Communication with the Core should always be handled via dedicated classes + * (MoteType), and never directly. MoteType works as an interface giving access + * to variable's values given their name (through CoreComm->Lib?). + * + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" +#include "contiki-lib.h" +#include "contiki-conf.h" +#include "sys/clock.h" + +#include "lib/simEnvChange.h" +#include "lib/sensors.h" +#include "net/uip.h" +#include "dev/radio-arch.h" +#include "sys/etimer.h" + +/* Declare all initialization processes */ +[PROCESS_DEFINITIONS] + +/* Declare all sensors */ +[SENSOR_DEFINITIONS] + +/* Declare all simulation interfaces */ +[INTERFACE_DEFINITIONS] + + +/* Create initialization process array */ +[PROCESS_ARRAY] + +/* Create sensor array */ +[SENSOR_ARRAY] + +/* Create simulation interfaces array */ +[INTERFACE_ARRAY] + +// Default network interface +static struct uip_fw_netif simNetworkIF = + {UIP_FW_NETIF(0,0,0,0, 0,0,0,0, simDoSend)}; + +/* + * referenceVar is used for comparing absolute and process relative memory. + * (this must not be static due to memory locations) + */ +int referenceVar; + +extern unsigned long _end; + +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize a mote by starting processes etc. + * + * This function initializes a mote by starting certain + * processes and setting up the environment. + * + * This is a JNI function and should only be called via the + * responsible Java part (MoteType.java). + */ +JNIEXPORT void JNICALL +Java_se_sics_cooja_corecomm_[CLASS_NAME]_init(JNIEnv *env, jobject obj) +{ + /* Initialize random generator */ + random_init(0); + + /* Start process handler */ + process_init(); + + /* Start Contiki processes */ + procinit_init(); + + /* Initialize uIP */ + uip_init(); + uip_fw_init(); + + /* Register network interface */ + uip_fw_default(&simNetworkIF); + + /* Start user applications */ + autostart_start((struct process **) autostart_processes); + } +/*---------------------------------------------------------------------------*/ +/** + * \brief Get a segment from the process memory. + * \param start Start address of segment + * \param length Size of memory segment + * \return Java byte array containing a copy of memory segment. + * + * Fetches a memory segment from the process memory starting at + * (start), with size (length). This function does not perform + * ANY error checking, and the process may crash if addresses are + * not available/readable. + * + * This is a JNI function and should only be called via the + * responsible Java part (MoteType.java). + */ +JNIEXPORT jbyteArray JNICALL +Java_se_sics_cooja_corecomm_[CLASS_NAME]_getMemory(JNIEnv *env, jobject obj, jint start, jint length) +{ + jbyteArray ret=(*env)->NewByteArray(env, length); + (*env)->SetByteArrayRegion(env, ret, 0, (size_t) length, (jbyte *) start); + + return (ret); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Replace a segment of the process memory with given byte array. + * \param start Start address of segment + * \param length Size of memory segment + * \param mem_arr Byte array contaning new memory + * + * Replaces a process memory segment with given byte array. + * This function does not perform ANY error checking, and the + * process may crash if addresses are not available/writable. + * + * This is a JNI function and should only be called via the + * responsible Java part (MoteType.java). + */ +JNIEXPORT void JNICALL +Java_se_sics_cooja_corecomm_[CLASS_NAME]_setMemory(JNIEnv *env, jobject obj, jint start, jint length, jbyteArray mem_arr) +{ + jbyte *mem = (*env)->GetByteArrayElements(env, mem_arr, 0); + memcpy((void *) start, mem, length); + (*env)->ReleaseByteArrayElements(env, mem_arr, mem, 0); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Let mote execute one "block" of code (tick mote). + * + * Let mote defined by the active contiki processes and current + * process memory execute some program code. This code must not block + * or else this function will never return. A typical contiki + * process will return when it executes PROCESS_WAIT..() statements. + * + * Before the control is left to contiki processes, any messages + * from the Java part are handled. These may for example be + * incoming network data. After the contiki processes return control, + * messages to the Java part are also handled (those which may need + * special attention). + * + * This is a JNI function and should only be called via the + * responsible Java part (MoteType.java). + */ +JNIEXPORT void JNICALL +Java_se_sics_cooja_corecomm_[CLASS_NAME]_tick(JNIEnv *env, jobject obj) +{ + /* Let all simulation interfaces act first */ + doActionsBeforeTick(); + + /* Check if any e-timers are pending (save result for state decisions) */ + if (etimer_pending()) { + /* Poll etimers */ + etimer_request_poll(); + simEtimerPending = 1; + } else { + simEtimerPending = 0; + } + + /* Execute the contiki code (save process_run return value for state decisions) */ + simProcessRunValue = process_run(); + + /* Let all simulation interfaces act before returning to java */ + doActionsAfterTick(); + + /* Look for new e-timers */ + if (!simEtimerPending && etimer_pending()) { + /* Poll etimers */ + etimer_request_poll(); + simEtimerPending = 1; + } + + /* Save nearest event timer expiration time (0 if no timers) */ + simNextExpirationTime = etimer_next_expiration_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Get the absolute memory address of a special variable. + * \return Absolute memory address. + * + * Returns the absolute memory address of a special variable + * "referenceVar". By comparing this address with the relative + * address (from the map file) for referenceVar, an runtime offset + * can be calculated. + * + * This is a JNI function and should only be called via the + * responsible Java part (MoteType.java). + */ +JNIEXPORT jint JNICALL +Java_se_sics_cooja_corecomm_[CLASS_NAME]_getReferenceAbsAddr(JNIEnv *env, jobject obj) +{ + return (jint) &referenceVar; +} + +/** @} */ diff --git a/tools/cooja/config/cooja_default.config b/tools/cooja/config/cooja_default.config new file mode 100644 index 000000000..d7c76784b --- /dev/null +++ b/tools/cooja/config/cooja_default.config @@ -0,0 +1,34 @@ + +se.sics.cooja.interfaces.Battery.INFINITE_ENERGY_bool = false +se.sics.cooja.interfaces.Battery.INITIAL_ENERGY_mQ = 13500000 +se.sics.cooja.interfaces.Battery.CPU_AWAKE_mA = 1.49 +se.sics.cooja.interfaces.Battery.CPU_LPM_mA = 1.34 + +se.sics.cooja.contikimote.interfaces.ContikiRS232.CONSUMPTION_PER_CHAR_mQ = 1 +se.sics.cooja.contikimote.interfaces.ContikiRS232.EXTERNAL_INTERRUPT_bool = true + +se.sics.cooja.contikimote.interfaces.ContikiLED.GREEN_LED_CONSUMPTION_mA = 5.69 +se.sics.cooja.contikimote.interfaces.ContikiLED.YELLOW_LED_CONSUMPTION_mA = 5.69 +se.sics.cooja.contikimote.interfaces.ContikiLED.RED_LED_CONSUMPTION_mA = 5.69 + +se.sics.cooja.contikimote.interfaces.ContikiButton.EXTERNAL_INTERRUPT_bool = true + +se.sics.cooja.contikimote.interfaces.ContikiBeeper.BEEP_CONSUMPTION_mQ = 1.669 + +se.sics.cooja.contikimote.interfaces.ContikiPIR.ACTIVE_CONSUMPTION_mA = 0.4 +se.sics.cooja.contikimote.interfaces.ContikiPIR.EXTERNAL_INTERRUPT_bool = true + +se.sics.cooja.contikimote.interfaces.ContikiRadio.ACTIVE_CONSUMPTION_mA = 5 +se.sics.cooja.contikimote.interfaces.ContikiRadio.EXTERNAL_INTERRUPT_bool = true + +se.sics.cooja.contikimote.interfaces.ContikiVib.ACTIVE_CONSUMPTION_mA = 1.58 +se.sics.cooja.contikimote.interfaces.ContikiVib.EXTERNAL_INTERRUPT_bool = true + +se.sics.cooja.contikimote.ContikiMoteType.MOTE_INTERFACES = se.sics.cooja.interfaces.Position se.sics.cooja.interfaces.Battery se.sics.cooja.contikimote.interfaces.ContikiVib se.sics.cooja.contikimote.interfaces.ContikiMoteID se.sics.cooja.contikimote.interfaces.ContikiRS232 se.sics.cooja.contikimote.interfaces.ContikiBeeper se.sics.cooja.contikimote.interfaces.ContikiIPAddress se.sics.cooja.contikimote.interfaces.ContikiRadio se.sics.cooja.contikimote.interfaces.ContikiButton se.sics.cooja.contikimote.interfaces.ContikiPIR se.sics.cooja.contikimote.interfaces.ContikiClock se.sics.cooja.contikimote.interfaces.ContikiLED se.sics.cooja.contikimote.interfaces.ContikiLog +se.sics.cooja.contikimote.ContikiMoteType.C_SOURCES = +se.sics.cooja.GUI.MOTETYPES = se.sics.cooja.contikimote.ContikiMoteType se.sics.cooja.motes.DummyMoteType +se.sics.cooja.GUI.PLUGINS = se.sics.cooja.plugins.VisState se.sics.cooja.plugins.VisBattery se.sics.cooja.plugins.VisTraffic se.sics.cooja.plugins.LogListener se.sics.cooja.plugins.MoteInformation se.sics.cooja.plugins.MoteInterfaceViewer se.sics.cooja.plugins.VariableWatcher +se.sics.cooja.GUI.IP_DISTRIBUTORS = se.sics.cooja.ipdistributors.RandomIPDistributor se.sics.cooja.ipdistributors.SpatialIPDistributor se.sics.cooja.ipdistributors.IdIPDistributor +se.sics.cooja.GUI.POSITIONERS = se.sics.cooja.positioners.RandomPositioner se.sics.cooja.positioners.LinearPositioner se.sics.cooja.positioners.EllipsePositioner +se.sics.cooja.GUI.RADIOMEDIUMS = se.sics.cooja.radiomediums.StandardRadioMedium se.sics.cooja.radiomediums.SilentRadioMedium + diff --git a/tools/cooja/config/external_tools_linux.config b/tools/cooja/config/external_tools_linux.config new file mode 100644 index 000000000..d9f5b07df --- /dev/null +++ b/tools/cooja/config/external_tools_linux.config @@ -0,0 +1,17 @@ +PATH_CONTIKI = ../../.. +PATH_COOJA_CORE_RELATIVE = /platform/cooja +PATH_MAKE = make +PATH_LINKER = ld +PATH_SHELL = sh +PATH_C_COMPILER = gcc +CMD_GREP_PROCESSES = grep "^PROCESS_THREAD([^,]*,[^,]*,[^)]*)" -o -H +REGEXP_PARSE_PROCESSES = ([^/]*.c):PROCESS_THREAD\\(([^,]*),[^,]*,[^)]*\\) +CMD_GREP_INTERFACES = grep "^SIM_INTERFACE([^,]*," -o -d skip -D skip -H -r +REGEXP_PARSE_INTERFACES = ([^/]*.c):SIM_INTERFACE\\(([^,]*), +CMD_GREP_SENSORS = grep "^SENSORS_SENSOR([^,]*," -o -d skip -D skip -H -r +REGEXP_PARSE_SENSORS = ([^/]*.c):SENSORS_SENSOR\\(([^,]*), +LINKER_ARGS_1 = +LINKER_ARGS_2 = +COMPILER_ARGS = +CONTIKI_STANDARD_PROCESSES = sensors_process;etimer_process;tcpip_process;ether_process;uip_fw_process +CONTIKI_MAIN_TEMPLATE_FILENAME = code_main_template \ No newline at end of file diff --git a/tools/cooja/config/external_tools_win32.config b/tools/cooja/config/external_tools_win32.config new file mode 100644 index 000000000..bde282ba5 --- /dev/null +++ b/tools/cooja/config/external_tools_win32.config @@ -0,0 +1,17 @@ +PATH_CONTIKI = ../../.. +PATH_COOJA_CORE_RELATIVE = /platform/cooja +PATH_MAKE = make +PATH_LINKER = ld +PATH_SHELL = sh +PATH_C_COMPILER = gcc +CMD_GREP_PROCESSES = grep '^PROCESS_THREAD([^,]*,[^,]*,[^)]*)' -o -d skip -D skip -H -r +REGEXP_PARSE_PROCESSES = ([^/]*.c):PROCESS_THREAD\\(([^,]*),[^,]*,[^)]*\\) +CMD_GREP_INTERFACES = grep '^SIM_INTERFACE([^,]*,' -o -d skip -D skip -H -r +REGEXP_PARSE_INTERFACES = ([^/]*.c):SIM_INTERFACE\\(([^,]*), +CMD_GREP_SENSORS = grep '^SENSORS_SENSOR([^,]*,' -o -d skip -D skip -H -r +REGEXP_PARSE_SENSORS = ([^/]*.c):SENSORS_SENSOR\\(([^,]*), +LINKER_ARGS_1 = --add-stdcall-alias /usr/lib/mingw/dllcrt2.o +LINKER_ARGS_2 = -L/usr/lib/mingw -lmingw32 -lmingwex -lmsvcrt +COMPILER_ARGS = -mno-cygwin -I'C:/Program Files/Java/jdk1.5.0_06/include' -I'C:/Program Files/Java/jdk1.5.0_06/include/win32' +CONTIKI_STANDARD_PROCESSES = sensors_process;etimer_process;tcpip_process;ether_process;uip_fw_process +CONTIKI_MAIN_TEMPLATE_FILENAME = code_main_template diff --git a/tools/cooja/config/log4j_config.xml b/tools/cooja/config/log4j_config.xml new file mode 100644 index 000000000..5a524e7a5 --- /dev/null +++ b/tools/cooja/config/log4j_config.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/cooja/examples/jni_test/build.xml b/tools/cooja/examples/jni_test/build.xml new file mode 100644 index 000000000..fc6c688bd --- /dev/null +++ b/tools/cooja/examples/jni_test/build.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + +Win32 cygwin users may try: + COMPILER_ARGS= -mno-cygwin -I....../jdk1.5.0/include -I....../jdk1.5.0/include/win32 + LINKER_ARGS_1 = --add-stdcall-alias /usr/lib/mingw/dllcrt2.o + LINKER_ARGS_2 = -L/usr/lib/mingw -lmingw32 -lmingwex -lmsvcrt + + Only for level 1, try the following compiler arguments: + COMPILER_ARGS= -mno-cygwin -I....../jdk1.5.0/include -I....../jdk1.5.0/include/win32 -Wl,--add-stdcall + + + + + +The COOJA Simulator - JNI Tests +There examples may help understand errors during compilation from inside COOJA. +For some examples; "ant help". + + +ant level1 + Runs JNI test level 1: + [compilation test] + Compiles level1.c to level1.library, using only c compiler. + Java class loads the library and calls a simple native function. + +ant level2 + Runs JNI test level 2: + [compilation test] + Compiles level2.c to level2.library, using both c compiler and linker. + Java class loads the library and calls a simple native function. + +ant level3 + Runs JNI test level 3: + [map file parsing test] + Compiles java + c. + The map file is parsed, and information about data+bss sections is outputted. + +ant level4 + Runs JNI test level 4: + [fetching reference var] + Calculates offset between relative (mapfile) and absolute memory. + A simple native function increases two counters (from both data and bss sections). + +ant level5 + Runs JNI test level 5: + [fetches and restores memory segments - the final test] + A simple native function increases two counters (from both data and bss sections). + The current memory (data+bss sections) is fetched and restored between function calls. + The counters should be restored with the memory! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/cooja/examples/jni_test/level1/Level1.java b/tools/cooja/examples/jni_test/level1/Level1.java new file mode 100644 index 000000000..b8027ca32 --- /dev/null +++ b/tools/cooja/examples/jni_test/level1/Level1.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2006, 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: Level1.java,v 1.1 2006/08/21 12:13:06 fros4943 Exp $ + */ + +import java.io.*; + +public class Level1 { + + static { + System.err.println("JAVA Level1 static> loading library now"); + System.load(new File("level1.library").getAbsolutePath()); + System.err.println("JAVA Level1 static> done loading library"); + } + + private native void test(); + + public Level1() { + System.err.println("JAVA Level1 constructor()> running native test function"); + test(); + } + + public static void main(String[] args) { + new Level1(); + } + +} diff --git a/tools/cooja/examples/jni_test/level1/level1.c b/tools/cooja/examples/jni_test/level1/level1.c new file mode 100644 index 000000000..37f035c9a --- /dev/null +++ b/tools/cooja/examples/jni_test/level1/level1.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006, 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: level1.c,v 1.1 2006/08/21 12:13:06 fros4943 Exp $ + */ + +#include +#include + +JNIEXPORT void JNICALL +Java_Level1_test(JNIEnv *env, jobject obj) +{ + fprintf(stderr, "C test()> Level 1 OK!\n"); + fflush(stderr); +} diff --git a/tools/cooja/examples/jni_test/level2/Level2.java b/tools/cooja/examples/jni_test/level2/Level2.java new file mode 100644 index 000000000..0b40ffb08 --- /dev/null +++ b/tools/cooja/examples/jni_test/level2/Level2.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2006, 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: Level2.java,v 1.1 2006/08/21 12:13:00 fros4943 Exp $ + */ + +import java.io.*; + +public class Level2 { + + static { + System.err.println("JAVA Level2 static> loading library now"); + System.load(new File("level2.library").getAbsolutePath()); + System.err.println("JAVA Level2 static> done loading library"); + } + + private native void test(); + + public Level2() { + System.err.println("JAVA Level2 constructor()> running native test function"); + test(); + } + + public static void main(String[] args) { + new Level2(); + } + +} diff --git a/tools/cooja/examples/jni_test/level2/level2.c b/tools/cooja/examples/jni_test/level2/level2.c new file mode 100644 index 000000000..7e8a6fe5b --- /dev/null +++ b/tools/cooja/examples/jni_test/level2/level2.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006, 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: level2.c,v 1.1 2006/08/21 12:13:00 fros4943 Exp $ + */ + +#include +#include + +JNIEXPORT void JNICALL +Java_Level2_test(JNIEnv *env, jobject obj) +{ + fprintf(stderr, "C test()> Level 2 OK!\n"); + fflush(stderr); +} diff --git a/tools/cooja/examples/jni_test/level3/Level3.java b/tools/cooja/examples/jni_test/level3/Level3.java new file mode 100644 index 000000000..12af4de7a --- /dev/null +++ b/tools/cooja/examples/jni_test/level3/Level3.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2006, 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: Level3.java,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + */ + +import java.io.*; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Level3 { + + final static private String bssSectionAddrRegExp = + "^.bss[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String bssSectionSizeRegExp = + "^.bss[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String dataSectionAddrRegExp = + "^.data[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String dataSectionSizeRegExp = + "^.data[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + + static { + System.load(new File("level3.library").getAbsolutePath()); + } + + private native void test(); + + public Level3() { + File mapFile = new File("level3.map"); + + // Check that map file exists + if (!mapFile.exists()) { + System.err.println("No map file could be loaded"); + System.exit(1); + } + + System.err.println("Loading map file"); + Vector mapContents = loadMapFile(mapFile); + + System.err.println("Parsing map file"); + int relDataSectionAddr = loadRelDataSectionAddr(mapContents); + int dataSectionSize = (int) loadDataSectionSize(mapContents); + int relBssSectionAddr = loadRelBssSectionAddr(mapContents); + int bssSectionSize = (int) loadBssSectionSize(mapContents); + + System.err.println("Found relative data section address: 0x" + Integer.toHexString(relDataSectionAddr)); + System.err.println("Found data section size: 0x" + Integer.toHexString(dataSectionSize)); + System.err.println("Found relative bss section address: 0x" + Integer.toHexString(relBssSectionAddr)); + System.err.println("Found bss section address: 0x" + Integer.toHexString(bssSectionSize)); + + test(); + } + + private static Vector loadMapFile(File mapFile) { + Vector mapContents = new Vector(); + + try { + BufferedReader in = + new BufferedReader( + new InputStreamReader( + new FileInputStream(mapFile))); + + while (in.ready()) + { + mapContents.add(in.readLine()); + } + } catch (FileNotFoundException e) { + System.err.println("File not found: " + e); + return null; + } catch (IOException e) { + System.err.println("IO error: " + e); + return null; + } + + return mapContents; + } + + private static int loadRelDataSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadDataSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadRelBssSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadBssSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static String getFirstMatchGroup(Vector lines, String regexp, int groupNr) { + Pattern pattern = Pattern.compile(regexp); + for (int i=0; i < lines.size(); i++) { + Matcher matcher = pattern.matcher(lines.elementAt(i)); + if (matcher.find()) { + return matcher.group(groupNr); + } + } + return null; + } + + + public static void main(String[] args) { + new Level3(); + } + +} diff --git a/tools/cooja/examples/jni_test/level3/level3.c b/tools/cooja/examples/jni_test/level3/level3.c new file mode 100644 index 000000000..aa2e73731 --- /dev/null +++ b/tools/cooja/examples/jni_test/level3/level3.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2006, 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: level3.c,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + */ + +#include +#include + +int initialized_counter=1; +int uninitialized_counter; + +JNIEXPORT void JNICALL +Java_Level3_test(JNIEnv *env, jobject obj) +{ + fprintf(stderr, "C test()> Level 3 OK!\n"); + fflush(stderr); +} diff --git a/tools/cooja/examples/jni_test/level4/Level4.java b/tools/cooja/examples/jni_test/level4/Level4.java new file mode 100644 index 000000000..bc34dfe3a --- /dev/null +++ b/tools/cooja/examples/jni_test/level4/Level4.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2006, 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: Level4.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +import java.io.*; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Level4 { + + static { + System.load(new File("level4.library").getAbsolutePath()); + } + + final static private String bssSectionAddrRegExp = + "^.bss[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String bssSectionSizeRegExp = + "^.bss[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String dataSectionAddrRegExp = + "^.data[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String dataSectionSizeRegExp = + "^.data[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String varAddressRegExpPrefix = + "^[ \t]*0x([0-9A-Fa-f]*)[ \t]*"; + final static private String varAddressRegExpSuffix = + "[ \t]*$"; + final static private String varNameRegExp = + "^[ \t]*(0x[0-9A-Fa-f]*)[ \t]*([^ ]*)[ \t]*$"; + final static private String varSizeRegExpPrefix = + "^"; + final static private String varSizeRegExpSuffix = + "[ \t]*(0x[0-9A-Fa-f]*)[ \t]*[^ ]*[ \t]*$"; + + private native void doCount(); + private native int getRefAddress(); + + public Level4() { + File mapFile = new File("level4.map"); + + // Check that map file exists + if (!mapFile.exists()) { + System.err.println("No map file could be loaded"); + System.exit(1); + } + + Vector mapContents = loadMapFile(mapFile); + + int relDataSectionAddr = loadRelDataSectionAddr(mapContents); + int dataSectionSize = (int) loadDataSectionSize(mapContents); + int relBssSectionAddr = loadRelBssSectionAddr(mapContents); + int bssSectionSize = (int) loadBssSectionSize(mapContents); + + int referenceAddress = getRefAddress(); + System.err.println("Reference address: 0x" + Integer.toHexString(referenceAddress)); + + int offsetRelToAbs = referenceAddress - getRelVarAddr(mapContents, "ref_var"); + System.err.println("Offset relative-absolute: 0x" + Integer.toHexString(offsetRelToAbs)); + + doCount(); + doCount(); + doCount(); + doCount(); + doCount(); + + System.err.println("Level 4 OK!"); + } + + private static int getRelVarAddr(Vector mapContents, String varName) { + String regExp = varAddressRegExpPrefix + varName + varAddressRegExpSuffix; + String retString = getFirstMatchGroup(mapContents, regExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static Vector loadMapFile(File mapFile) { + Vector mapContents = new Vector(); + + try { + BufferedReader in = + new BufferedReader( + new InputStreamReader( + new FileInputStream(mapFile))); + + while (in.ready()) + { + mapContents.add(in.readLine()); + } + } catch (FileNotFoundException e) { + System.err.println("File not found: " + e); + return null; + } catch (IOException e) { + System.err.println("IO error: " + e); + return null; + } + + return mapContents; + } + + private static int loadRelDataSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadDataSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadRelBssSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadBssSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static String getFirstMatchGroup(Vector lines, String regexp, int groupNr) { + Pattern pattern = Pattern.compile(regexp); + for (int i=0; i < lines.size(); i++) { + Matcher matcher = pattern.matcher(lines.elementAt(i)); + if (matcher.find()) { + return matcher.group(groupNr); + } + } + return null; + } + + + public static void main(String[] args) { + new Level4(); + } + +} diff --git a/tools/cooja/examples/jni_test/level4/level4.c b/tools/cooja/examples/jni_test/level4/level4.c new file mode 100644 index 000000000..27a95df81 --- /dev/null +++ b/tools/cooja/examples/jni_test/level4/level4.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006, 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: level4.c,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +#include +#include + +int ref_var; + +int initialized_counter=1; +int uninitialized_counter; + +JNIEXPORT void JNICALL +Java_Level4_doCount(JNIEnv *env, jobject obj) +{ + fprintf(stderr, ">> DATA_counter=\t%i\tBSS_counter=\t%i\n", initialized_counter++, uninitialized_counter++); + fflush(stderr); +} +JNIEXPORT jint JNICALL +Java_Level4_getRefAddress(JNIEnv *env, jobject obj) +{ + return (jint) &ref_var; +} diff --git a/tools/cooja/examples/jni_test/level5/Level5.java b/tools/cooja/examples/jni_test/level5/Level5.java new file mode 100644 index 000000000..69b9a0879 --- /dev/null +++ b/tools/cooja/examples/jni_test/level5/Level5.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2006, 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: Level5.java,v 1.1 2006/08/21 12:13:10 fros4943 Exp $ + */ + +import java.io.*; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Level5 { + + static { + System.load(new File("level5.library").getAbsolutePath()); + } + + final static private String bssSectionAddrRegExp = + "^.bss[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String bssSectionSizeRegExp = + "^.bss[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String dataSectionAddrRegExp = + "^.data[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String dataSectionSizeRegExp = + "^.data[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String varAddressRegExpPrefix = + "^[ \t]*0x([0-9A-Fa-f]*)[ \t]*"; + final static private String varAddressRegExpSuffix = + "[ \t]*$"; + final static private String varNameRegExp = + "^[ \t]*(0x[0-9A-Fa-f]*)[ \t]*([^ ]*)[ \t]*$"; + final static private String varSizeRegExpPrefix = + "^"; + final static private String varSizeRegExpSuffix = + "[ \t]*(0x[0-9A-Fa-f]*)[ \t]*[^ ]*[ \t]*$"; + + private native void doCount(); + private native int getRefAddress(); + private native byte[] getMemory(int start, int length); + private native void setMemory(int start, int length, byte[] mem); + + public Level5() { + File mapFile = new File("level5.map"); + + // Check that map file exists + if (!mapFile.exists()) { + System.err.println("No map file could be loaded"); + System.exit(1); + } + + Vector mapContents = loadMapFile(mapFile); + + int relDataSectionAddr = loadRelDataSectionAddr(mapContents); + int dataSectionSize = (int) loadDataSectionSize(mapContents); + int relBssSectionAddr = loadRelBssSectionAddr(mapContents); + int bssSectionSize = (int) loadBssSectionSize(mapContents); + + int referenceAddress = getRefAddress(); + + int offsetRelToAbs = referenceAddress - getRelVarAddr(mapContents, "ref_var"); + + System.err.println("\n\n--- RUNNING DO_COUNT 5 TIMES ---"); + doCount(); + doCount(); + doCount(); + doCount(); + doCount(); + System.err.println("\n\n--- FETCHING AND SAVING MEMORY ---"); + byte[] savedDataSection = getMemory(relDataSectionAddr + offsetRelToAbs, dataSectionSize); + byte[] savedBssSection = getMemory(relBssSectionAddr + offsetRelToAbs, bssSectionSize); + System.err.println("data section size:\t" + savedDataSection.length + " = " + "0x" + Integer.toHexString(savedDataSection.length)); + System.err.println("bss section size:\t" + savedBssSection.length + " = " + "0x" + Integer.toHexString(savedBssSection.length)); + + System.err.println("\n\n--- RUNNING DO_COUNT 3 TIMES ---"); + doCount(); + doCount(); + doCount(); + + System.err.println("\n\n--- RESTORING MEMORY: DATA ---"); + setMemory(relDataSectionAddr + offsetRelToAbs, dataSectionSize, savedDataSection); + + System.err.println("\n\n--- RUNNING DO_COUNT 3 TIMES ---"); + doCount(); + doCount(); + doCount(); + + System.err.println("\n\n--- RESTORING MEMORY: BSS ---"); + setMemory(relBssSectionAddr + offsetRelToAbs, bssSectionSize, savedBssSection); + + System.err.println("\n\n--- RUNNING DO_COUNT 3 TIMES ---"); + doCount(); + doCount(); + doCount(); + + System.err.println("Level 5 OK!"); + } + + private static int getRelVarAddr(Vector mapContents, String varName) { + String regExp = varAddressRegExpPrefix + varName + varAddressRegExpSuffix; + String retString = getFirstMatchGroup(mapContents, regExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static Vector loadMapFile(File mapFile) { + Vector mapContents = new Vector(); + + try { + BufferedReader in = + new BufferedReader( + new InputStreamReader( + new FileInputStream(mapFile))); + + while (in.ready()) + { + mapContents.add(in.readLine()); + } + } catch (FileNotFoundException e) { + System.err.println("File not found: " + e); + return null; + } catch (IOException e) { + System.err.println("IO error: " + e); + return null; + } + + return mapContents; + } + + private static int loadRelDataSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadDataSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadRelBssSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static int loadBssSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else return 0; + } + + private static String getFirstMatchGroup(Vector lines, String regexp, int groupNr) { + Pattern pattern = Pattern.compile(regexp); + for (int i=0; i < lines.size(); i++) { + Matcher matcher = pattern.matcher(lines.elementAt(i)); + if (matcher.find()) { + return matcher.group(groupNr); + } + } + return null; + } + + + + public static void main(String[] args) { + new Level5(); + } + +} diff --git a/tools/cooja/examples/jni_test/level5/level5.c b/tools/cooja/examples/jni_test/level5/level5.c new file mode 100644 index 000000000..7acd7a956 --- /dev/null +++ b/tools/cooja/examples/jni_test/level5/level5.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006, 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: level5.c,v 1.1 2006/08/21 12:13:10 fros4943 Exp $ + */ + +#include +#include +#include + +int ref_var; + +int initialized_counter=1; +int uninitialized_counter; + +JNIEXPORT void JNICALL +Java_Level5_doCount(JNIEnv *env, jobject obj) +{ + fprintf(stderr, ">> DATA_counter=\t%i\tBSS_counter=\t%i\n", initialized_counter++, uninitialized_counter++); + fflush(stderr); +} +JNIEXPORT jint JNICALL +Java_Level5_getRefAddress(JNIEnv *env, jobject obj) +{ + return (jint) &ref_var; +} + +JNIEXPORT jbyteArray JNICALL +Java_Level5_getMemory(JNIEnv *env, jobject obj, jint start, jint length) +{ + jbyteArray ret=(*env)->NewByteArray(env, length); + (*env)->SetByteArrayRegion(env, ret, 0, (size_t) length, (jbyte *) start); + + return (ret); +} + +JNIEXPORT void JNICALL +Java_Level5_setMemory(JNIEnv *env, jobject obj, jint start, jint length, jbyteArray mem_arr) +{ + jbyte *mem = (*env)->GetByteArrayElements(env, mem_arr, 0); + memcpy((void *) start, mem, length); + (*env)->ReleaseByteArrayElements(env, mem_arr, mem, 0); +} diff --git a/tools/cooja/examples/userplatform_debug/cooja.config b/tools/cooja/examples/userplatform_debug/cooja.config new file mode 100644 index 000000000..d59479393 --- /dev/null +++ b/tools/cooja/examples/userplatform_debug/cooja.config @@ -0,0 +1 @@ +se.sics.cooja.GUI.PLUGINS = + MoteDebugger diff --git a/tools/cooja/examples/userplatform_debug/java/MoteDebugger.java b/tools/cooja/examples/userplatform_debug/java/MoteDebugger.java new file mode 100644 index 000000000..6fa7becaa --- /dev/null +++ b/tools/cooja/examples/userplatform_debug/java/MoteDebugger.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2006, 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: MoteDebugger.java,v 1.1 2006/08/21 12:13:14 fros4943 Exp $ + */ + +import java.awt.event.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.*; +import org.apache.log4j.Logger; +import java.io.*; +import java.lang.management.*; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMote; +import se.sics.cooja.contikimote.ContikiMoteType; + +/** + * Mote debugger lets a user debug a mote using an external debugger. + * + * It executes the external program 'gdb' and sets up breakpoints + * at the entry of the tick function. + * + * The selected mote is then set to state active and ticked. + * + * OBSERVE! Experimental code. Not fully tested yet! + * + * @author Fredrik Osterlind + */ +@ClassDescription("Debug using GDB") +@VisPluginType(VisPluginType.MOTE_PLUGIN) +public class MoteDebugger extends VisPlugin {; + + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(MoteDebugger.class); + private ContikiMote moteToDebug; + + /** + * Creates a new VisDebug. + * @param mote Contiki mote to debug next tick + */ + public MoteDebugger(Mote mote) { + super("VisDebug (" + mote + ")"); + this.moteToDebug = (ContikiMote) mote; + + JButton debugButton = new JButton("Debug now"); + debugButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + logger.warn("OBSERVE! This is experimental code"); + + logger.info("Getting JVM pid"); + RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean(); + String runtimeName = rt.getName(); + int pid = 1; + + String pidExtraction = "^([0-9]*)[^$]*$"; + Pattern pattern = Pattern.compile(pidExtraction); + Matcher matcher = pattern.matcher(runtimeName); + if (!matcher.find()) { + logger.fatal("Could not determine pid, aborting"); + return; + } + + pid = Integer.parseInt(matcher.group(1)); + if (pid <= 0) { + logger.fatal("Pid seems to be strange, aborting. pid=" + pid); + return; + } + + logger.info("Extracted PID=" + pid); + + logger.info("Checking that source code file exists.."); + File sourceFile = new File("obj_cooja/" + moteToDebug.getType().getIdentifier() + ".c"); + if (!sourceFile.exists()) { + logger.fatal("Can't find source file: " + sourceFile); + return; + } + + logger.info("Source file ok: " + sourceFile); + + + logger.info("Determining function name to break at (entry of tick)"); + String libName = ((ContikiMoteType) moteToDebug.getType()).getLibraryClassName(); + + String functionName = "Java." + CoreComm.class.getPackage().getName() + ".corecomm." + libName + ".tick"; + functionName = functionName.replaceAll("\\.", "_"); + + logger.info("Function name is: " + functionName); + + logger.info("Creating temporary file .tmp with initial commands"); + File tmpFile = new File("obj_cooja/" + ".tmp"); + if (tmpFile.exists()) { + tmpFile.delete(); + } + try { + BufferedWriter tmpStream = new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream( + tmpFile))); + tmpStream.write("break " + functionName + "\n"); + tmpStream.write("cont\n"); + tmpStream.close(); + } catch (Exception ex) { + logger.fatal("Could not create temporary command file: " + tmpFile); + return; + } + + logger.info("Command file created ok: " + tmpFile.getName()); + + logger.info("Starting external GDB"); + logger.info("> GDB must be exited before control is returned to COOJA"); + logger.info("> Use command 'quit' followed by y to exit GDB"); + + Process gdbProcess = null; + try { + gdbProcess = Runtime.getRuntime().exec("xterm -e gdb" + + " -nw -quiet " + + " --pid=" + pid + + " -x " + "obj_cooja/" + tmpFile.getName() + ); + + logger.info("Sleeping 2500 ms while starting up GDB"); + Thread.sleep(2500); + logger.info("Ticking chosen mote now! (setting state to active)"); + moteToDebug.setState(Mote.STATE_ACTIVE); + moteToDebug.tick(GUI.currentSimulation.getSimulationTime()); + + gdbProcess.waitFor(); + } catch (Exception ex) { + logger.fatal("Exception while starting gdb, aborting"); + } + + logger.debug("GDB terminated with exit code: " + gdbProcess.exitValue()); + } + }); + + add(debugButton); + setSize(250, 80); + } + + public void closePlugin() { + } + +} diff --git a/tools/cooja/examples/userplatform_new_apps/app1.c b/tools/cooja/examples/userplatform_new_apps/app1.c new file mode 100644 index 000000000..17a1fedfa --- /dev/null +++ b/tools/cooja/examples/userplatform_new_apps/app1.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006, 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: app1.c,v 1.1 2006/08/21 12:13:09 fros4943 Exp $ + */ + +#include "contiki.h" +#include "sys/loader.h" + +#include + +#include "lib/list.h" +#include "lib/random.h" + +#include "net/uip.h" + +#include "lib/sensors.h" +#include "sys/log.h" +#include "dev/button-sensor.h" + + +PROCESS(dummy_process_1, "Dummy process 1"); + +PROCESS_THREAD(dummy_process_1, ev, data) +{ + PROCESS_BEGIN(); + + log_message("Dummy process 1 started", ""); + + while(1) { + PROCESS_WAIT_EVENT(); + log_message("Dummy process 1 received event", ""); + } + + PROCESS_END(); +} diff --git a/tools/cooja/examples/userplatform_new_apps/app2.c b/tools/cooja/examples/userplatform_new_apps/app2.c new file mode 100644 index 000000000..3ed5fd558 --- /dev/null +++ b/tools/cooja/examples/userplatform_new_apps/app2.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006, 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: app2.c,v 1.1 2006/08/21 12:13:09 fros4943 Exp $ + */ + +#include "contiki.h" +#include "sys/loader.h" + +#include + +#include "lib/list.h" +#include "lib/random.h" + +#include "net/uip.h" + +#include "lib/sensors.h" +#include "sys/log.h" +#include "dev/button-sensor.h" + + +PROCESS(dummy_process_2, "Dummy process 2"); + +PROCESS_THREAD(dummy_process_2, ev, data) +{ + PROCESS_BEGIN(); + + log_message("Dummy process 2 started", ""); + + while(1) { + PROCESS_WAIT_EVENT(); + log_message("Dummy process 2 received event", ""); + } + + PROCESS_END(); +} diff --git a/tools/cooja/examples/userplatform_new_apps/cooja.config b/tools/cooja/examples/userplatform_new_apps/cooja.config new file mode 100644 index 000000000..d2cf1d2e6 --- /dev/null +++ b/tools/cooja/examples/userplatform_new_apps/cooja.config @@ -0,0 +1 @@ +se.sics.cooja.contikimote.ContikiMoteType.C_SOURCES = + app1.c app2.c diff --git a/tools/cooja/examples/userplatform_new_interface/cooja.config b/tools/cooja/examples/userplatform_new_interface/cooja.config new file mode 100644 index 000000000..4cafbd62a --- /dev/null +++ b/tools/cooja/examples/userplatform_new_interface/cooja.config @@ -0,0 +1,2 @@ +se.sics.cooja.contikimote.ContikiMoteType.MOTE_INTERFACES = + DummyInterface +se.sics.cooja.contikimote.ContikiMoteType.C_SOURCES = + dummy_intf.c diff --git a/tools/cooja/examples/userplatform_new_interface/dummy_intf.c b/tools/cooja/examples/userplatform_new_interface/dummy_intf.c new file mode 100644 index 000000000..ebbfcfaac --- /dev/null +++ b/tools/cooja/examples/userplatform_new_interface/dummy_intf.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006, 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: dummy_intf.c,v 1.1 2006/08/21 12:13:13 fros4943 Exp $ + */ + +#include "dummy_intf.h" +#include "lib/simEnvChange.h" +#include + +const struct simInterface beep_interface; + +// COOJA variables (shared between Java and C) +char simDummyVar; + +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ + fprintf(stderr, "Core (C) dummy interface acts BEFORE mote tick\n"); +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ + fprintf(stderr, "Core (C) dummy interface acts AFTER mote tick\n"); +} +/*-----------------------------------------------------------------------------------*/ + +// Register this as an available interface +SIM_INTERFACE(dummy_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/tools/cooja/examples/userplatform_new_interface/dummy_intf.h b/tools/cooja/examples/userplatform_new_interface/dummy_intf.h new file mode 100644 index 000000000..d76594543 --- /dev/null +++ b/tools/cooja/examples/userplatform_new_interface/dummy_intf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006, 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: dummy_intf.h,v 1.1 2006/08/21 12:13:13 fros4943 Exp $ + */ + +#ifndef __DUMMY_INTF_H__ +#define __DUMMY_INTF_H__ + +// Interface needs to include something? + +#define DUMMY_NR_1 1 +#define DUMMY_NR_2 2 + +#endif /* __DUMMY_INTF_H__ */ diff --git a/tools/cooja/examples/userplatform_new_interface/java/DummyInterface.java b/tools/cooja/examples/userplatform_new_interface/java/DummyInterface.java new file mode 100644 index 000000000..24c71a636 --- /dev/null +++ b/tools/cooja/examples/userplatform_new_interface/java/DummyInterface.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2006, 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: DummyInterface.java,v 1.1 2006/08/21 12:13:13 fros4943 Exp $ + */ + +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; + +/** + * This is an example of how to implement new simulation interfaces. + * + * It needs read/write access to the following core variables: + *
    + *
  • char simDummyVar + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • dummy_interface + *
+ *

+ * This observable never changes. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Dummy Interface") +public class DummyInterface extends MoteInterface { + private static Logger logger = Logger.getLogger(DummyInterface.class); + + public DummyInterface(Mote mote) { + } + + public static String[] getCoreInterfaceDependencies() { + // I need the corresponding C dummy interface (in dummy_intf.c) + return new String[] { "dummy_interface" }; + } + + public void doActionsBeforeTick() { + logger.debug("Simulation (Java) dummy interface acts BEFORE mote tick"); + } + + public void doActionsAfterTick() { + logger.debug("Simulation (Java) dummy interface acts AFTER mote tick"); + } + + public JPanel getInterfaceVisualizer() { + return null; // No visualizer exists + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + public double energyConsumptionPerTick() { + return 0.0; // I never require any energy + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/examples/userplatform_new_plugin/cooja.config b/tools/cooja/examples/userplatform_new_plugin/cooja.config new file mode 100644 index 000000000..c75e2409f --- /dev/null +++ b/tools/cooja/examples/userplatform_new_plugin/cooja.config @@ -0,0 +1 @@ +se.sics.cooja.GUI.PLUGINS = + MyDummyPlugin diff --git a/tools/cooja/examples/userplatform_new_plugin/java/MyDummyPlugin.java b/tools/cooja/examples/userplatform_new_plugin/java/MyDummyPlugin.java new file mode 100644 index 000000000..b0f90eff4 --- /dev/null +++ b/tools/cooja/examples/userplatform_new_plugin/java/MyDummyPlugin.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006, 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: MyDummyPlugin.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * This is an simple example plugin. + * It is a simulation plugin, which means that it depends on a single simulation. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Dummy Plugin") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class MyDummyPlugin extends VisPlugin { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(MyDummyPlugin.class); + private Simulation mySimulation; + private Observer tickObserver; + + /** + * Creates a new dummy plugin. + * + * @param simulationToVisualize Simulation to visualize + */ + public MyDummyPlugin(Simulation simulationToVisualize) { + super("This is my title!"); + mySimulation = simulationToVisualize; + + // Create and add a button + JButton button = new JButton("dummy button"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + logger.info("You just pressed my button"); + } + }); + add(button); + + // Register as tickobserver + mySimulation.addTickObserver(tickObserver = new Observer() { + public void update(Observable obs, Object obj) { + logger.info("Another tick loop completed - simulation time is now:\t" + mySimulation.getSimulationTime()); + } + }); + + setSize(300,100); // Set an initial size of this plugin + + // Tries to select this plugin + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + public void closePlugin() { + mySimulation.deleteTickObserver(tickObserver); + } + +} diff --git a/tools/cooja/examples/userplatform_new_radiomedium/cooja.config b/tools/cooja/examples/userplatform_new_radiomedium/cooja.config new file mode 100644 index 000000000..9eb9aa4e8 --- /dev/null +++ b/tools/cooja/examples/userplatform_new_radiomedium/cooja.config @@ -0,0 +1 @@ +se.sics.cooja.GUI.RADIOMEDIUMS = + DummyRadioMedium diff --git a/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java b/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java new file mode 100644 index 000000000..bd16d69ca --- /dev/null +++ b/tools/cooja/examples/userplatform_new_radiomedium/java/DummyRadioMedium.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2006, 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: DummyRadioMedium.java,v 1.1 2006/08/21 12:13:00 fros4943 Exp $ + */ + +import java.util.Collection; +import java.util.Observer; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.*; + +/** + * Dummy radio medium. No data is ever transferred through this medium. + * It also outputs some dummy debug messages during usage. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Dummy Radio Medium") +public class DummyRadioMedium extends RadioMedium { + private static Logger logger = Logger.getLogger(GUI.class); + + public void registerMote(Mote mote, Simulation sim) { + // Do nothing + logger.debug("I'm a dummy. Nothing will be registered by me."); + } + + public void unregisterMote(Mote mote, Simulation sim) { + // Do nothing + } + + public void registerRadioInterface(Radio radio, Position position, Simulation sim) { + // Do nothing + logger.debug("I'm a dummy. Nothing will be registered by me."); + } + + public void unregisterRadioInterface(Radio radio, Simulation sim) { + // Do nothing + } + + public void addRadioMediumObserver(Observer observer) { + // Do nothing + logger.debug("I'm a dummy. I will never change."); + } + + public void deleteRadioMediumObserver(Observer observer) { + // Do nothing + logger.debug("I'm a dummy. I will never change."); + } + + public RadioConnection[] getLastTickConnections() { + return null; + } + + public void setConnectionLogger(ConnectionLogger connection) { + // Do nothing + } + + public Collection getConfigXML() { + return null; + } + + public boolean setConfigXML(Collection configXML) { + return true; + } + +} diff --git a/tools/cooja/examples/userplatform_uaodv/cooja.config b/tools/cooja/examples/userplatform_uaodv/cooja.config new file mode 100644 index 000000000..21435db17 --- /dev/null +++ b/tools/cooja/examples/userplatform_uaodv/cooja.config @@ -0,0 +1,3 @@ +se.sics.cooja.GUI.PLUGINS = + VisUAODV UAODVControl +se.sics.cooja.contikimote.ContikiMoteType.C_SOURCES = + uaodv-example.c + diff --git a/tools/cooja/examples/userplatform_uaodv/java/UAODVControl.java b/tools/cooja/examples/userplatform_uaodv/java/UAODVControl.java new file mode 100644 index 000000000..ba9c7a2b6 --- /dev/null +++ b/tools/cooja/examples/userplatform_uaodv/java/UAODVControl.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006, 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: UAODVControl.java,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + */ + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.interfaces.ContikiRS232; +import se.sics.cooja.interfaces.*; + +/** + * @author Fredrik Osterlind + */ +@ClassDescription("uAODV Control") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class UAODVControl extends VisPlugin { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(UAODVControl.class); + private Simulation mySimulation; + private JComboBox sourceComboBox; + private JComboBox destComboBox; + + /** + * @param simulationToVisualize Current simulation + */ + public UAODVControl(Simulation simulationToVisualize) { + super("uAODV Control (uses RS232)"); + mySimulation = simulationToVisualize; + + Container mainPane = this.getContentPane(); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JLabel label; + JPanel smallPane; + + // Create available nodes list + Vector nodeDescs = new Vector(); + for (int i=0; i < mySimulation.getMotesCount(); i++) { + Mote currentMote = mySimulation.getMote(i); + nodeDescs.add("ID=" + + currentMote.getInterfaces().getMoteID().getMoteID() + + ", IP=" + + currentMote.getInterfaces().getIPAddress().getIPString()); + } + + // Create source combo box + label = new JLabel("Select RREQ source"); + + sourceComboBox = new JComboBox(nodeDescs); + if (sourceComboBox.getItemCount() < 1) { + logger.warn("No nodes available"); + } else + sourceComboBox.setSelectedIndex(0); + label.setLabelFor(sourceComboBox); + + smallPane = new JPanel(); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(sourceComboBox); + + mainPane.add(smallPane); + + // Create destination combo box + label = new JLabel("Select RREQ destination"); + + destComboBox = new JComboBox(nodeDescs); + if (destComboBox.getItemCount() < 1) { + logger.warn("No nodes available"); + } else + destComboBox.setSelectedIndex(0); + label.setLabelFor(destComboBox); + + smallPane = new JPanel(); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(destComboBox); + + mainPane.add(smallPane); + + // Add set button + smallPane = new JPanel(new BorderLayout()); + JButton setDestinationButton = new JButton("Set IP and send RREQ"); + setDestinationButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + logger.debug("Sending RS232 command now"); + Mote sourceMote = mySimulation.getMote(sourceComboBox.getSelectedIndex()); + Mote destMote = mySimulation.getMote(destComboBox.getSelectedIndex()); + if (sourceMote == null || destMote == null) { + logger.error("Error in mote selection"); + return; + } + + // Get destination IP + IPAddress destIP = destMote.getInterfaces().getIPAddress(); + if (destIP == null) { + logger.error("Error when fetching destination IP"); + return; + } + + // Set destination and start sending by using RS232 + ContikiRS232 rs232 = sourceMote.getInterfaces().getInterfaceOfType(ContikiRS232.class); + if (rs232 == null) { + logger.error("RS232 interface is null!"); + return; + } + + rs232.sendSerialMessage("SENDTO>" + destIP.getIPString()); + } + }); + smallPane.add(BorderLayout.EAST, setDestinationButton); + mainPane.add(smallPane); + + + pack(); + + // Tries to select this plugin + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + public void closePlugin() { + } + +} diff --git a/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java b/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java new file mode 100644 index 000000000..2e0c30ee0 --- /dev/null +++ b/tools/cooja/examples/userplatform_uaodv/java/VisUAODV.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2006, 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: VisUAODV.java,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + */ + +import java.awt.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.plugins.*; + +/** + * VisUAODV is a 2D graphical visualizer for simulations with motes running + * UAODV protocol. + * RREQs are painted red, and RREPs green. + * The rest of sent data is painted black. + * + * Interactions with motes are available via registered mote plugins. + * + * @author Fredrik Osterlind + */ +@ClassDescription("uAODV Visualizer") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class VisUAODV extends VisTraffic { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(VisUAODV.class); + + /** + * Creates a new VisUAODV visualizer. + * @param simulationToVisualize Simulation to visualize + */ + public VisUAODV(Simulation simulationToVisualize) { + super(simulationToVisualize); + setTitle("uAODV Visualizer"); + } + + protected void paintConnection(RadioConnection connection, Graphics g2d) { + Point sourcePixelPosition = transformPositionToPixel(connection.getSourcePosition()); + for (Position destPosition: connection.getDestinationPositons()) { + Point destPixelPosition = transformPositionToPixel(destPosition); + g2d.setColor(getColorOf(connection)); + + if (isRouteReply(connection.getSourceData())) { + ((Graphics2D) g2d).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); + } + + g2d.drawLine(sourcePixelPosition.x, sourcePixelPosition.y, + destPixelPosition.x, destPixelPosition.y); + + int hopCount = getHopCount(connection.getSourceData()); + if (hopCount >= 0) + g2d.drawString("" + hopCount, sourcePixelPosition.x, sourcePixelPosition.y); + } + } + + protected Color getColorOf(RadioConnection conn) { + if (isRouteRequest(conn.getSourceData())) + return Color.RED; + else if (isRouteReply(conn.getSourceData())) + return Color.GREEN; + else + return Color.BLACK; + } + + private boolean isRouteRequest(byte[] data) { + if (data.length > 28) + return data[28] == 1; + return false; + } + private boolean isRouteReply(byte[] data) { + if (data.length > 28) + return data[28] == 2; + return false; + } + private int getHopCount(byte[] data) { + if (data.length > 31) + return (int) data[31]; + return -1; + } + +} diff --git a/tools/cooja/examples/userplatform_uaodv/uaodv-example.c b/tools/cooja/examples/userplatform_uaodv/uaodv-example.c new file mode 100644 index 000000000..499af4dfb --- /dev/null +++ b/tools/cooja/examples/userplatform_uaodv/uaodv-example.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006, 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: uaodv-example.c,v 1.1 2006/08/21 12:13:12 fros4943 Exp $ + */ + +#include "contiki-net.h" +#include "net/uaodv.h" +#include "net/uaodv-rt.h" + +#include "lib/sensors.h" +#include "sys/log.h" + +#include "dev/button-sensor.h" +#include "dev/serial.h" + +/*---------------------------------------------------------------------------*/ +PROCESS(uaodv_example_process, "uAODV example"); + +AUTOSTART_PROCESSES(&uaodv_process, &uaodv_example_process); + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(uaodv_example_process, ev, data) +{ + static uip_ipaddr_t addr; + + PROCESS_BEGIN(); + + int ipA, ipB, ipC, ipD; + char buf[200]; + + button_sensor.activate(); + serial_init(); + + while(1) { + PROCESS_WAIT_EVENT(); + if(ev == sensors_event && data == &button_sensor && button_sensor.value(0)) { + uip_ipaddr(addr, 10,10,0,1); + log_message("Sending RREQ to (static) 10.10.0.1\n", ""); + uaodv_request_route_to(addr); + } else if(ev == serial_event_message) { + sscanf(data, "SENDTO>%d.%d.%d.%d", &ipA, &ipB, &ipC, &ipD); + sprintf(buf, "Sending RREQ to %d.%d.%d.%d .. \n", ipA, ipB, ipC, ipD); + log_message(buf, ""); + uip_ipaddr(&addr, ipA, ipB, ipC, ipD); + uaodv_request_route_to(&addr); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/tools/cooja/java/se/sics/cooja/ClassDescription.java b/tools/cooja/java/se/sics/cooja/ClassDescription.java new file mode 100644 index 000000000..7203e00af --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/ClassDescription.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006, 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: ClassDescription.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation type to describe a class. + * Description may be shown in menues etc. + * + * @author Fredrik Osterlind + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +public @interface ClassDescription { + String value(); +} + diff --git a/tools/cooja/java/se/sics/cooja/ConnectionLogger.java b/tools/cooja/java/se/sics/cooja/ConnectionLogger.java new file mode 100644 index 000000000..236edf9ff --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/ConnectionLogger.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2006, 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: ConnectionLogger.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.io.File; +import java.io.FileOutputStream; +import org.apache.log4j.Logger; + +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.plugins.SimControl; + +/** + * ConnectionLogger is a simple connection information outputter. All + * connections given via the method logConnection will be written to either + * default Log4J info stream, a log file or both. + * + * Log files have the following structure (spaces are tabs): SRC_POS [src_x] + * [src_y] [src_z] SRC_DATA [sent data bytes] DEST_POS [dest_x] [dest_y] + * [dest_z] DEST_DATA [received data bytes] [newline] + * + * @see RadioConnection + * @see RadioMedium + * + * @author Fredrik Osterlind + */ +public class ConnectionLogger { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(SimControl.class); + + private static int LOG_TO_FILE = 1; + private static int LOG_TO_LOG4J = 2; + private static int LOG_TO_FILE_AND_LOG4J = 3; + + private int myType; + private File myFile; + + /** + * Creates a new connection logger outputting to Log4J info stream. + */ + public ConnectionLogger() { + myType = LOG_TO_LOG4J; + } + + /** + * Creates a new connection logger outputting to a file. + * + * @param logFile + * Log file + */ + public ConnectionLogger(File logFile) { + myType = LOG_TO_FILE; + myFile = logFile; + if (myFile.exists()) + myFile.delete(); + } + + /** + * Output given connection to either Log4J info stream or a file. + * + * @param conn + * Connection to output + */ + public void logConnection(RadioConnection conn) { + + if (myType == LOG_TO_LOG4J || myType == LOG_TO_FILE_AND_LOG4J) { + if (conn.getDestinationPositons() != null + && conn.getDestinationPositons().length > 0) + for (Position destPos : conn.getDestinationPositons()) { + logger.info("RADIODATA from " + conn.getSourcePosition() + " to " + + destPos + "\tsize:" + conn.getSourceData().length); + } + else + logger.info("RADIODATA from " + conn.getSourcePosition() + " to " + + "[NOWHERE]" + "\tsize:" + conn.getSourceData().length); + } + if (myType == LOG_TO_FILE || myType == LOG_TO_FILE_AND_LOG4J) { + + try { + FileOutputStream out = new FileOutputStream(myFile, true); + + if (conn.getDestinationPositons() != null + && conn.getDestinationPositons().length > 0) { + for (int i = 0; i < conn.getDestinationPositons().length; i++) { + // Source pos + out.write("SRC_POS\t".getBytes()); + Position pos = conn.getSourcePosition(); + out.write(Double.toString(pos.getXCoordinate()).getBytes()); + out.write("\t".getBytes()); + out.write(Double.toString(pos.getYCoordinate()).getBytes()); + out.write("\t".getBytes()); + out.write(Double.toString(pos.getZCoordinate()).getBytes()); + out.write("\t".getBytes()); + + // Source data + out.write("SRC_DATA\t".getBytes()); + for (byte b : conn.getSourceData()) + out.write(Integer.toHexString((int) b).getBytes()); + out.write("\t".getBytes()); + + // Destination pos + out.write("DEST_POS\t".getBytes()); + pos = conn.getDestinationPositons()[i]; + out.write(Double.toString(pos.getXCoordinate()).getBytes()); + out.write("\t".getBytes()); + out.write(Double.toString(pos.getYCoordinate()).getBytes()); + out.write("\t".getBytes()); + out.write(Double.toString(pos.getZCoordinate()).getBytes()); + out.write("\t".getBytes()); + + // Source data + out.write("DEST_DATA\t".getBytes()); + for (byte b : conn.getDestinationData()[i]) + out.write(Integer.toHexString((int) b).getBytes()); + out.write("\t".getBytes()); + + out.write("\n".getBytes()); + } + + } else { + // Source pos + out.write("SRC_POS\t".getBytes()); + Position pos = conn.getSourcePosition(); + out.write(Double.toString(pos.getXCoordinate()).getBytes()); + out.write("\t".getBytes()); + out.write(Double.toString(pos.getYCoordinate()).getBytes()); + out.write("\t".getBytes()); + out.write(Double.toString(pos.getZCoordinate()).getBytes()); + out.write("\t".getBytes()); + + // Source data + out.write("SRC_DATA\t".getBytes()); + for (byte b : conn.getSourceData()) + out.write(Integer.toHexString((int) b).getBytes()); + + out.write("\n".getBytes()); + } + out.close(); + + } catch (Exception e) { + logger.fatal("Exception while logging to file: " + e); + myType = LOG_TO_LOG4J; + return; + } + } + + } +} diff --git a/tools/cooja/java/se/sics/cooja/CoreComm.java b/tools/cooja/java/se/sics/cooja/CoreComm.java new file mode 100644 index 000000000..2b82cc0c7 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/CoreComm.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2006, 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: CoreComm.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.io.File; +import se.sics.cooja.corecomm.*; + +/** + * The package corecomm's purpose is communicating with the simulation core + * using Java Native Interface (JNI). Each implementing class (named Lib[1-MAX]), + * loads a shared library which belongs to one mote type. The reason for this + * somewhat strange design is that once loaded, a native library cannot be unloaded + * in Java (yet). Therefore if we wish to load several libraries, the names and associated + * native functions must have unique names. And those names are defined via the calling class in JNI. + * For example, the native tick function in class Lib1 is named contiki_javasim_corecomm_Lib1_tick. + * When creating a new mote type, the main contiki source file is generated with function names + * compatible with the next available corecomm. + * This also implies that even if a mote type is deleted, a new one cannot be created without + * restarting the JVM and thus the entire simulation. + * + * Each implemented CoreComm class needs read access to the following core variables: + *

    + *
  • referenceVar + *
+ * and the following native functions: + *
    + *
  • init() + *
  • tick() + *
  • getReferenceAbsAddr() + *
  • getMemory(int start, int length) + *
  • setMemory(int start, int length, byte[] mem) + *
+ + * @author Fredrik Osterlind + */ +public abstract class CoreComm { + /** + * Maximum supported core communicators in a simulation. + */ + private final static int MAX_LIBRARIES = 8; + + // Static pointers to current libraries + private final static CoreComm[] coreComms = new CoreComm[MAX_LIBRARIES]; + private final static File[] coreCommFiles = new File[MAX_LIBRARIES]; + + /** + * Has any library been loaded? Since libraries can't be unloaded + * the entire simulator may have to be restarted. + * + * @return True if any library has been loaded this session + */ + public static boolean hasLibraryBeenLoaded() { + for (int i=0; i < coreComms.length; i++) + if (coreComms[i] != null) + return true; + return false; + } + + /** + * Has given library file already been loaded during this session? + * A loaded library can be removed, but not unloaded + * during one session. And a new library file, named + * the same as an earlier loaded and removed file, + * can't be loaded either. + * + * @param libraryFile Library file + * @return True if a library has already been loaded from the given file's filename + */ + public static boolean hasLibraryFileBeenLoaded(File libraryFile) { + for (File libFile: coreCommFiles) + if (libFile != null && libFile.getName().equals(libraryFile.getName())) + return true; + return false; + } + + /** + * Get the class name of next free core communicator class. + * If null is returned, no classes are available. + * + * @return Class name + */ + public static String getAvailableClassName() { + if (coreComms[0] == null) + return "Lib1"; + if (coreComms[1] == null) + return "Lib2"; + if (coreComms[2] == null) + return "Lib3"; + if (coreComms[3] == null) + return "Lib4"; + if (coreComms[4] == null) + return "Lib5"; + if (coreComms[5] == null) + return "Lib6"; + if (coreComms[6] == null) + return "Lib7"; + if (coreComms[7] == null) + return "Lib8"; + + return null; + } + + /** + * Create and return an instance of the core communicator identified + * by className. This core communicator will load the native library libFile. + * + * @param className Class name of core communicator + * @param libFile Native library file + * @return Core Communicator + */ + public static CoreComm createCoreComm(String className, File libFile) { + if (className.equals("Lib1") && coreComms[0] == null) { + coreComms[0] = new Lib1(libFile); + coreCommFiles[0] = libFile; + return coreComms[0]; + } + if (className.equals("Lib2") && coreComms[1] == null) { + coreComms[1] = new Lib2(libFile); + coreCommFiles[1] = libFile; + return coreComms[1]; + } + if (className.equals("Lib3") && coreComms[2] == null) { + coreComms[2] = new Lib3(libFile); + coreCommFiles[2] = libFile; + return coreComms[2]; + } + if (className.equals("Lib4") && coreComms[3] == null) { + coreComms[3] = new Lib4(libFile); + coreCommFiles[3] = libFile; + return coreComms[3]; + } + if (className.equals("Lib5") && coreComms[4] == null) { + coreComms[4] = new Lib5(libFile); + coreCommFiles[4] = libFile; + return coreComms[4]; + } + if (className.equals("Lib6") && coreComms[5] == null) { + coreComms[5] = new Lib6(libFile); + coreCommFiles[5] = libFile; + return coreComms[5]; + } + if (className.equals("Lib7") && coreComms[6] == null) { + coreComms[6] = new Lib7(libFile); + coreCommFiles[6] = libFile; + return coreComms[6]; + } + if (className.equals("Lib8") && coreComms[7] == null) { + coreComms[7] = new Lib8(libFile); + coreCommFiles[7] = libFile; + return coreComms[7]; + } + + return null; + } + + + /** + * Ticks a mote once. This should not be used directly, + * but instead via Mote.tick(). + */ + public abstract void tick(); + + /** + * Initializes a mote by running a startup script in the core. + * (Should only by run once, at the same time as the library is loaded) + */ + protected abstract void init(); + + /** + * Returns absolute memory location of the core variable + * referenceVar. Used to get offset between relative and absolute + * memory addresses. + * + * @return Absolute memory address + */ + public abstract int getReferenceAbsAddr(); + + /** + * Returns a memory segment identified by start and length. + * + * @param start Start address of segment + * @param length Length of segment + * @return Memory segment + */ + public abstract byte[] getMemory(int start, int length); + + /** + * Overwrites a memory segment identified by start and length. + * + * @param start Start address of segment + * @param length Length of segment + * @param mem Data to fill memory segment + */ + public abstract void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/DirectoryClassLoader.java b/tools/cooja/java/se/sics/cooja/DirectoryClassLoader.java new file mode 100644 index 000000000..f9e5bbc10 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/DirectoryClassLoader.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2006, 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: DirectoryClassLoader.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.io.*; +import org.apache.log4j.Logger; + +/** + * Loads an external file from the given directory as a Java class. + * + * @author Fredrik Osterlind + */ +public class DirectoryClassLoader extends ClassLoader { + private static Logger logger = Logger.getLogger(DirectoryClassLoader.class); + private File directory; + + /** + * Creates a new class loader reading from given directory. + * + * @param directory + * Directory + */ + public DirectoryClassLoader(File directory) { + super(); + this.directory = directory; + } + + /** + * Creates a new class loader reading from given directory, with the given + * class loader as parent class loader. + * + * @param parent + * Parent class loader + * @param directory + * Directory + */ + public DirectoryClassLoader(ClassLoader parent, File directory) { + super(parent); + this.directory = directory; + } + + public Class findClass(String name) throws ClassNotFoundException { + String fullFilePath = directory.getPath() + File.separatorChar + name + + ".class"; + + // Read external file + //logger.info("Directory class loader reading file: " + fullFilePath); + byte[] classData = loadClassData(fullFilePath); + if (classData == null) { + throw new ClassNotFoundException(); + } + + // Create class + return defineClass(name, classData, 0, classData.length); + } + + private byte[] loadClassData(String name) { + // Support for fill class names in configuration file + // TODO Quick-fix (may contain bugs) + name = name.replace('.', File.separatorChar); + name = name.replace(File.separatorChar + "class", ".class"); + + // Open file for read access + File classFile = new File(name); + InputStream inputStream = null; + if (!classFile.exists()) { + //logger.fatal("File " + classFile + " does not exist!"); + return null; + } + + try { + inputStream = new FileInputStream(classFile); + + if (inputStream == null) { + logger.fatal("File input stream is null!"); + return null; + } + } catch (FileNotFoundException e) { + logger.fatal("Could not open file (not found?)!"); + return null; + } + long fileSize = classFile.length(); + + if (fileSize > Integer.MAX_VALUE) { + logger.fatal("Class file is too large"); + return null; + } + + // Read class data + byte[] classData = new byte[(int) fileSize]; + int offset = 0; + int numRead = 0; + try { + while (offset < classData.length + && (numRead = inputStream.read(classData, offset, classData.length + - offset)) >= 0) { + offset += numRead; + } + + inputStream.close(); + } catch (IOException e) { + logger.fatal("Error when reading class file"); + return null; + } + + // Ensure all the bytes have been read in + if (offset < classData.length) { + logger.fatal("Could not read entire class file"); + return null; + } + + return classData; + } +} diff --git a/tools/cooja/java/se/sics/cooja/GUI.java b/tools/cooja/java/se/sics/cooja/GUI.java new file mode 100644 index 000000000..96e41f269 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/GUI.java @@ -0,0 +1,1612 @@ +/* + * Copyright (c) 2006, 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: GUI.java,v 1.1 2006/08/21 12:12:51 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import javax.swing.*; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; +import javax.swing.filechooser.FileFilter; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.DOMConfigurator; + +import se.sics.cooja.dialogs.*; +import se.sics.cooja.plugins.*; + +/** + * Main file of COOJA Simulator. + * + * @author Fredrik Osterlind + */ +public class GUI extends JDesktopPane { + + /** + * External tools default Win32 settings filename. + */ + public static final String EXTERNAL_TOOLS_WIN32_SETTINGS_FILENAME = "/external_tools_win32.config"; + + /** + * External tools default Linux/Unix settings filename. + */ + public static final String EXTERNAL_TOOLS_LINUX_SETTINGS_FILENAME = "/external_tools_linux.config"; + + /** + * External tools user settings filename. + */ + public static final String EXTERNAL_TOOLS_USER_SETTINGS_FILENAME = "external_tools_user.config"; + + /** + * Logger settings filename. + */ + public static final String LOG_CONFIG_FILE = "log4j_config.xml"; + + /** + * Default platform configuration filename. + */ + public static final String PLATFORM_DEFAULT_CONFIG_FILENAME = "cooja_default.config"; + + /** + * User platform configuration filename. + */ + public static final String PLATFORM_CONFIG_FILENAME = "cooja.config"; + + /** + * File filter only showing saved simulations files (*.csc). + */ + public static final FileFilter SAVED_SIMULATIONS_FILES = new FileFilter() { + public boolean accept(File file) { + if (file.isDirectory()) + return true; + + if (file.getName().endsWith(".csc")) + return true; + + return false; + } + + public String getDescription() { + return "COOJA Configuration files"; + } + + public String toString() { + return ".csc"; + } + }; + + /** + * Main frame for current GUI + */ + public static JFrame frame; + + /** + * Current active simulation + */ + public static Simulation currentSimulation = null; + + /** + * Current active GUI + */ + public static GUI currentGUI = null; + + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(GUI.class); + + // External tools setting names + private static Properties currentExternalToolsSettings; + private static final String externalToolsSettingNames[] = new String[]{ + "PATH_CONTIKI", "PATH_COOJA_CORE_RELATIVE", "PATH_MAKE", "PATH_SHELL", + "PATH_C_COMPILER", "COMPILER_ARGS", "PATH_LINKER", "LINKER_ARGS_1", + "LINKER_ARGS_2", "CONTIKI_STANDARD_PROCESSES", "CMD_GREP_PROCESSES", + "REGEXP_PARSE_PROCESSES", "CMD_GREP_INTERFACES", + "REGEXP_PARSE_INTERFACES", "CMD_GREP_SENSORS", "REGEXP_PARSE_SENSORS", + "CONTIKI_MAIN_TEMPLATE_FILENAME"}; + + private static final int FRAME_NEW_OFFSET = 30; + private static final int FRAME_STANDARD_WIDTH = 150; + private static final int FRAME_STANDARD_HEIGHT = 300; + + private GUI myGUI; + private Mote selectedMote = null; + private GUIEventHandler guiEventHandler = new GUIEventHandler(); + + private JMenu menuPlugins, menuMoteTypeClasses, menuMoteTypes; + private JPopupMenu menuMotePlugins; + + // Platform configuration variables + // Maintained via method reparsePlatformConfig() + private PlatformConfig platformConfig; + private Vector currentUserPlatforms = new Vector(); + private ClassLoader userPlatformClassLoader; + + private Vector> moteTypeClasses = new Vector>(); + private Vector> pluginClasses = new Vector>(); + private Vector> pluginClassesTemporary = new Vector>(); + private Vector> radioMediumClasses = new Vector>(); + private Vector> ipDistributorClasses = new Vector>(); + private Vector> positionerClasses = new Vector>(); + + /** + * Creates a new COOJA Simulator GUI. + */ + public GUI() { + myGUI = this; + currentGUI = this; + + // Set drag frames to outlines only (faster) + setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + + // Add menu bar + frame.setJMenuBar(createMenuBar()); + + frame.setSize(700, 700); + + frame.addWindowListener(guiEventHandler); + + // Load default and overwrite with user settings (if any) + loadExternalToolsDefaultSettings(); + loadExternalToolsUserSettings(); + + // If simulator was quick-started (via make), double-check that the + // contiki-paths are equal + if (System.getProperty("PATH_CONTIKI") != null) { + String makefilePath = null; + String userSettingsPath = null; + try { + makefilePath = new File(System.getProperty("PATH_CONTIKI")) + .getCanonicalPath(); + userSettingsPath = new File(getExternalToolsSetting("PATH_CONTIKI")) + .getCanonicalPath(); + } catch (Exception e) { + } + + if (makefilePath == null || userSettingsPath == null + || !makefilePath.equals(userSettingsPath)) { + // Show dialog asking user which path to use + Object[] options = {"Use new temporarily", "Keep old (unsafe)"}; + String question = "COOJA has detected a possible error in your current Contiki 2.x path!\n" + + "Maybe COOJA was started via a make script which defined a newer path.\n" + + "Old user settings: " + + getExternalToolsSetting("PATH_CONTIKI") + + "\n" + + "New makefile path: " + + System.getProperty("PATH_CONTIKI") + + "\n"; + + String title = "Possible error in Contiki 2.x path"; + + int answer = JOptionPane.showOptionDialog(this, question, title, + JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, + options, options[0]); + + if (answer == JOptionPane.YES_OPTION) { + setExternalToolsSetting("PATH_CONTIKI", System + .getProperty("PATH_CONTIKI")); + logger.info("New Contiki path settings are not saved"); + } + } + } + + // Load extendable parts (using current platform config) + reparsePlatformConfig(); + } + + private JMenuBar createMenuBar() { + JMenuBar menuBar = new JMenuBar(); + JMenu menu; + JMenuItem menuItem; + + // File menu + menu = new JMenu("File"); + menu.setMnemonic(KeyEvent.VK_F); + menuBar.add(menu); + + menuItem = new JMenuItem("New simulation"); + menuItem.setMnemonic(KeyEvent.VK_N); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, + ActionEvent.CTRL_MASK)); + menuItem.setActionCommand("new sim"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + menuItem = new JMenuItem("Close simulation"); + menuItem.setMnemonic(KeyEvent.VK_C); + menuItem.setActionCommand("close sim"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + menuItem = new JMenuItem("Load simulation"); + menuItem.setMnemonic(KeyEvent.VK_L); + menuItem.setActionCommand("load sim"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + menuItem = new JMenuItem("Save simulation"); + menuItem.setMnemonic(KeyEvent.VK_S); + menuItem.setActionCommand("save sim"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + menu.addSeparator(); + + menuItem = new JMenuItem("Quit"); + menuItem.setMnemonic(KeyEvent.VK_Q); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, + ActionEvent.CTRL_MASK)); + menuItem.setActionCommand("quit"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + // Simulation menu + menu = new JMenu("Simulation"); + menu.setMnemonic(KeyEvent.VK_S); + menuBar.add(menu); + + menuItem = new JMenuItem("Open Control"); + menuItem.setMnemonic(KeyEvent.VK_C); + menuItem.setActionCommand("start plugin"); + menuItem.putClientProperty("class", SimControl.class); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + menuItem = new JMenuItem("Information"); + menuItem.setMnemonic(KeyEvent.VK_I); + menuItem.setActionCommand("start plugin"); + menuItem.putClientProperty("class", SimInformation.class); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + // Mote type menu + menu = new JMenu("Mote Types"); + menu.setMnemonic(KeyEvent.VK_T); + menuBar.add(menu); + + // Mote type classes sub menu + menuMoteTypeClasses = new JMenu("Create mote type"); + menuMoteTypeClasses.setMnemonic(KeyEvent.VK_C); + menuMoteTypeClasses.addMenuListener(new MenuListener() { + public void menuSelected(MenuEvent e) { + // Clear menu + menuMoteTypeClasses.removeAll(); + + // Recreate menu items + JMenuItem menuItem; + + for (Class moteTypeClass : moteTypeClasses) { + String description = GUI.getDescriptionOf(moteTypeClass); + menuItem = new JMenuItem(description); + menuItem.setActionCommand("create mote type"); + menuItem.putClientProperty("class", moteTypeClass); + menuItem.addActionListener(guiEventHandler); + menuMoteTypeClasses.add(menuItem); + } + } + public void menuDeselected(MenuEvent e) { + } + public void menuCanceled(MenuEvent e) { + } + }); + menu.add(menuMoteTypeClasses); + + menuItem = new JMenuItem("Information"); + menuItem.setActionCommand("start plugin"); + menuItem.putClientProperty("class", MoteTypeInformation.class); + menuItem.addActionListener(guiEventHandler); + + menu.add(menuItem); + + // Mote menu + menu = new JMenu("Motes"); + menu.setMnemonic(KeyEvent.VK_M); + menuBar.add(menu); + + // Mote types sub menu + menuMoteTypes = new JMenu("Add motes of type"); + menuMoteTypes.setMnemonic(KeyEvent.VK_A); + menuMoteTypes.addMenuListener(new MenuListener() { + public void menuSelected(MenuEvent e) { + // Clear menu + menuMoteTypes.removeAll(); + + if (currentSimulation == null) { + return; + } + + // Recreate menu items + JMenuItem menuItem; + + for (MoteType moteType : currentSimulation.getMoteTypes()) { + menuItem = new JMenuItem(moteType.getDescription()); + menuItem.setActionCommand("add motes"); + menuItem.setToolTipText(getDescriptionOf(moteType.getClass())); + menuItem.putClientProperty("motetype", moteType); + menuItem.addActionListener(guiEventHandler); + menuMoteTypes.add(menuItem); + } + } + public void menuDeselected(MenuEvent e) { + } + public void menuCanceled(MenuEvent e) { + } + }); + menu.add(menuMoteTypes); + + // Plugins menu + menuPlugins = new JMenu("Plugins"); + menuPlugins.setMnemonic(KeyEvent.VK_P); + menuBar.add(menuPlugins); + + // Settings menu + menu = new JMenu("Settings"); + menuBar.add(menu); + + menuItem = new JMenuItem("External tools paths"); + menuItem.setActionCommand("edit paths"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + menuItem = new JMenuItem("Manage user platforms"); + menuItem.setActionCommand("manage platforms"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + + // Mote plugins popup menu (not available via menu bar) + menuMotePlugins = new JPopupMenu(); + menuMotePlugins.add(new JLabel("Open mote plugin:")); + menuMotePlugins.add(new JSeparator()); + + return menuBar; + } + + private static void createAndShowGUI() { + + // Make sure we have nice window decorations. + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + + // Create and set up the window. + frame = new JFrame("COOJA Simulator"); + frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + + // Create and set up the content pane. + JComponent newContentPane = new GUI(); + newContentPane.setOpaque(true); + frame.setContentPane(newContentPane); + frame.setLocationRelativeTo(null); + + // Display the window. + frame.setVisible(true); + } + + // // PLATFORM CONFIG AND EXTENDABLE PARTS METHODS //// + + /** + * Register new mote type class. + * + * @param moteTypeClass + * Class to register + */ + public void registerMoteType(Class moteTypeClass) { + moteTypeClasses.add(moteTypeClass); + } + + /** + * Unregister all mote type classes. + */ + public void unregisterMoteTypes() { + moteTypeClasses.clear(); + } + + /** + * @return All registered mote type classes + */ + public Vector> getRegisteredMoteTypes() { + return moteTypeClasses; + } + + /** + * Register new IP distributor class + * + * @param ipDistributorClass + * Class to register + * @return True if class was registered + */ + public boolean registerIPDistributor( + Class ipDistributorClass) { + // Check that vector constructor exists + try { + ipDistributorClass.getConstructor(new Class[]{Vector.class}); + } catch (Exception e) { + logger.fatal("No vector constructor found of IP distributor: " + + ipDistributorClass); + return false; + } + + ipDistributorClasses.add(ipDistributorClass); + return true; + } + + /** + * Unregister all IP distributors. + */ + public void unregisterIPDistributors() { + ipDistributorClasses.clear(); + } + + /** + * @return All registered IP distributors + */ + public Vector> getRegisteredIPDistributors() { + return ipDistributorClasses; + } + + /** + * Register new positioner class. + * + * @param positionerClass + * Class to register + * @return True if class was registered + */ + public boolean registerPositioner(Class positionerClass) { + // Check that interval constructor exists + try { + positionerClass + .getConstructor(new Class[]{int.class, double.class, double.class, + double.class, double.class, double.class, double.class}); + } catch (Exception e) { + logger.fatal("No interval constructor found of positioner: " + + positionerClass); + return false; + } + + positionerClasses.add(positionerClass); + return true; + } + + /** + * Unregister all positioner classes. + */ + public void unregisterPositioners() { + positionerClasses.clear(); + } + + /** + * @return All registered positioner classes + */ + public Vector> getRegisteredPositioners() { + return positionerClasses; + } + + /** + * Register new radio medium class. + * + * @param radioMediumClass + * Class to register + * @return True if class was registered + */ + public boolean registerRadioMedium( + Class radioMediumClass) { + radioMediumClasses.add(radioMediumClass); + return true; + } + + /** + * Unregister all radio medium classes. + */ + public void unregisterRadioMediums() { + radioMediumClasses.clear(); + } + + /** + * @return All registered radio medium classes + */ + public Vector> getRegisteredRadioMediums() { + return radioMediumClasses; + } + + /** + * Builds new platform configuration using current user platforms settings. + * Reregisters mote types, plugins, IP distributors, positioners and radio + * mediums. This method may still return true even if all classes could not be + * registered, but always returns false if all user platform configuration + * files were not parsed correctly. + * + * Any registered temporary plugins will be saved and reregistered. + * + * @return True if external configuration files were found and parsed OK + */ + public boolean reparsePlatformConfig() { + // Backup temporary plugins + Vector> oldTempPlugins = (Vector>) pluginClassesTemporary + .clone(); + + // Reset current configuration + unregisterMoteTypes(); + unregisterPlugins(); + unregisterIPDistributors(); + unregisterPositioners(); + unregisterRadioMediums(); + + // Read default configuration + platformConfig = new PlatformConfig(); + // logger.info("Loading default platform configuration: " + + // PLATFORM_DEFAULT_CONFIG_FILENAME); + try { + platformConfig.appendConfig(new File(PLATFORM_DEFAULT_CONFIG_FILENAME)); + } catch (FileNotFoundException e) { + logger.fatal("Could not find default platform config file: " + + PLATFORM_DEFAULT_CONFIG_FILENAME); + return false; + } catch (IOException e) { + logger.fatal("Error when reading default platform config file: " + + PLATFORM_DEFAULT_CONFIG_FILENAME); + return false; + } + + // Append user platform configurations + for (File userPlatform : currentUserPlatforms) { + File userPlatformConfig = new File(userPlatform.getPath() + + File.separatorChar + PLATFORM_CONFIG_FILENAME); + // logger.info("Loading platform configuration: " + userPlatformConfig); + + try { + // Append config to general config + platformConfig.appendConfig(userPlatformConfig); + } catch (FileNotFoundException e) { + logger.fatal("Could not find platform config file: " + + userPlatformConfig); + return false; + } catch (IOException e) { + logger.fatal("Error when reading platform config file: " + + userPlatformConfig); + return false; + } + } + + // Create class loader + userPlatformClassLoader = createClassLoader(currentUserPlatforms); + + // Register mote types + String[] moteTypeClassNames = platformConfig.getStringArrayValue(GUI.class, + "MOTETYPES"); + if (moteTypeClassNames != null) { + for (String moteTypeClassName : moteTypeClassNames) { + Class moteTypeClass = tryLoadClass(this, + MoteType.class, moteTypeClassName); + + if (moteTypeClass != null) { + registerMoteType(moteTypeClass); + // logger.info("Loaded mote type class: " + moteTypeClassName); + } else { + logger.warn("Could not load mote type class: " + moteTypeClassName); + } + } + } + + // Register plugins + registerPlugin(SimControl.class, false); // Not in menu + registerPlugin(SimInformation.class, false); // Not in menu + registerPlugin(MoteTypeInformation.class, false); // Not in menu + String[] pluginClassNames = platformConfig.getStringArrayValue(GUI.class, + "PLUGINS"); + if (pluginClassNames != null) { + for (String pluginClassName : pluginClassNames) { + Class pluginClass = tryLoadClass(this, + VisPlugin.class, pluginClassName); + + if (pluginClass != null) { + registerPlugin(pluginClass); + // logger.info("Loaded plugin class: " + pluginClassName); + } else { + logger.warn("Could not load plugin class: " + pluginClassName); + } + } + } + + // Reregister temporary plugins again + if (oldTempPlugins != null) { + for (Class pluginClass : oldTempPlugins) { + if (registerTemporaryPlugin(pluginClass)) { + // logger.info("Reregistered temporary plugin class: " + + // getDescriptionOf(pluginClass)); + } else + logger.warn("Could not reregister temporary plugin class: " + + getDescriptionOf(pluginClass)); + } + } + + // Register IP distributors + String[] ipDistClassNames = platformConfig.getStringArrayValue(GUI.class, + "IP_DISTRIBUTORS"); + if (ipDistClassNames != null) { + for (String ipDistClassName : ipDistClassNames) { + Class ipDistClass = tryLoadClass(this, + IPDistributor.class, ipDistClassName); + + if (ipDistClass != null) { + registerIPDistributor(ipDistClass); + // logger.info("Loaded IP distributor class: " + ipDistClassName); + } else { + logger + .warn("Could not load IP distributor class: " + ipDistClassName); + } + } + } + + // Register positioners + String[] positionerClassNames = platformConfig.getStringArrayValue( + GUI.class, "POSITIONERS"); + if (positionerClassNames != null) { + for (String positionerClassName : positionerClassNames) { + Class positionerClass = tryLoadClass(this, + Positioner.class, positionerClassName); + + if (positionerClass != null) { + registerPositioner(positionerClass); + // logger.info("Loaded positioner class: " + positionerClassName); + } else { + logger + .warn("Could not load positioner class: " + positionerClassName); + } + } + } + + // Register radio mediums + String[] radioMediumsClassNames = platformConfig.getStringArrayValue( + GUI.class, "RADIOMEDIUMS"); + if (radioMediumsClassNames != null) { + for (String radioMediumClassName : radioMediumsClassNames) { + Class radioMediumClass = tryLoadClass(this, + RadioMedium.class, radioMediumClassName); + + if (radioMediumClass != null) { + registerRadioMedium(radioMediumClass); + // logger.info("Loaded radio medium class: " + radioMediumClassName); + } else { + logger.warn("Could not load radio medium class: " + + radioMediumClassName); + } + } + } + + return true; + } + + /** + * Returns the current platform configuration common to the entire simulator. + * + * @return Current platform configuration + */ + public PlatformConfig getPlatformConfig() { + return platformConfig; + } + + /** + * Returns the current user platforms common to the entire simulator. + * + * @return Current user platforms. + */ + public Vector getUserPlatforms() { + return currentUserPlatforms; + } + + // // PLUGIN METHODS //// + + /** + * Show a started plugin in working area. + * + * @param plugin + * Internal frame to add + */ + public void showPlugin(VisPlugin plugin) { + int nrFrames = this.getAllFrames().length; + add(plugin); + + // Set standard size if not specified by plugin itself + if (plugin.getWidth() <= 0 || plugin.getHeight() <= 0) { + plugin.setSize(FRAME_STANDARD_WIDTH, FRAME_STANDARD_HEIGHT); + } + + // Set location if not already visible + if (!plugin.isVisible()) { + plugin.setLocation((nrFrames + 1) * FRAME_NEW_OFFSET, (nrFrames + 1) + * FRAME_NEW_OFFSET); + plugin.setVisible(true); + } + + // Mote to front and select plugin + myGUI.moveToFront(plugin); + myGUI.setSelectedFrame(plugin); + } + + /** + * Remove a plugin from working area. + * + * @param plugin + * Plugin to remove + * @param askUser + * If plugin is the last one, ask user if we should remove current + * simulation also? + */ + public void removePlugin(VisPlugin plugin, boolean askUser) { + // Clear any allocated resources and remove plugin + plugin.closePlugin(); + plugin.dispose(); + + if (askUser && myGUI.getAllFrames().length == 0) { + String s1 = "Remove"; + String s2 = "Cancel"; + Object[] options = {s1, s2}; + int n = JOptionPane.showOptionDialog(frame, + "You have an active simulation.\nDo you want to remove it?", + "Remove current simulation?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + doRemoveSimulation(false); + } + } + + /** + * Starts a plugin of given plugin class. If the plugin is a mote plugin the + * currently selected mote will be given as an argument. + * + * @param pluginClass + * Plugin class + * @return True if plugin was started, false otherwise + */ + protected boolean startPlugin(Class pluginClass) { + // Check that plugin class is registered + if (!pluginClasses.contains(pluginClass)) { + logger.fatal("Plugin class not registered: " + pluginClass); + return false; + } + + // Instantiate and show plugin differently depending on plugin type + VisPlugin newPlugin = null; + int pluginType = pluginClass.getAnnotation(VisPluginType.class).value(); + + try { + if (pluginType == VisPluginType.MOTE_PLUGIN) { + if (selectedMote == null) { + logger.fatal("Can't start mote plugin (no mote selected)"); + return false; + } + + newPlugin = pluginClass.getConstructor(new Class[]{Mote.class}) + .newInstance(selectedMote); + selectedMote = null; + } else if (pluginType == VisPluginType.SIM_PLUGIN) { + if (currentSimulation == null) { + logger.fatal("Can't start simulation plugin (no simulation)"); + return false; + } + + newPlugin = pluginClass.getConstructor(new Class[]{Simulation.class}) + .newInstance(currentSimulation); + } else if (pluginType == VisPluginType.SIM_STANDARD_PLUGIN) { + if (currentSimulation == null) { + logger + .fatal("Can't start simulation standard plugin (no simulation)"); + return false; + } + + newPlugin = pluginClass.getConstructor(new Class[]{Simulation.class}) + .newInstance(currentSimulation); + } else if (pluginType == VisPluginType.GUI_PLUGIN) { + if (currentGUI == null) { + logger.fatal("Can't start GUI plugin (no GUI)"); + return false; + } + + newPlugin = pluginClass.getConstructor(new Class[]{GUI.class}) + .newInstance(currentGUI); + } + } catch (Exception e) { + logger.fatal("Exception thrown when starting plugin: " + e); + return false; + } + + if (newPlugin == null) + return false; + + // Show plugin + myGUI.showPlugin(newPlugin); + return true; + } + + /** + * Register a plugin to be included in the GUI. The plugin will be visible in + * the menubar. + * + * @param newPluginClass + * New plugin to register + * @return True if this plugin was registered ok, false otherwise + */ + public boolean registerPlugin(Class newPluginClass) { + return registerPlugin(newPluginClass, true); + } + + /** + * Register a temporary plugin to be included in the GUI. The plugin will be + * visible in the menubar. This plugin will automatically be unregistered if + * the current simulation is removed. + * + * @param newPluginClass + * New plugin to register + * @return True if this plugin was registered ok, false otherwise + */ + public boolean registerTemporaryPlugin( + Class newPluginClass) { + if (pluginClasses.contains(newPluginClass)) + return false; + + boolean returnVal = registerPlugin(newPluginClass, true); + if (!returnVal) + return false; + + pluginClassesTemporary.add(newPluginClass); + return true; + } + + /** + * Unregister a plugin class. Removes any plugin menu items links as well. + * + * @param pluginClass + * Plugin class to unregister + */ + public void unregisterPlugin(Class pluginClass) { + + // Remove (if existing) plugin class menu items + for (Component menuComponent : menuPlugins.getMenuComponents()) { + if (menuComponent.getClass().isAssignableFrom(JMenuItem.class)) { + JMenuItem menuItem = (JMenuItem) menuComponent; + if (menuItem.getClientProperty("class").equals(pluginClass)) + menuPlugins.remove(menuItem); + } + } + for (MenuElement menuComponent : menuMotePlugins.getSubElements()) { + if (menuComponent.getClass().isAssignableFrom(JMenuItem.class)) { + JMenuItem menuItem = (JMenuItem) menuComponent; + if (menuItem.getClientProperty("class").equals(pluginClass)) + menuPlugins.remove(menuItem); + } + } + + // Remove from plugin vectors (including temporary) + if (pluginClasses.contains(pluginClass)) + pluginClasses.remove(pluginClass); + if (pluginClassesTemporary.contains(pluginClass)) + pluginClassesTemporary.remove(pluginClass); + } + + /** + * Register a plugin to be included in the GUI. + * + * @param newPluginClass + * New plugin to register + * @param addToMenu + * Should this plugin be added to the dedicated plugins menubar? + * @return True if this plugin was registered ok, false otherwise + */ + private boolean registerPlugin(Class newPluginClass, + boolean addToMenu) { + + // Get description annotation (if any) + String description = getDescriptionOf(newPluginClass); + + // Get plugin type annotation (required) + int pluginType; + if (newPluginClass.isAnnotationPresent(VisPluginType.class)) { + pluginType = newPluginClass.getAnnotation(VisPluginType.class).value(); + } else { + pluginType = VisPluginType.UNDEFINED_PLUGIN; + } + + // Check that plugin type is valid and constructor exists + try { + if (pluginType == VisPluginType.MOTE_PLUGIN) { + newPluginClass.getConstructor(new Class[]{Mote.class}); + } else if (pluginType == VisPluginType.SIM_PLUGIN) { + newPluginClass.getConstructor(new Class[]{Simulation.class}); + } else if (pluginType == VisPluginType.SIM_STANDARD_PLUGIN) { + newPluginClass.getConstructor(new Class[]{Simulation.class}); + } else if (pluginType == VisPluginType.GUI_PLUGIN) { + newPluginClass.getConstructor(new Class[]{GUI.class}); + } else { + logger.fatal("Could not find valid plugin type annotation in class " + + newPluginClass); + return false; + } + } catch (NoSuchMethodException e) { + logger.fatal("Could not find valid constructor in class " + + newPluginClass + ": " + e); + return false; + } + + if (addToMenu) { + // Create 'start plugin'-menu item + JMenuItem menuItem = new JMenuItem(description); + menuItem.setActionCommand("start plugin"); + menuItem.putClientProperty("class", newPluginClass); + menuItem.addActionListener(guiEventHandler); + + menuPlugins.add(menuItem); + + if (pluginType == VisPluginType.MOTE_PLUGIN) { + // Disable previous menu item and add new item to mote plugins menu + menuItem.setEnabled(false); + menuItem.setToolTipText("Mote plugin"); + + menuItem = new JMenuItem(description); + menuItem.setActionCommand("start plugin"); + menuItem.putClientProperty("class", newPluginClass); + menuItem.addActionListener(guiEventHandler); + menuMotePlugins.add(menuItem); + } + } + + pluginClasses.add(newPluginClass); + return true; + } + + /** + * Unregister all plugin classes, including temporary plugins. + */ + public void unregisterPlugins() { + menuPlugins.removeAll(); + menuMotePlugins.removeAll(); + pluginClasses.clear(); + pluginClassesTemporary.clear(); + } + + /** + * Show mote plugins menu for starting a mote plugin. All registered mote + * plugins can be selected from. + * + * @param invoker + * Component that wants to display the menu + * @param mote + * Mote of plugin selected + * @param location + * Location of popup menu + */ + public void showMotePluginsMenu(Component invoker, Mote mote, Point location) { + menuMotePlugins.setInvoker(invoker); + menuMotePlugins.setLocation(location); + menuMotePlugins.setVisible(true); + selectedMote = mote; + } + + // // GUI CONTROL METHODS //// + + private void setSimulation(Simulation sim) { + if (sim != null) { + doRemoveSimulation(false); + } + currentSimulation = sim; + + // Set frame title + frame.setTitle("COOJA Simulator" + " - " + sim.getTitle()); + + // Open standard plugins + for (Class visPluginClass : pluginClasses) { + int pluginType = visPluginClass.getAnnotation(VisPluginType.class) + .value(); + if (pluginType == VisPluginType.SIM_STANDARD_PLUGIN) { + startPlugin(visPluginClass); + } + } + } + + /** + * Creates a new mote type of the given mote type class. + * + * @param moteTypeClass + * Mote type class + */ + public void doCreateMoteType(Class moteTypeClass) { + if (currentSimulation == null) { + logger.fatal("Can't create mote type (no simulation)"); + return; + } + + // Stop simulation (if running) + currentSimulation.stopSimulation(); + + // Create mote type + MoteType newMoteType = null; + boolean moteTypeOK = false; + try { + newMoteType = moteTypeClass.newInstance(); + moteTypeOK = newMoteType.configureAndInit(frame, currentSimulation); + } catch (Exception e) { + logger.fatal("Exception when creating mote type: " + e); + return; + } + + // Add mote type to simulation + if (newMoteType != null && moteTypeOK) { + currentSimulation.addMoteType(newMoteType); + } + } + + /** + * Remove current simulation + * + * @param askForConfirmation + * Should we ask for confirmation if a simulation is already active? + */ + public void doRemoveSimulation(boolean askForConfirmation) { + + if (currentSimulation != null) { + if (askForConfirmation) { + String s1 = "Remove"; + String s2 = "Cancel"; + Object[] options = {s1, s2}; + int n = JOptionPane.showOptionDialog(frame, + "You have an active simulation.\nDo you want to remove it?", + "Remove current simulation?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + } + + // Close all started non-GUI plugins + for (JInternalFrame openededFrame : myGUI.getAllFrames()) { + // Check that frame is a plugin + Class frameClass = openededFrame.getClass(); + if (pluginClasses.contains(frameClass)) { + int pluginType = ((Class) frameClass) + .getAnnotation(VisPluginType.class).value(); + if (pluginType != VisPluginType.GUI_PLUGIN) + removePlugin((VisPlugin) openededFrame, false); + } + } + + // Delete simulation + currentSimulation.deleteObservers(); + currentSimulation.stopSimulation(); + currentSimulation = null; + + // Unregister temporary plugin classes + Enumeration> pluginClasses = pluginClassesTemporary + .elements(); + while (pluginClasses.hasMoreElements()) { + unregisterPlugin(pluginClasses.nextElement()); + } + + // Reset frame title + frame.setTitle("COOJA Simulator"); + } + } + + /** + * Load a simulation configuration file from disk + * + * @param askForConfirmation + * Should we ask for confirmation if a simulation is already active? + */ + public void doLoadConfig(boolean askForConfirmation) { + + if (CoreComm.hasLibraryBeenLoaded()) { + JOptionPane + .showMessageDialog( + frame, + "Shared libraries has already been loaded.\nYou need to restart the simulator!", + "Can't load simulation", JOptionPane.ERROR_MESSAGE); + return; + } + + if (askForConfirmation && currentSimulation != null) { + String s1 = "Remove"; + String s2 = "Cancel"; + Object[] options = {s1, s2}; + int n = JOptionPane.showOptionDialog(frame, + "You have an active simulation.\nDo you want to remove it?", + "Remove current simulation?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + } + + doRemoveSimulation(false); + + JFileChooser fc = new JFileChooser(); + + fc.setFileFilter(GUI.SAVED_SIMULATIONS_FILES); + + int returnVal = fc.showOpenDialog(frame); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File loadFile = fc.getSelectedFile(); + + // Try adding extension if not founds + if (!loadFile.exists()) { + loadFile = new File(loadFile.getParent(), loadFile.getName() + + SAVED_SIMULATIONS_FILES); + } + + if (loadFile.exists() && loadFile.canRead()) { + Simulation newSim = null; + try { + newSim = Simulation.loadSimulationConfig(loadFile); + } catch (UnsatisfiedLinkError e) { + logger.warn("Could not reopen libraries"); + newSim = null; + } + if (newSim != null) { + myGUI.setSimulation(newSim); + } + } else + logger.fatal("No read access to file"); + + } else { + logger.info("Load command cancelled by user..."); + } + + } + + /** + * Save current simulation configuration to disk + * + * @param askForConfirmation + * Ask for confirmation before overwriting file + */ + public void doSaveConfig(boolean askForConfirmation) { + if (currentSimulation != null) { + currentSimulation.stopSimulation(); + + JFileChooser fc = new JFileChooser(); + + fc.setFileFilter(GUI.SAVED_SIMULATIONS_FILES); + + int returnVal = fc.showSaveDialog(myGUI); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File saveFile = fc.getSelectedFile(); + if (!fc.accept(saveFile)) { + saveFile = new File(saveFile.getParent(), saveFile.getName() + + SAVED_SIMULATIONS_FILES); + } + + if (saveFile.exists()) { + if (askForConfirmation) { + String s1 = "Overwrite"; + String s2 = "Cancel"; + Object[] options = {s1, s2}; + int n = JOptionPane + .showOptionDialog( + frame, + "A file with the same name already exists.\nDo you want to remove it?", + "Overwrite existing file?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + } + } + + if (!saveFile.exists() || saveFile.canWrite()) + currentSimulation.saveSimulationConfig(saveFile); + else + logger.fatal("No write access to file"); + + } else { + logger.info("Save command cancelled by user..."); + } + } + } + + /** + * Add new mote to current simulation + */ + public void doAddMotes(MoteType moteType) { + if (currentSimulation != null) { + currentSimulation.stopSimulation(); + + Vector newMotes = AddMoteDialog.showDialog(frame, moteType); + if (newMotes != null) { + for (Mote newMote : newMotes) + currentSimulation.addMote(newMote); + } + + } else + logger.warn("No simulation active"); + } + + /** + * Create a new simulation + * + * @param askForConfirmation + * Should we ask for confirmation if a simulation is already active? + */ + public void doCreateSimulation(boolean askForConfirmation) { + if (askForConfirmation && currentSimulation != null) { + String s1 = "Remove"; + String s2 = "Cancel"; + Object[] options = {s1, s2}; + int n = JOptionPane.showOptionDialog(frame, + "You have an active simulation.\nDo you want to remove it?", + "Remove current simulation?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + } + + // Create new simulation + doRemoveSimulation(false); + Simulation newSim = new Simulation(); + boolean createdOK = CreateSimDialog.showDialog(frame, newSim); + if (createdOK) { + myGUI.setSimulation(newSim); + } + } + + /** + * Quit program + * + * @param askForConfirmation + * Should we ask for confirmation before quitting? + */ + public void doQuit(boolean askForConfirmation) { + if (!askForConfirmation) + System.exit(0); + + String s1 = "Quit"; + String s2 = "Cancel"; + Object[] options = {s1, s2}; + int n = JOptionPane.showOptionDialog(frame, "Sure you want to quit?", + "Close COOJA Simulator", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) + return; + + System.exit(0); + } + + // // EXTERNAL TOOLS SETTINGS METHODS //// + + /** + * @return Number of external tools settings + */ + public static int getExternalToolsSettingsCount() { + return externalToolsSettingNames.length; + } + + /** + * Get name of external tools setting at given index. + * + * @param index + * Setting index + * @return Name + */ + public static String getExternalToolsSettingName(int index) { + return externalToolsSettingNames[index]; + } + + /** + * @param name + * Name of setting + * @return Value + */ + public static String getExternalToolsSetting(String name) { + return currentExternalToolsSettings.getProperty(name); + } + + /** + * @param name + * Name of setting + * @param defaultValue + * Default value + * @return Value + */ + public static String getExternalToolsSetting(String name, String defaultValue) { + return currentExternalToolsSettings.getProperty(name, defaultValue); + } + + /** + * @param name + * Name of setting + * @param newVal + * New value + */ + public static void setExternalToolsSetting(String name, String newVal) { + currentExternalToolsSettings.setProperty(name, newVal); + } + + /** + * Load external tools settings from default file. + */ + public static void loadExternalToolsDefaultSettings() { + String filename = GUI.EXTERNAL_TOOLS_LINUX_SETTINGS_FILENAME; + if (System.getProperty("os.name").startsWith("Win")) + filename = GUI.EXTERNAL_TOOLS_WIN32_SETTINGS_FILENAME; + + try { + InputStream in = GUI.class.getResourceAsStream(filename); + if (in == null) { + throw new FileNotFoundException(filename + " not found"); + } + Properties settings = new Properties(); + settings.load(in); + in.close(); + + currentExternalToolsSettings = settings; + } catch (IOException e) { + // Error while importing default properties + logger.warn( + "Error when reading external tools settings from " + filename, e); + } finally { + if (currentExternalToolsSettings == null) { + currentExternalToolsSettings = new Properties(); + } + } + } + + /** + * Load user values from external properties file + */ + private static void loadExternalToolsUserSettings() { + String filename = GUI.EXTERNAL_TOOLS_USER_SETTINGS_FILENAME; + try { + FileInputStream in = new FileInputStream(filename); + Properties settings = new Properties(); + settings.load(in); + in.close(); + + Enumeration en = settings.keys(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + setExternalToolsSetting(key, settings.getProperty(key)); + } + + } catch (FileNotFoundException e) { + // No default configuration file found, using default + } catch (IOException e) { + // Error while importing saved properties, using default + logger.warn("Error when reading default settings from " + filename); + } + } + + /** + * Save external tools user settings to file. + */ + public static void saveExternalToolsUserSettings() { + String filename = GUI.EXTERNAL_TOOLS_USER_SETTINGS_FILENAME; + try { + FileOutputStream out = new FileOutputStream(filename); + currentExternalToolsSettings.store(out, "COOJA User Settings"); + out.close(); + } catch (FileNotFoundException ex) { + // Could not open settings file for writing, aborting + logger.warn("Could not save external tools user settings to " + filename + + ", aborting"); + } catch (IOException ex) { + // Could not open settings file for writing, aborting + logger.warn("Error while saving external tools user settings to " + + filename + ", aborting"); + } + } + + // // GUI EVENT HANDLER //// + + private class GUIEventHandler implements ActionListener, WindowListener { + public void windowDeactivated(WindowEvent e) { + } + public void windowIconified(WindowEvent e) { + } + public void windowDeiconified(WindowEvent e) { + } + public void windowOpened(WindowEvent e) { + } + public void windowClosed(WindowEvent e) { + } + public void windowActivated(WindowEvent e) { + } + + public void windowClosing(WindowEvent e) { + myGUI.doQuit(true); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("new sim")) { + myGUI.doCreateSimulation(true); + } else if (e.getActionCommand().equals("close sim")) { + myGUI.doRemoveSimulation(true); + } else if (e.getActionCommand().equals("load sim")) { + myGUI.doLoadConfig(true); + } else if (e.getActionCommand().equals("save sim")) { + myGUI.doSaveConfig(true); + } else if (e.getActionCommand().equals("quit")) { + myGUI.doQuit(true); + } else if (e.getActionCommand().equals("create mote type")) { + myGUI.doCreateMoteType((Class) ((JMenuItem) e + .getSource()).getClientProperty("class")); + } else if (e.getActionCommand().equals("add motes")) { + myGUI.doAddMotes((MoteType) ((JMenuItem) e.getSource()) + .getClientProperty("motetype")); + } else if (e.getActionCommand().equals("edit paths")) { + ExternalToolsDialog.showDialog(frame); + } else if (e.getActionCommand().equals("manage platforms")) { + Vector newPlatforms = UserPlatformsDialog.showDialog(frame, + currentUserPlatforms, null); + if (newPlatforms != null) { + currentUserPlatforms = newPlatforms; + reparsePlatformConfig(); + } + } else if (e.getActionCommand().equals("start plugin")) { + Class pluginClass = (Class) ((JMenuItem) e + .getSource()).getClientProperty("class"); + startPlugin(pluginClass); + } else + logger.warn("Unhandled action: " + e.getActionCommand()); + } + } + + // // VARIOUS HELP METHODS //// + + /** + * Help method that tries to load and initialize a class with given name. + * + * @param + * Class extending given class type + * @param classType + * Class type + * @param className + * Class name + * @return Class extending given class type or null if not found + */ + public Class tryLoadClass( + Object callingObject, Class classType, String className) { + + if (callingObject != null) { + try { + return callingObject.getClass().getClassLoader().loadClass(className) + .asSubclass(classType); + } catch (ClassNotFoundException e) { + } + } + + try { + return Class.forName(className).asSubclass(classType); + } catch (ClassNotFoundException e) { + } + + try { + return userPlatformClassLoader.loadClass(className).asSubclass(classType); + } catch (ClassNotFoundException e) { + } + + return null; + } + + private ClassLoader createClassLoader(Vector currentUserPlatforms) { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + + // Combine class loader from all user platforms (including any specified JAR + // files) + for (File userPlatform : currentUserPlatforms) { + // Read configuration to check if any JAR files should be loaded + try { + File userPlatformConfigFile = new File(userPlatform.getPath() + + File.separatorChar + PLATFORM_CONFIG_FILENAME); + PlatformConfig userPlatformConfig = new PlatformConfig(); + userPlatformConfig.appendConfig(userPlatformConfigFile); + String[] platformJarFiles = userPlatformConfig.getStringArrayValue( + GUI.class, "JARFILES"); + if (platformJarFiles != null && platformJarFiles.length > 0) { + URL[] platformJarURLs = new URL[platformJarFiles.length]; + for (int i = 0; i < platformJarFiles.length; i++) { + platformJarURLs[i] = new File(userPlatform.getPath() + + File.separatorChar + "lib" + File.separatorChar + + platformJarFiles[i]).toURL(); + } + + classLoader = new URLClassLoader(platformJarURLs, classLoader); + } + + } catch (Exception e) { + logger.fatal("Error when trying to read JAR-file in " + userPlatform + + ": " + e); + } + + // Add java class directory + classLoader = new DirectoryClassLoader(classLoader, new File(userPlatform + .getPath() + + File.separatorChar + "java")); + } + + return classLoader; + } + + /** + * Help method that returns the description for given object. This method + * reads from the object's class annotations if existing. Otherwise it returns + * the simple class name of object's class. + * + * @param object + * Object + * @return Description + */ + public static String getDescriptionOf(Object object) { + return getDescriptionOf(object.getClass()); + } + + /** + * Help method that returns the description for given class. This method reads + * from class annotations if existing. Otherwise it returns the simple class + * name. + * + * @param clazz + * Class + * @return Description + */ + public static String getDescriptionOf(Class clazz) { + if (clazz.isAnnotationPresent(ClassDescription.class)) { + return clazz.getAnnotation(ClassDescription.class).value(); + } + return clazz.getSimpleName(); + } + + /** + * Load configurations and create a GUI. + * + * @param args + * null + */ + public static void main(String[] args) { + + // Configure logger + if ((new File(LOG_CONFIG_FILE)).exists()) { + DOMConfigurator.configure(LOG_CONFIG_FILE); + } else { + // Used when starting from jar + DOMConfigurator.configure(GUI.class.getResource("/" + LOG_CONFIG_FILE)); + } + + // Schedule a job for the event-dispatching thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/IPDistributor.java b/tools/cooja/java/se/sics/cooja/IPDistributor.java new file mode 100644 index 000000000..1e6cb8f8a --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/IPDistributor.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006, 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: IPDistributor.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.lang.reflect.Constructor; +import java.util.Vector; +import org.apache.log4j.Logger; + +/** + * A IP distributor is used for determining IP addresses of newly created motes. + * + * @author Fredrik Osterlind + */ +public abstract class IPDistributor { + private static Logger logger = Logger.getLogger(IPDistributor.class); + + /** + * This method creates an instance of the given class with the given vector as + * constructor argument. Instead of calling the constructors directly this + * method may be used. + * + * @param ipDistClass Class + * @param newMotes All motes that later should be assigned IP numbers + * @return IP distributor instance + */ + public static final IPDistributor generateInterface( + Class ipDistClass, Vector newMotes) { + try { + // Generating IP distributor + Constructor constr = ipDistClass + .getConstructor(new Class[]{Vector.class}); + return (IPDistributor) constr.newInstance(new Object[]{newMotes}); + } catch (Exception e) { + logger.fatal("Exception when creating " + ipDistClass + ": " + e); + return null; + } + } + + /** + * Returns the next mote position. + * + * @return Position + */ + public abstract String getNextIPAddress(); + +} diff --git a/tools/cooja/java/se/sics/cooja/Mote.java b/tools/cooja/java/se/sics/cooja/Mote.java new file mode 100644 index 000000000..2f75cd4cd --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/Mote.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2006, 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: Mote.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.util.Collection; +import java.util.Observer; +import org.jdom.Element; + +/** + * This interface represents a simulated mote. + * + * A mote is always in some state, describing the status of the CPU etc. + * Motes in different states may be handled differently by the for example simulation loops and plugins. + * + * All motes must also have an interface handler, a mote type and a mote memory. + * + * @see se.sics.cooja.MoteInterfaceHandler + * @see se.sics.cooja.MoteMemory + * @see se.sics.cooja.MoteType + * + * @author Fredrik Osterlind + */ +public interface Mote { + + /** + * Active state. + */ + public static int STATE_ACTIVE = 1; + + /** + * Sleeping state. + */ + public static int STATE_LPM = 2; + + /** + * Dead state (may be out of batteries). + */ + public static int STATE_DEAD = 3; + + /** + * Tries to change state to given argument. + * A dead mote can typically not change state, while a sleeping or active mote can. + * + * @param newState New state of mote. + */ + public void setState(int newState); + + /** + * @return Current mote state + */ + public int getState(); + + /** + * Adds new state observer. + * This observer is notified if mote changes state. + * + * @see #deleteStateObserver(Observer) + * @param newObserver New observer + */ + public void addStateObserver(Observer newObserver); + + /** + * Delete existing state observer. + * + * @see #addStateObserver(Observer) + * @param newObserver Registered state observer + */ + public void deleteStateObserver(Observer newObserver); + + + /** + * Returns the interface handler of this mote. + * + * @see #setInterfaces(MoteInterfaceHandler) + * @return Mote interface handler + */ + public MoteInterfaceHandler getInterfaces(); + + /** + * Sets the interface handler of this mote. + * + * @param moteInterfaceHandler New interface handler + * @see #getInterfaces() + */ + public void setInterfaces(MoteInterfaceHandler moteInterfaceHandler); + + + /** + * Returns the memory of this mote. + * + * @see #setMemory(MoteMemory) + * @return Mote memory + */ + public MoteMemory getMemory(); + + /** + * Sets the memory of this mote. + * + * @see #getMemory() + * @param memory Mote memory + */ + public void setMemory(MoteMemory memory); + + + /** + * Returns mote type. + * + * @see #setType(MoteType) + * @return Mote type + */ + public MoteType getType(); + + /** + * Sets mote type to given argument. + * + * @see #getType() + * @param type New type + */ + public void setType(MoteType type); + + + /** + * Returns simulation which holds this mote. + * + * @see #setSimulation(Simulation) + * @return Simulation + */ + public Simulation getSimulation(); + + /** + * Sets the simulation which holds this mote. + * + * @see #getSimulation() + * @param simulation Simulation + */ + public void setSimulation(Simulation simulation); + + /** + * Ticks this mote and increases any internal time to given argument. + * + * Each mote implementation may handle calls to this method differently, + * but, if existing, the simulated mote should at least handle one event. + * + * This method is responsible for updating the mote interfaces, the memory and the mote state. + * + * A call to this method typically + * polls all interfaces, + * activates the memory, + * lets the underlying mote software handle one event, + * fetches the updated memory and + * finally polls all interfaces again. + * + * @param simTime New simulation time + */ + public void tick(int simTime); + + /** + * Returns XML elements representing the current config of this mote. + * This is fetched by the simulator for example when saving a simulation configuration file. + * For example a mote may return the configs of all its interfaces. + * This method should however not return state specific information such as the mote state. + * (All nodes are restarted when loading a simulation.) + * + * @see #setConfigXML(Simulation, Collection) + * @return XML elements representing the current mote config + */ + public abstract Collection getConfigXML(); + + /** + * Sets the current mote config depending on the given XML elements. + * + * @param simulation Simulation holding this mote + * @param configXML Config XML elements + * + * @see #getConfigXML() + */ + public abstract boolean setConfigXML(Simulation simulation, Collection configXML); + +} diff --git a/tools/cooja/java/se/sics/cooja/MoteInterface.java b/tools/cooja/java/se/sics/cooja/MoteInterface.java new file mode 100644 index 000000000..623e6ce10 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/MoteInterface.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006, 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: MoteInterface.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.util.Collection; +import java.util.Observable; +import javax.swing.JPanel; +import org.apache.log4j.Logger; +import org.jdom.Element; + +/** + * A mote interface represents a mote property. + * Often this is a simulated hardware peripheral such as a button or a led. + * This can also be a property the mote software itself is unaware of, + * for example the current position of the mote. + * + * Interfaces are the main way for the simulator to interact with a simulated mote. + * + * Interfaces are divided into active and passive interfaces, and are handled differently. + * In order to create a passive interfaces, the class should also implement the dummy Java interface PassiveMoteInterface. + * For an explanation of the differences of active and passive interfaces see class PassiveMoteInterface. + * + * @see PassiveMoteInterface + * @author Fredrik Osterlind + */ +public abstract class MoteInterface extends Observable { + private static Logger logger = Logger.getLogger(MoteInterface.class); + + /** + * This method creates an instance of the given class with the given mote as constructor + * argument. Instead of calling the interface constructors directly this method may be used. + * + * @param interfaceClass Mote interface class + * @param mote Mote that will hold the interface + * @return Mote interface instance + */ + public static final MoteInterface generateInterface(Class interfaceClass, Mote mote) { + try { + // Generating interface + MoteInterface instance = (MoteInterface) interfaceClass.getConstructor( + new Class[] { Mote.class }).newInstance(new Object[] { mote }); + + return instance; + } catch (Exception e) { + logger.fatal("Exception when creating " + interfaceClass + ": " + e); + return null; + } + } + + /** + * Actions to be performed just before the holding mote is ticked + */ + public abstract void doActionsBeforeTick(); + + /** + * Actions to be performed just after the holding mote has been ticked + */ + public abstract void doActionsAfterTick(); + + /** + * Returns a panel with interesting data for this interface. + * This could for example show last messages sent/received for + * a radio interface, or logged message for a log interface. + * + * All panels returned from this method must later be released + * for memory reasons. + * + * If returned panel is null, this interface will not be visualized. + * + * @see #releaseInterfaceVisualizer(JPanel) + * @return Interface visualizer or null + */ + public abstract JPanel getInterfaceVisualizer(); + + /** + * This method should be called when a visualizer panel is no longer in use. + * Any resources of that panel, for example registered observers, will be released. + * + * @see #getInterfaceVisualizer() + * @param panel A interface visualizer panel fetched earlier for this mote interface. + */ + public abstract void releaseInterfaceVisualizer(JPanel panel); + + /** + * Returns approximated energy consumed (mQ) during the current tick. + * If the interface is active, this information must be available after the doActionsAfterTick method. + * If the interface is passive, this information must be available after the doActionsBeforeTick method. + * + * The interface is responsible to gather information about the current internal state, + * and calculate whatever energy it needs in that state and during one tick. + * + * If the holding mote is dead, this method will not be called. + * If the holding mote is sleeping and this interface is active, this method will not be called. + * + * For example, a radio transmitter or a PIR sensor often has a much higher energy + * usage than a button sensor which virtually needs no energy at all. + * If the radio is turned off in hardware, it should return a zero energy consumption. + * If the radio is sending something which would take longer than one tick, it may either return + * the total energy used directly, or a smaller amount during several ticks. + * + * This method may typically be used by the passive interface battery, which sums up + * all energy used during one tick and decreases the battery energy left. + * + * @see se.sics.cooja.interfaces.Battery + * @return Energy consumption of this device during the current tick + */ + public abstract double energyConsumptionPerTick(); + + /** + * Returns XML elements representing the current config of this mote interface. + * This is fetched by the simulator for example when saving a simulation configuration file. + * For example an IP interface may return one element with the mote IP address. + * This method should however not return state specific information such as a log history. + * (All nodes are restarted when loading a simulation.) + * + * @see #setConfigXML(Collection) + * @return XML elements representing the current interface config + */ + public abstract Collection getConfigXML(); + + /** + * Sets the current mote interface config depending on the given XML elements. + * + * @see #getConfigXML() + * @param configXML Config XML elements + */ + public abstract void setConfigXML(Collection configXML); + +} diff --git a/tools/cooja/java/se/sics/cooja/MoteInterfaceHandler.java b/tools/cooja/java/se/sics/cooja/MoteInterfaceHandler.java new file mode 100644 index 000000000..c4f45ded6 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/MoteInterfaceHandler.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2006, 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: MoteInterfaceHandler.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.util.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.interfaces.*; + +/** + * A mote interface handler holds all interfaces for a specific mote. Even + * though an interface handler strictly does not need any interfaces at all, a + * position interface is highly recommended. (A lot of plugins depend on a mote + * position, for example when visualizing nodes.) + * + * Interfaces are divided into active and passive interfaces. Active interfaces + * are only polled if the mote is active, while passive interfaces are polled in + * all states except dead state. + * + * Interfaces should be polled via this class when the mote is ticked. + * + * @author Fredrik Osterlind + */ +public class MoteInterfaceHandler { + private static Logger logger = Logger.getLogger(MoteInterfaceHandler.class); + + private Battery myBattery; + private Beeper myBeeper; + private Button myButton; + private Clock myClock; + private IPAddress myIPAddress; + private LED myLED; + private Log myLog; + private MoteID myMoteID; + private PIR myPIR; + private Position myPosition; + private Radio myRadio; + + private Vector myActiveInterfaces = new Vector(); + private Vector myPassiveInterfaces = new Vector(); + + /** + * Creates a new empty mote interface handler. + */ + public MoteInterfaceHandler() { + } + + /** + * Creates a new mote interface handler. All given interfaces are loaded. + * + * @param mote + * The mote holding this interface handler + * @param allInterfaces + * Simulation interfaces to load + */ + public MoteInterfaceHandler(Mote mote, + Vector> allInterfaces) { + + // Load all interfaces + for (Class interfaceClass : allInterfaces) { + boolean isPassive = false; + + // Check if interface is active or passive + if (PassiveMoteInterface.class.isAssignableFrom(interfaceClass)) + isPassive = true; + + // Load interface + MoteInterface loadedInterface = MoteInterface.generateInterface( + interfaceClass, mote); + + if (loadedInterface != null) + if (isPassive) + addPassiveInterface(loadedInterface); + else + addActiveInterface(loadedInterface); + else + logger.warn("Interface could not be loaded: " + interfaceClass); + } + } + + /** + * Get an interface (active or passive) of the given type. Returns the first + * loaded interface found, that is either of the given class or of a subclass. + * + * For example, if the current radio interface is wanted, this method would be + * called like the following: getInterfaceOfType(Radio.class) + * + * @param interfaceType + * Type of interface to return + * @return Interface or null if no interface loaded of given type + */ + public N getInterfaceOfType(Class interfaceType) { + + Enumeration allActive = myActiveInterfaces.elements(); + while (allActive.hasMoreElements()) { + N nextInterface = (N) allActive.nextElement(); + if (interfaceType.isAssignableFrom(nextInterface.getClass())) + return nextInterface; + } + Enumeration allPassive = myPassiveInterfaces.elements(); + while (allPassive.hasMoreElements()) { + N nextInterface = (N) allPassive.nextElement(); + if (interfaceType.isAssignableFrom(nextInterface.getClass())) + return nextInterface; + } + return null; + } + + /** + * Returns the battery interface (if any). + * + * @return Battery interface + */ + public Battery getBattery() { + if (myBattery == null) { + myBattery = getInterfaceOfType(Battery.class); + } + return myBattery; + } + + /** + * Returns the beeper interface (if any). + * + * @return Beeper interface + */ + public Beeper getBeeper() { + if (myBeeper == null) { + myBeeper = getInterfaceOfType(Beeper.class); + } + return myBeeper; + } + + /** + * Returns the button interface (if any). + * + * @return Button interface + */ + public Button getButton() { + if (myButton == null) { + myButton = getInterfaceOfType(Button.class); + } + return myButton; + } + + /** + * Returns the clock interface (if any). + * + * @return Clock interface + */ + public Clock getClock() { + if (myClock == null) { + myClock = getInterfaceOfType(Clock.class); + } + return myClock; + } + + /** + * Returns the IP address interface (if any). + * + * @return IPAddress interface + */ + public IPAddress getIPAddress() { + if (myIPAddress == null) { + myIPAddress = getInterfaceOfType(IPAddress.class); + } + return myIPAddress; + } + + /** + * Returns the LED interface (if any). + * + * @return LED interface + */ + public LED getLED() { + if (myLED == null) { + myLED = getInterfaceOfType(LED.class); + } + return myLED; + } + + /** + * Returns the log interface (if any). + * + * @return Log interface + */ + public Log getLog() { + if (myLog == null) { + myLog = getInterfaceOfType(Log.class); + } + return myLog; + } + + /** + * Returns the mote ID interface (if any). + * + * @return Mote ID interface + */ + public MoteID getMoteID() { + if (myMoteID == null) { + myMoteID = getInterfaceOfType(MoteID.class); + } + return myMoteID; + } + + /** + * Returns the PIR interface (if any). + * + * @return PIR interface + */ + public PIR getPIR() { + if (myPIR == null) { + myPIR = getInterfaceOfType(PIR.class); + } + return myPIR; + } + + /** + * Returns the position interface (if any). + * + * @return Position interface + */ + public Position getPosition() { + if (myPosition == null) { + myPosition = getInterfaceOfType(Position.class); + } + return myPosition; + } + + /** + * Returns the radio interface (if any). + * + * @return Radio interface + */ + public Radio getRadio() { + if (myRadio == null) { + myRadio = getInterfaceOfType(Radio.class); + } + return myRadio; + } + + /** + * Polls all active interfaces. This method should be called during a mote + * tick before the mote software is executed. + */ + public void doActiveActionsBeforeTick() { + for (int i = 0; i < myActiveInterfaces.size(); i++) + myActiveInterfaces.get(i).doActionsBeforeTick(); + } + + /** + * Polls all active interfaces. This method should be called during a mote + * tick after the mote software has executed. + */ + public void doActiveActionsAfterTick() { + for (int i = 0; i < myActiveInterfaces.size(); i++) + myActiveInterfaces.get(i).doActionsAfterTick(); + } + + /** + * Polls all passive interfaces. This method should be called during a mote + * tick before the mote software is executed. + */ + public void doPassiveActionsBeforeTick() { + for (int i = 0; i < myPassiveInterfaces.size(); i++) + myPassiveInterfaces.get(i).doActionsBeforeTick(); + } + + /** + * Polls all passive interfaces. This method should be called during a mote + * tick after the mote software has executed. + */ + public void doPassiveActionsAfterTick() { + for (int i = 0; i < myPassiveInterfaces.size(); i++) + myPassiveInterfaces.get(i).doActionsAfterTick(); + } + + /** + * Returns all passive mote interfaces. + * + * @return All passive mote interface + */ + public Vector getAllPassiveInterfaces() { + return myPassiveInterfaces; + } + + /** + * Returns all active mote interfaces. + * + * @return All active mote interface + */ + public Vector getAllActiveInterfaces() { + return myActiveInterfaces; + } + + /** + * Add an active interface to corresponding mote. An active interface is only + * allowed to act if the mote is in active state. However, since interfaces + * may awaken a sleeping mote up via external interrupts, most of the + * interfaces should be active. + * + * For example a button interface should be active. When the button is + * pressed, the interface will wake the mote up (simulated external + * interrupt), and then that button will be allowed to act before next tick. + * + * A passive interface is an interface which will always act if the mote is + * not dead. For example a battery should always be allowed to act since a + * mote needs energy even if it is in sleep mode. + * + * @see #addPassiveInterface(MoteInterface) + * @param newInterface + * New interface + */ + public void addActiveInterface(MoteInterface newInterface) { + myActiveInterfaces.add(newInterface); + } + + /** + * Add a passive interface to corresponding mote. For explanation of passive + * vs active interfaces, see addActiveInterface(MoteInterface). + * + * @see #addActiveInterface(MoteInterface) + * @param newInterface + * New interface + */ + public void addPassiveInterface(MoteInterface newInterface) { + myPassiveInterfaces.add(newInterface); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/MoteMemory.java b/tools/cooja/java/se/sics/cooja/MoteMemory.java new file mode 100644 index 000000000..3f69b93b0 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/MoteMemory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2006, 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: MoteMemory.java,v 1.1 2006/08/21 12:12:55 fros4943 Exp $ + */ + +package se.sics.cooja; + +/** + * This interface represents a mote memory. + * + * Mote memory is represented by byte arrays and this + * interface provides a few of basic operations. + * + * Note that this memory internally may consist of several + * different memory sections, not covering the entire range + * between the start address and the end address of this memory. + * + * @author Fredrik Osterlind + */ +public interface MoteMemory { + + /** + * Clears the entire memory. + */ + public void clearMemory(); + + /** + * Returns a memory segment. + * + * @param address Start address of memory segment + * @param size Size of memory segment + * @return Memory segment or null if segment not available + */ + public byte[] getMemorySegment(int address, int size); + + /** + * Sets a memory segment. + * + * @param address Start address of memory segment + * @param data Data + */ + public void setMemorySegment(int address, byte[] data); + + /** + * Returns the sum of all byte array sizes in this memory. + * This is not neccessarily the the same as the total memory range, + * since the entire memory range may not be handled by this memory. + * + * @return Total size + */ + public int getTotalSize(); + +} diff --git a/tools/cooja/java/se/sics/cooja/MoteType.java b/tools/cooja/java/se/sics/cooja/MoteType.java new file mode 100644 index 000000000..7242dd5cb --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/MoteType.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2006, 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: MoteType.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.util.Collection; +import javax.swing.JFrame; +import javax.swing.JPanel; +import org.jdom.Element; + +/** + * Every simulated motes belongs to a mote type. + * + * The mote type defines properties common for several motes. These properties + * may differ between different implementations, but typically includes how a + * mote of that type is initialized, which hardware peripherals each mote has + * etc. + * + * A mote type may also hold the connection to an underlying simulation + * framework. + * + * @author Fredrik Osterlind + */ +public interface MoteType { + + /** + * Returns the mote type description. + * + * @return Description + */ + public String getDescription(); + + /** + * Sets the mote type description. + * + * @param description + * New description + */ + public void setDescription(String description); + + /** + * Returns the mote type identifier. + * + * @return Mote type identifier + */ + public String getIdentifier(); + + /** + * Sets the mote type identifier. + * + * @param identifier + * New identifier + */ + public void setIdentifier(String identifier); + + /** + * Returns a panel with interesting data for this mote type. + * + * @return Mote type visualizer + */ + public JPanel getTypeVisualizer(); + + /** + * Returns this mote type's platform configuration. + * + * @return Platform configuration + */ + public PlatformConfig getConfig(); + + /** + * Generates a mote of this mote type. + * + * @param simulation + * Newly created mote's simulation + * @return New mote + */ + public Mote generateMote(Simulation simulation); + + /** + * This method configures and initializes a mote type ready to be used. It is + * called from the simulator when a new mote type is created. It may simply + * confirm that all settings are valid and return true, or display a dialog + * allowing a user to manually configure the mote type. + * + * This method need normally only be run once per mote type! + * + * @param parentFrame + * Parent frame or null + * @param simulation + * Simulation holding (or that should hold) mote type + * @return True if mote type has valid settings and is ready to be used + */ + public boolean configureAndInit(JFrame parentFrame, Simulation simulation); + + /** + * Returns XML elements representing the current config of this mote type. + * This is fetched by the simulator for example when saving a simulation + * configuration file. For example a Contiki base directory may be saved. + * + * @see #setConfigXML(Simulation, Collection) + * @return XML elements representing the current mote type's config + */ + public Collection getConfigXML(); + + /** + * Sets the current mote type config depending on the given XML elements. + * Observe that this method is responsible for restoring the configuration + * depending on the given arguments. This may include recompiling and loading + * libraries. + * + * @see #getConfigXML() + * @param simulation + * Simulation that will hold the mote type + * @param configXML + * Config XML elements + * @return True if config was set successfully, false otherwise + */ + public boolean setConfigXML(Simulation simulation, + Collection configXML); + +} diff --git a/tools/cooja/java/se/sics/cooja/PassiveMoteInterface.java b/tools/cooja/java/se/sics/cooja/PassiveMoteInterface.java new file mode 100644 index 000000000..fc4aa0989 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/PassiveMoteInterface.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006, 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: PassiveMoteInterface.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja; + +/** + * Mote interfaces are divided into active and passive interfaces. + * + * A passive mote interface is treated different than an ordinary (active) + * mote interface; + * Passive interfaces are allowed to act even when the mote is sleeping, + * while active interface only acts when the mote is in active state. + * + * A typical active interface is the radio interface, since radio + * messages only can be received when the mote is active. + * + * A typical passive interface is the battery interface, since a mote + * consumes energy even though it is sleeping. + * + * All passive interface should implement this interface. + * All interfaces not implemented this interface will be handled as active interfaces. + * + * Any energy required by this interface must be available after the + * doActionsBeforeTick method. + * + * @author Fredrik Osterlind + */ +public interface PassiveMoteInterface { + +} diff --git a/tools/cooja/java/se/sics/cooja/PlatformConfig.java b/tools/cooja/java/se/sics/cooja/PlatformConfig.java new file mode 100644 index 000000000..64cd7156d --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/PlatformConfig.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2006, 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: PlatformConfig.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.io.*; +import java.util.*; +import org.apache.log4j.Logger; + +/** + * A platform configuration may hold the configuration for one or several user + * platforms as well as a general simulator configuration. + * + * The configuration for a user platform may for example consist of which + * plugins, interfaces and processes that the specific platform supplies. Each + * user platform configuration is read from the property file cooja.config, a + * file which is required in each user platform. + * + * Values can be fetched as String, Boolean, Integer, Double or String array. + * + * Several configurations can be merged, together forming a final overall + * configuration. The order of the how configurations are merged matter - later + * values will overwrite earlier. For example merging two configurations with + * the key 'SOMEKEY' in the following order: + * + * SOMEKEY = a b c + * + * SOMEKEY = d e + * + * will result in the final value "d e". + * + * If a specific value should be extended instead of overwritten, the value must + * start with a single space-surrounded '+'. For example, merging two + * configurations with the key as above in the following order: + * + * SOMEKEY = a b c + * + * SOMEKEY = + d e + * + * will result in the final value "a b c d e". + * + * The simulator will hold a merged platform configuration, depending on which + * user platforms are used. Additionally. each mote type may also have a + * configuration of its own, that differs from the general simulator + * configuration. + * + * Often, but not necessarily, keys are named depending on which class is + * associated with the information. For example, let's say a battery interface + * wants to store its initial capacity (a double) using this approach. Data + * stored in the external configuration file can look like the following: + * se.sics.cooja.interfaces.Battery.initial_capacity 54.123321 + * + * This value is then be read by: myMoteTypeConfig.getDoubleValue(Battery.class, + * "initial_capacity"); + * + * @author Fredrik Osterlind + */ +public class PlatformConfig { + private static Logger logger = Logger.getLogger(PlatformConfig.class); + + private Properties myConfig = new Properties(); + + /** + * Creates a new empty platform configuration. + */ + public PlatformConfig() { + myConfig = new Properties(); + } + + /** + * Loads the given property file and appends it to the current configuration. + * If a property already exists it will be overwritten, unless the new value + * begins with a '+' in which case the old value will be extended. + * + * @param propertyFile + * Property file to read + * @return True if file was read ok, false otherwise + * @throws FileNotFoundException + * If file was not found + * @throws IOException + * Stream read error + */ + public boolean appendConfig(File propertyFile) throws FileNotFoundException, + IOException { + return appendConfig(myConfig, propertyFile); + } + + private static boolean appendConfig(Properties currentValues, + File propertyFile) throws FileNotFoundException, IOException { + // Open file + FileInputStream in = new FileInputStream(propertyFile); + return appendConfig(currentValues, in); + } + + /** + * Reads propertues from the given stream and appends them to the current + * configuration. If a property already exists it will be overwritten, unless + * the new value begins with a '+' in which case the old value will be + * extended. + * + * @param configFileStream + * Stream to read from + * @return True if stream was read ok, false otherwise + * @throws IOException + * Stream read error + */ + public boolean appendConfig(InputStream configFileStream) throws IOException { + return appendConfig(myConfig, configFileStream); + } + + private static boolean appendConfig(Properties currentValues, + InputStream configFileStream) throws IOException { + + // Read from stream + Properties newProps = new Properties(); + newProps.load(configFileStream); + configFileStream.close(); + + // Read new properties + Enumeration en = newProps.keys(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + String property = newProps.getProperty(key); + if (property.startsWith("+ ")) { + if (currentValues.getProperty(key) != null) + currentValues.setProperty(key, currentValues.getProperty(key) + " " + property.substring(1).trim()); + else + currentValues.setProperty(key, property.substring(1).trim()); + } else + currentValues.setProperty(key, property); + } + + return true; + } + + /** + * @return All property names in configuration + */ + public Enumeration getPropertyNames() { + return (Enumeration) myConfig.propertyNames(); + } + + /** + * Get string value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @param defaultValue + * Default value to return if id is not found + * @return Value or defaultValue if id wasn't found + */ + public String getStringValue(Class callingClass, String id, + String defaultValue) { + return getStringValue(myConfig, callingClass, id, defaultValue); + } + + private static String getStringValue(Properties currentValues, + Class callingClass, String id, String defaultValue) { + String val = currentValues.getProperty(callingClass.getName() + "." + id); + + if (val == null) { + logger.warn("Could not find key named '" + callingClass.getName() + "." + id + "'"); + return defaultValue; + } + + return val; + } + + /** + * Returns value of given name. + * + * @param name + * Name + * @return Value as string + */ + public String getStringValue(String name) { + if (!myConfig.containsKey(name)) + logger.debug("Could not find key named '" + name + "'"); + + return myConfig.getProperty(name); + } + + /** + * Get string value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @return Value or null if id wasn't found + */ + public String getStringValue(Class callingClass, String id) { + return getStringValue(callingClass, id, null); + } + + /** + * Get string array value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @return Value or null if id wasn't found + */ + public String[] getStringArrayValue(Class callingClass, String id) { + String stringVal = getStringValue(callingClass, id, null); + if (stringVal == null) + return new String[0]; + + return getStringValue(callingClass, id, "").split(" "); + } + + /** + * Get string value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @return Value or null if id wasn't found + */ + public String getValue(Class callingClass, String id) { + return getStringValue(callingClass, id); + } + + /** + * Get integer value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @param defaultValue + * Default value to return if id is not found + * @return Value or defaultValue if id wasn't found + */ + public int getIntegerValue(Class callingClass, String id, int defaultValue) { + String str = getStringValue(callingClass, id); + if (str == null) + return defaultValue; + + return Integer.parseInt(str); + } + + /** + * Get integer value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @return Value or 0 if id wasn't found + */ + public int getIntegerValue(Class callingClass, String id) { + return getIntegerValue(callingClass, id, 0); + } + + /** + * Get double value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @param defaultValue + * Default value to return if id is not found + * @return Value or defaultValue if id wasn't found + */ + public double getDoubleValue(Class callingClass, String id, + double defaultValue) { + String str = getStringValue(callingClass, id); + if (str == null) + return defaultValue; + + return Double.parseDouble(str); + } + + /** + * Get double value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @return Value or 0.0 if id wasn't found + */ + public double getDoubleValue(Class callingClass, String id) { + return getDoubleValue(callingClass, id, 0.0); + } + + /** + * Get boolean value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @param defaultValue + * Default value to return if id is not found + * @return Value or defaultValue if id wasn't found + */ + public boolean getBooleanValue(Class callingClass, String id, + boolean defaultValue) { + String str = getStringValue(callingClass, id); + if (str == null) + return defaultValue; + + return Boolean.parseBoolean(str); + } + + /** + * Get boolean value with given id. + * + * @param callingClass + * Class which value belongs to + * @param id + * Id of value to return + * @return Value or false if id wasn't found + */ + public boolean getBooleanValue(Class callingClass, String id) { + return getBooleanValue(callingClass, id, false); + } + + public PlatformConfig clone() { + PlatformConfig clone = new PlatformConfig(); + clone.myConfig = (Properties) this.myConfig.clone(); + return clone; + } +} diff --git a/tools/cooja/java/se/sics/cooja/Positioner.java b/tools/cooja/java/se/sics/cooja/Positioner.java new file mode 100644 index 000000000..6c6968a69 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/Positioner.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006, 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: Positioner.java,v 1.1 2006/08/21 12:12:51 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.lang.reflect.Constructor; +import org.apache.log4j.Logger; + +/** + * A positioner is used for determining positions of newly created motes. + * + * @author Fredrik Osterlind + */ +public abstract class Positioner { + private static Logger logger = Logger.getLogger(Positioner.class); + + /** + * This method creates an instance of the given class with the given interval + * information as constructor arguments. Instead of calling the constructors + * directly this method may be used. + * + * @param positionerClass + * Positioner class + * @param totalNumberOfMotes + * Total number of motes that should be generated using this + * positioner + * @param startX + * Lowest X value of positions generated using returned positioner + * @param endX + * Highest X value of positions generated using returned positioner + * @param startY + * Lowest Y value of positions generated using returned positioner + * @param endY + * Highest Y value of positions generated using returned positioner + * @param startZ + * Lowest Z value of positions generated using returned positioner + * @param endZ + * Highest Z value of positions generated using returned positioner + * @return Postioner instance + */ + public static final Positioner generateInterface( + Class positionerClass, int totalNumberOfMotes, + double startX, double endX, double startY, double endY, double startZ, + double endZ) { + try { + // Generating positioner + Constructor constr = positionerClass.getConstructor(new Class[]{ + int.class, double.class, double.class, double.class, double.class, + double.class, double.class}); + return (Positioner) constr.newInstance(new Object[]{totalNumberOfMotes, + startX, endX, startY, endY, startZ, endZ}); + } catch (Exception e) { + logger.fatal("Exception when creating " + positionerClass + ": " + e); + return null; + } + } + + /** + * Returns the next mote position. + * + * @return Position + */ + public abstract double[] getNextPosition(); + +} diff --git a/tools/cooja/java/se/sics/cooja/RadioConnection.java b/tools/cooja/java/se/sics/cooja/RadioConnection.java new file mode 100644 index 000000000..63b4c6524 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/RadioConnection.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2006, 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: RadioConnection.java,v 1.1 2006/08/21 12:12:55 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.util.Vector; + +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; + +/** + * RadioConnection represents a radio connection between a sending radio + * and zero or more receiving radios. + * By registering as an observer to the current radio medium, all + * radio connections and data sent in that medium can be accessed. + * + * Each radio is associated with a position and some radio data. + * Often the destinations' and source's data will refer to the same object, + * but some radio mediums may want to distort the transferred data, hence + * resulting in different data sent and received. + * + * @see RadioMedium + * @author Fredrik Osterlind + */ +public class RadioConnection { + private Radio sourceRadio; + private Position sourcePosition; + private byte[] sourceData; + + private Vector destinationRadios = new Vector(); + private Vector destinationPositions = new Vector(); + private Vector destinationData = new Vector(); + + /** + * Set source of this connection. + * + * @param radio Source radio + * @param position Source position + * @param data Source data + */ + public void setSource(Radio radio, Position position, byte[] data) { + sourceRadio = radio; + sourcePosition = position; + sourceData = data; + } + + /** + * Add a connection destination. + * + * @param radio Source radio + * @param position Source position + * @param data Source data + */ + public void addDestination(Radio radio, Position position, byte[] data) { + destinationRadios.add(radio); + destinationPositions.add(position); + destinationData.add(data); + } + + /** + * @return Source radio + */ + public Radio getSourceRadio() { + return sourceRadio; + } + + /** + * @return Source position + */ + public Position getSourcePosition() { + return sourcePosition; + } + + /** + * Returns the data actually sent by source radio. + * @return Source data + */ + public byte[] getSourceData() { + return sourceData; + } + + /** + * @return Array of destination radios + */ + public Radio[] getDestinationRadios() { + Radio[] radioArrayType; + Radio[] radioArray; + + radioArrayType = new Radio[destinationRadios.size()]; + radioArray = (Radio[]) destinationRadios.toArray(radioArrayType); + + return radioArray; + } + + /** + * @return Array of destination positions + */ + public Position[] getDestinationPositons() { + Position[] positionArrayType; + Position[] positionArray; + + positionArrayType = new Position[destinationPositions.size()]; + positionArray = (Position[]) destinationPositions.toArray(positionArrayType); + + return positionArray; + } + + /** + * Returns an array of data actually received by each radio. + * @return Array of destination data + */ + public byte[][] getDestinationData() { + byte[][] dataArrayType; + byte[][] dataArray; + + dataArrayType = new byte[destinationData.size()][]; + dataArray = (byte[][]) destinationData.toArray(dataArrayType); + + return dataArray; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/RadioMedium.java b/tools/cooja/java/se/sics/cooja/RadioMedium.java new file mode 100644 index 000000000..6af056dcf --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/RadioMedium.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2006, 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: RadioMedium.java,v 1.1 2006/08/21 12:12:55 fros4943 Exp $ + */ + +package se.sics.cooja; +import java.util.Collection; +import java.util.Observer; + +import org.jdom.Element; + +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; + +/** + * This interface represents a radio medium. Radios registered to this medium + * can both send and receive radio data. Depending on the implementation of this + * interface, more or less accurate radio behaviour imitation is aquired. + * + * Often a radio medium, at initialization, registers one or several dynamic + * plugins. These plugins shows the user some radio medium specific details, + * such as radio transmission radius etc. + * + * @author Fredrik Osterlind + */ +public abstract class RadioMedium { + + /** + * Registers a mote to this medium. + * + * How radio data will be received from and sent to this mote depends on the + * medium implementation. Common factors may be random, distance from sending + * to receiving mote and interference with other radio transmitters in some + * range. + * + * @param mote + * Mote to register + * @param sim + * Simulation holding mote + */ + public abstract void registerMote(Mote mote, Simulation sim); + + /** + * Unregisters a mote from this medium. + * + * @param mote + * Mote to unregister + * @param sim + * Simulation holding mote + */ + public abstract void unregisterMote(Mote mote, Simulation sim); + + /** + * Register a radio to this medium at a given position. + * + * Concerning radio data, this radio will be treated the same way as a mote's + * radio. This method can be used to add non-mote radio devices, such as a + * packet generator or a sniffer. + * + * @param radio + * Radio + * @param position + * Position + * @param sim + * Simulation holding radio + */ + public abstract void registerRadioInterface(Radio radio, Position position, + Simulation sim); + + /** + * Unregisters a radio interface from this medium. + * + * @param radio + * Radio interface to unregister + * @param sim + * Simulation holding radio + */ + public abstract void unregisterRadioInterface(Radio radio, Simulation sim); + + /** + * Adds an observer which is notified after the radio connections has been + * calculated. Often a radio medium is a tick observer and makes these + * calculations after each tick loop. A radio medium observer may then gather + * network data by being notified every time the radio medium has delivered + * data. The radio medium observable MUST notify observers every time the + * getLastTickConnections returns a new value, even if the new value is null. + * + * @see #getLastTickConnections() + * @see #deleteRadioMediumObserver(Observer) + * @param observer + * New observer + */ + public abstract void addRadioMediumObserver(Observer observer); + + /** + * Deletes an radio medium observer. + * + * @see #addRadioMediumObserver(Observer) + * @param observer + * Observer to delete + */ + public abstract void deleteRadioMediumObserver(Observer observer); + + /** + * Returns all connections made during last tick loop. + * + * Typically a radio medium is a tick observer and transfers data between + * radios after each tick loop. When these calculations are finished, it will + * in turn notify all radio medium observers. A radio medium observer may get + * information about which connections were made by using this method. Observe + * that this method may return null of no connections were made. + * + * @see RadioConnection + * @return All connections made during last tick loop or null if none + */ + public abstract RadioConnection[] getLastTickConnections(); + + /** + * Set an overall connection logger. This logger will see all connections in + * the radio medium. + * + * @param logger + * New overall connection logger. + */ + public abstract void setConnectionLogger(ConnectionLogger logger); + + /** + * Returns XML elements representing the current config of this radio medium. + * This is fetched by the simulator for example when saving a simulation + * configuration file. For example a radio medium may return user altered + * range parameters. This method should however not return state specific + * information such as a current radio status. (All nodes are restarted when + * loading a simulation.) + * + * @see #setConfigXML(Collection) + * @return XML elements representing the current radio medium config + */ + public abstract Collection getConfigXML(); + + /** + * Sets the current radio medium config depending on the given XML elements. + * + * @see #getConfigXML() + * @param configXML + * Config XML elements + * @return True if config was set successfully, false otherwise + */ + public abstract boolean setConfigXML(Collection configXML); + +} diff --git a/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java b/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java new file mode 100644 index 000000000..9f51a708a --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2006, 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: SectionMoteMemory.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.MoteMemory; + +/** + * Represents a mote memory consisting of non-overlapping + * memory sections. This memory also contains information + * about variable starts addresses. + *

+ * When an unhandled memory segment is set a new section is + * automatically created for this segment. + *

+ * @author Fredrik Osterlind + */ +public class SectionMoteMemory implements MoteMemory { + private static Logger logger = Logger.getLogger(SectionMoteMemory.class); + + private Vector sections = new Vector(); + private final Properties variableAddresses; + + /** + * Create a new mote memory with information about which + * variables exist and their relative memory addresses. + * + * @param variableAddresses Variable addresses + */ + public SectionMoteMemory(Properties variableAddresses) { + this.variableAddresses = variableAddresses; + } + + /** + * @return All variable names known and residing in this memory + */ + public String[] getVariableNames() { + String[] names = new String[variableAddresses.size()]; + Enumeration nameEnum = variableAddresses.keys(); + for (int i=0; i < variableAddresses.size(); i++) { + names[i] = (String) nameEnum.nextElement(); + } + return names; + } + + public void clearMemory() { + sections.clear(); + } + + public byte[] getMemorySegment(int address, int size) { + for (int i=0; i < sections.size(); i++) { + if (sections.elementAt(i).includesAddr(address) && sections.elementAt(i).includesAddr(address + size - 1)) { + return sections.elementAt(i).getMemorySegment(address, size); + } + } + return null; + } + + public void setMemorySegment(int address, byte[] data) { + // TODO Creating overlapping memory sections possible + for (int i=0; i < sections.size(); i++) { + if (sections.elementAt(i).includesAddr(address) && sections.elementAt(i).includesAddr(address + data.length - 1)) { + sections.elementAt(i).setMemorySegment(address, data); + return; + } + } + sections.add(new MoteMemorySection(address, data)); + } + + public int getTotalSize() { + int totalSize = 0; + for (MoteMemorySection section: sections) + totalSize += section.getSize(); + return totalSize; + } + + /** + * Returns the total number of sections in this memory. + * + * @return Number of sections + */ + public int getNumberOfSections() { + return sections.size(); + } + + /** + * Removes a memory segment from this memory. + * The section containing the segment may be split into two sections. + * + * @param startAddr Start address + * @param size Length + */ + public void removeSegmentFromMemory(int startAddr, int size) { + for (MoteMemorySection section: sections) + // Find section containing segment to remove + if (section.includesAddr(startAddr) && + section.includesAddr(startAddr + size - 1)) { + MoteMemorySection oldSection = section; + + byte[] dataFirstPart = oldSection.getMemorySegment( + oldSection.startAddr, + (int) (startAddr - oldSection.startAddr) + ); + byte[] dataSecondPart = oldSection.getMemorySegment( + startAddr + size, + (int) (oldSection.startAddr + oldSection.getSize() - (startAddr + size))); + + MoteMemorySection newSectionFirstPart = new MoteMemorySection(oldSection.startAddr, dataFirstPart); + MoteMemorySection newSectionSecondPart = new MoteMemorySection(startAddr + size, dataSecondPart); + + // Remove old section, add new sections + sections.remove(oldSection); + if (newSectionFirstPart.getSize() > 0) + sections.add(newSectionFirstPart); + if (newSectionSecondPart.getSize() > 0) + sections.add(newSectionSecondPart); + } + } + + + /** + * Get start address of section at given position. + * + * @param sectionNr Section position + * @return Start address of section + */ + public int getStartAddrOfSection(int sectionNr) { + if (sectionNr >= sections.size()) + return 0; + + return sections.elementAt(sectionNr).getStartAddr(); + } + + /** + * Get size of section at given position. + * + * @param sectionNr Section position + * @return Size of section + */ + public int getSizeOfSection(int sectionNr) { + if (sectionNr >= sections.size()) + return 0; + + return sections.elementAt(sectionNr).getSize(); + } + + /** + * Get data of section at given position. + * + * @param sectionNr Section position + * @return Data at section + */ + public byte[] getDataOfSection(int sectionNr) { + if (sectionNr >= sections.size()) + return null; + + return sections.elementAt(sectionNr).getData(); + } + + /** + * Returns a value of the integer variable with the given name. + * + * @param varName Name of integer variable + * @return Value of integer variable + */ + public int getIntValueOf(String varName) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) + return -1; + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + byte[] varData = getMemorySegment(varAddr, 4); + + int retVal = 0; + int pos = 0; + retVal += ((int) (varData[pos++] & 0xFF)) << 24; + retVal += ((int) (varData[pos++] & 0xFF)) << 16; + retVal += ((int) (varData[pos++] & 0xFF)) << 8; + retVal += ((int) (varData[pos++] & 0xFF)) << 0; + + // TODO Check if small/big-endian when coming from JNI? + retVal = Integer.reverseBytes(retVal); + + return retVal; + } + + /** + * Set integer value of variable with given name. + * + * @param varName Name of integer variable + * @param newVal New value to set + */ + public void setIntValueOf(String varName, int newVal) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) + return; + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + // TODO Check if small/big-endian when coming from JNI? + int newValToSet = Integer.reverseBytes(newVal); + + // Create byte array + int pos = 0; + + byte[] varData = new byte[4]; + varData[pos++] = (byte) ((newValToSet & 0xFF000000) >> 24); + varData[pos++] = (byte) ((newValToSet & 0xFF0000) >> 16); + varData[pos++] = (byte) ((newValToSet & 0xFF00) >> 8); + varData[pos++] = (byte) ((newValToSet & 0xFF) >> 0); + + setMemorySegment(varAddr, varData); + } + + /** + * Returns a value of the byte variable with the given name. + * + * @param varName Name of byte variable + * @return Value of byte variable + */ + public byte getByteValueOf(String varName) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) + return -1; + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + byte[] varData = getMemorySegment(varAddr, 1); + + return varData[0]; + } + + /** + * Set byte value of variable with given name. + * + * @param varName Name of byte variable + * @param newVal New value to set + */ + public void setByteValueOf(String varName, byte newVal) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) + return; + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + byte[] varData = new byte[1]; + + varData[0] = newVal; + + setMemorySegment(varAddr, varData); + } + + /** + * Returns byte array of given length and with the given name. + * + * @param varName Name of array + * @param length Length of array + * @return Data of array + */ + public byte[] getByteArray(String varName, int length) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) + return null; + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + // TODO Check if small/big-endian when coming from JNI? + return getMemorySegment(varAddr, length); + } + + /** + * Set byte array of the variable with the given name. + * + * @param varName Name of array + * @param data New data of array + */ + public void setByteArray(String varName, byte[] data) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) + return; + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + // TODO Check if small/big-endian when coming from JNI? + setMemorySegment(varAddr, data); + } + + /** + * A memory section represented of a byte array and a start address. + * + * @author Fredrik Osterlind + */ + private class MoteMemorySection { + private byte[] data = null; + private int startAddr; + + /** + * Create a new memory section. + * + * @param startAddr Start address of section + * @param data Data of section + */ + public MoteMemorySection(int startAddr, byte[] data) { + this.startAddr = startAddr; + this.data = data; + } + + /** + * Returns start address of this memory section. + * + * @return Start address + */ + public int getStartAddr() { + return startAddr; + } + + /** + * Returns size of this memory section. + * + * @return Size + */ + public int getSize() { + return data.length; + } + + /** + * Returns the entire byte array which defines this section. + * + * @return Byte array + */ + public byte[] getData() { + return data; + } + + /** + * True if given address is part of this memory section. + * + * @param addr Address + * @return True if given address is part of this memory section, false otherwise + */ + public boolean includesAddr(int addr) { + if (data == null) + return false; + + return (addr >= startAddr && addr < (startAddr + data.length)); + } + + /** + * Returns memory segment. + * + * @param addr Start address of memory segment + * @param size Size of memory segment + * @return Memory segment + */ + public byte[] getMemorySegment(int addr, int size) { + byte[] ret = new byte[size]; + for (int i = 0; i < size; i++) + ret[i] = data[(int) (addr - startAddr + i)]; + return ret; + } + + /** + * Sets a memory segment. + * @param addr Start of memory segment + * @param data Data of memory segment + */ + public void setMemorySegment(int addr, byte[] data) { + int nonnull=0; + for (int i = 0; i < data.length; i++) { + if (data[i] != 0) nonnull++; + this.data[(int) (addr - startAddr + i)] = data[i]; + } + } + + public MoteMemorySection clone() { + byte[] dataClone = new byte[data.length]; + for (int i=0; i < data.length; i++) + dataClone[i] = data[i]; + + MoteMemorySection clone = new MoteMemorySection(startAddr, dataClone); + return clone; + } + + } + + + // EXPERIMENTAL AND DEBUG METHODS + public SectionMoteMemory clone() { + Vector clonedSections = new Vector(); + for (int i=0; i < sections.size(); i++) { + clonedSections.add((MoteMemorySection) sections.elementAt(i).clone()); + } + + SectionMoteMemory clone = new SectionMoteMemory(variableAddresses); + clone.sections = clonedSections; + + return clone; + } + + protected byte[] getChecksum() { + MessageDigest messageDigest; + try { + messageDigest = MessageDigest.getInstance("MD5"); + + for (int i=0; i < sections.size(); i++) { + messageDigest.update(sections.get(i).data, 0, sections.get(i).getSize()); + } + } catch (NoSuchAlgorithmException e) { + return null; + } + return messageDigest.digest(); + } + + protected Vector getDifferenceAddressesOf(SectionMoteMemory anotherMem) { + Vector differences = new Vector(); + + if (this.getNumberOfSections() != anotherMem.getNumberOfSections()) { + logger.fatal("Number of section do not match!"); + return null; + } + + for (int i=0; i < sections.size(); i++) { + if (this.getSizeOfSection(i) != anotherMem.getSizeOfSection(i)) { + logger.fatal("Section " + i + " sizes do not match!"); + return null; + } + if (this.getStartAddrOfSection(i) != anotherMem.getStartAddrOfSection(i)) { + logger.fatal("Section " + i + " start addresses do not match!"); + return null; + } + + for (int j=0; j < sections.get(i).getSize(); j++) + if (this.sections.get(i).data[j] != anotherMem.getDataOfSection(i)[j]) + differences.add(new Integer(sections.get(i).startAddr + j)); + System.err.println(); + } + return differences; + } + + protected void printMemory() { + for (int i=0; i < sections.size(); i++) { + System.err.print("Section[" + i + "]: "); + for (int j=0; j < sections.get(i).getSize(); j++) + System.err.print(sections.get(i).getData()[j] + ","); + System.err.println(); + } + } + + protected void printDifferences(SectionMoteMemory anotherMem) { + if (this.getNumberOfSections() != anotherMem.getNumberOfSections()) { + logger.fatal("Number of section do not match!"); + return; + } + + for (int i=0; i < sections.size(); i++) { + if (this.getSizeOfSection(i) != anotherMem.getSizeOfSection(i)) { + logger.fatal("Section " + i + " sizes do not match!"); + return; + } + if (this.getStartAddrOfSection(i) != anotherMem.getStartAddrOfSection(i)) { + logger.fatal("Section " + i + " start addresses do not match!"); + return; + } + + System.err.print("Section[" + i + "]: "); + for (int j=0; j < sections.get(i).getSize(); j++) + if (this.sections.get(i).data[j] != anotherMem.getDataOfSection(i)[j]) + System.err.print(j + ","); + System.err.println(); + } + } + + protected void printChecksum() { + byte[] checksum = this.getChecksum(); + System.err.print("Checksum: "); + for (int i=0; i < checksum.length; i++) { + System.err.print(checksum[i] + ","); + } + System.err.println(); + } + + + +} diff --git a/tools/cooja/java/se/sics/cooja/Simulation.java b/tools/cooja/java/se/sics/cooja/Simulation.java new file mode 100644 index 000000000..da42c58fe --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/Simulation.java @@ -0,0 +1,735 @@ +/* + * Copyright (c) 2006, 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: Simulation.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.io.*; +import java.util.*; + +import org.apache.log4j.Logger; +import org.jdom.*; +import org.jdom.input.SAXBuilder; +import org.jdom.output.Format; +import org.jdom.output.XMLOutputter; + +import se.sics.cooja.dialogs.*; + +/** + * A simulation contains motes and ticks them one by one. When all motes has + * been ticked once, the simulation sleeps for some specified time, and the + * current simulation time is updated. Some observers (tick observers) are also + * notified. + * + * When observing the simulation itself, the simulation state, added or deleted + * motes etc are observed, as opposed to individual mote changes. Changes of + * individual motes should instead be observed via corresponding mote + * interfaces. + * + * @author Fredrik Osterlind + */ +public class Simulation extends Observable implements Runnable { + + private Vector motes = new Vector(); + private Vector moteTypes = new Vector(); + + private int delayTime = 100; + private int currentSimulationTime = 0; + private int tickTime = 1; + private String title = null; + + // Radio Medium + private RadioMedium currentRadioMedium = null; + + private static Logger logger = Logger.getLogger(Simulation.class); + + private boolean isRunning = false; + private boolean stopSimulation = false; + private Thread thread = null; + + // Tick observable + private class TickObservable extends Observable { + private void allTicksPerformed() { + setChanged(); + notifyObservers(); + } + } + private TickObservable tickObservable = new TickObservable(); + + /** + * Add tick observer. This observer is notified once every tick loop, that is, + * when all motes have been ticked. + * + * @see #deleteTickObserver(Observer) + * @param newObserver + * New observer + */ + public void addTickObserver(Observer newObserver) { + tickObservable.addObserver(newObserver); + } + + /** + * Delete an existing tick observer. + * + * @see #addTickObserver(Observer) + * @param observer + * Observer to delete + */ + public void deleteTickObserver(Observer observer) { + tickObservable.deleteObserver(observer); + } + + public void run() { + long lastStartTime = System.currentTimeMillis(); + logger.info("Simulation main loop started, system time: " + lastStartTime); + isRunning = true; + + // Notify observers simulation is starting + this.setChanged(); + this.notifyObservers(this); + + while (isRunning) { + try { + // Tick all motes + for (Mote moteToTick : motes) { + moteToTick.tick(currentSimulationTime); + } + + // Increase simulation time + currentSimulationTime += tickTime; + + // Notify tick observers + tickObservable.allTicksPerformed(); + + // Sleep + if (delayTime > 0) + Thread.sleep(delayTime); + + if (stopSimulation) { + // We should only tick once (and we just did), so abort now + stopSimulation = false; + isRunning = false; + thread = null; + } + + } catch (InterruptedException e) { + isRunning = false; + thread = null; + break; + } catch (IllegalArgumentException e) { + logger.warn("llegalArgumentException:" + e); + isRunning = false; + thread = null; + break; + } catch (IllegalMonitorStateException e) { + logger.warn("IllegalMonitorStateException:" + e); + isRunning = false; + thread = null; + break; + } + } + + isRunning = false; + thread = null; + stopSimulation = false; + + // Notify observers simulation has stopped + this.setChanged(); + this.notifyObservers(this); + + logger.info("Simulation main loop stopped, system time: " + + System.currentTimeMillis() + "\tDuration: " + + (System.currentTimeMillis() - lastStartTime) + " ms"); + } + + /** + * Creates a new simulation with a delay time of 1 second. + */ + public Simulation() { + // New simulation instance + + // logger.fatal("WARNING ADDING 10000 BLINKER NODES NOW!!!"); + // for (int i=0; i < 10000; i++) + // addMote(new BlinkerNode()); + + } + + /** + * Starts this simulation (notifies observers). + */ + public void startSimulation() { + if (!isRunning()) { + thread = new Thread(this); + thread.start(); + } + } + + /** + * Stops this simulation (notifies observers). + */ + public void stopSimulation() { + if (isRunning()) { + stopSimulation = true; + thread.interrupt(); + + // Wait until simulation stops + if (Thread.currentThread() != thread) + while (thread != null && thread.isAlive()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + } // else logger.fatal("Could not stop simulation: isRunning=" + isRunning + + // ", thread=" + thread); + } + + /** + * Starts simulation if stopped, ticks all motes once, and finally stop + * simulation again. + */ + public void tickSimulation() { + stopSimulation = true; + + if (!isRunning()) { + thread = new Thread(this); + thread.start(); + } + + // Wait until simulation stops + while (thread != null && thread.isAlive()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + + } + + /** + * Loads a simulation configuration from given file. + * + * When loading mote types, user must recompile the actual library of each + * type. User may also change mote type settings at this point. + * + * @see #saveSimulationConfig(File) + * @param file + * File to read + * @return New simulation or null if recompiling failed or aborted + * @throws UnsatisfiedLinkError + * If associated libraries could not be loaded + */ + public static Simulation loadSimulationConfig(File file) + throws UnsatisfiedLinkError { + + Simulation newSim = null; + + try { + // Open config file + SAXBuilder builder = new SAXBuilder(); + Document doc = builder.build(file); + Element root = doc.getRootElement(); + + // Check that config file version is correct + if (!root.getName().equals("simulation")) { + logger.fatal("Not a COOJA simulation config xml file!"); + return null; + } + + // Build new simulation + Collection config = root.getChildren(); + newSim = new Simulation(); + boolean createdOK = newSim.setConfigXML(config); + if (!createdOK) { + logger.info("Simulation not loaded"); + return null; + } + + } catch (JDOMException e) { + logger.fatal("File not wellformed: " + e.getMessage()); + return null; + } catch (IOException e) { + logger.fatal("No access to file: " + e.getMessage()); + return null; + } catch (Exception e) { + logger.fatal("Exception when loading file: " + e); + e.printStackTrace(); + return null; + } + + return newSim; + } + + /** + * Saves current simulation configuration to given file and notifies + * observers. + * + * @see #loadSimulationConfig(File file) + * @see #getConfigXML() + * @param file + * File to write + */ + public void saveSimulationConfig(File file) { + + try { + // Create simulation XML + Element root = new Element("simulation"); + root.addContent(getConfigXML()); + + // Create config + Document doc = new Document(root); + + // Write to file + FileOutputStream out = new FileOutputStream(file); + XMLOutputter outputter = new XMLOutputter(); + outputter.setFormat(Format.getPrettyFormat()); + outputter.output(doc, out); + + out.close(); + + logger.info("Saved to file: " + file.getAbsolutePath()); + } catch (Exception e) { + logger.warn("Exception while saving simulation config: " + e); + } + + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Returns the current simulation config represented by XML elements. This + * config also includes the current radio medium, all mote types and motes. + * + * @see #saveSimulationConfig(File file) + * @return Current simulation config + */ + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // Title + element = new Element("title"); + element.setText(title); + config.add(element); + + // Delay time + element = new Element("delaytime"); + element.setText(Integer.toString(delayTime)); + config.add(element); + + // Simulation time + element = new Element("simtime"); + element.setText(Integer.toString(currentSimulationTime)); + config.add(element); + + // Tick time + element = new Element("ticktime"); + element.setText(Integer.toString(tickTime)); + config.add(element); + + // Radio Medium + element = new Element("radiomedium"); + element.setText(currentRadioMedium.getClass().getName()); + + Collection radioMediumXML = currentRadioMedium.getConfigXML(); + if (radioMediumXML != null) + element.addContent(radioMediumXML); + config.add(element); + + // Mote types + for (MoteType moteType : getMoteTypes()) { + element = new Element("motetype"); + element.setText(moteType.getClass().getName()); + + Collection moteTypeXML = moteType.getConfigXML(); + if (moteTypeXML != null) + element.addContent(moteTypeXML); + config.add(element); + } + + // Motes + for (Mote mote : motes) { + element = new Element("mote"); + element.setText(mote.getClass().getName()); + + Collection moteXML = mote.getConfigXML(); + if (moteXML != null) + element.addContent(moteXML); + config.add(element); + } + + return config; + } + + /** + * Sets the current simulation config depending on the given XML elements. + * + * @see #getConfigXML() + * @param configXML + * Config XML elements + */ + public boolean setConfigXML(Collection configXML) throws Exception { + + // Parse elements + for (Element element : configXML) { + + // Title + if (element.getName().equals("title")) { + title = element.getText(); + } + + // Delay time + if (element.getName().equals("delaytime")) { + delayTime = Integer.parseInt(element.getText()); + } + + // Simulation time + if (element.getName().equals("simtime")) { + currentSimulationTime = Integer.parseInt(element.getText()); + } + + // Tick time + if (element.getName().equals("ticktime")) { + tickTime = Integer.parseInt(element.getText()); + } + + // Radio medium + if (element.getName().equals("radiomedium")) { + String radioMediumClassName = element.getText().trim(); + Class radioMediumClass = GUI.currentGUI + .tryLoadClass(this, RadioMedium.class, radioMediumClassName); + + if (radioMediumClass != null) + // Create radio medium specified in config + currentRadioMedium = radioMediumClass.newInstance(); + else + logger.warn("Could not find radio medium class: " + + radioMediumClassName); + + // Show configure simulation dialog + boolean createdOK = CreateSimDialog.showDialog(GUI.frame, this); + + if (!createdOK) { + logger.debug("Simulation not created, aborting"); + throw new Exception("Load aborted by user"); + } + + // Check if radio medium specific config should be applied + if (radioMediumClassName + .equals(currentRadioMedium.getClass().getName())) { + currentRadioMedium.setConfigXML(element.getChildren()); + } else { + logger + .info("Radio Medium changed - ignoring radio medium specific config"); + } + } + + // Mote type + if (element.getName().equals("motetype")) { + String moteTypeClassName = element.getText().trim(); + + Class moteTypeClass = GUI.currentGUI.tryLoadClass( + this, MoteType.class, moteTypeClassName); + + if (moteTypeClass == null) { + logger.fatal("Could not load mote type class: " + moteTypeClassName); + return false; + } + + MoteType moteType = moteTypeClass.getConstructor((Class[]) null) + .newInstance(); + + boolean createdOK = moteType.setConfigXML(this, element.getChildren()); + if (createdOK) { + addMoteType(moteType); + } else { + logger + .fatal("Mote type was not created: " + element.getText().trim()); + throw new Exception("All mote types were not recreated"); + } + } + + // Mote + if (element.getName().equals("mote")) { + Class moteClass = GUI.currentGUI.tryLoadClass(this, + Mote.class, element.getText().trim()); + + Mote mote = moteClass.getConstructor((Class[]) null).newInstance(); + if (mote.setConfigXML(this, element.getChildren())) { + addMote(mote); + } else { + logger.fatal("Mote was not created: " + element.getText().trim()); + throw new Exception("All motes were not recreated"); + } + } + } + + return true; + } + + /** + * Removes a mote from this simulation + * + * @param mote + * Mote to remove + */ + public void removeMote(Mote mote) { + if (isRunning()) { + stopSimulation(); + motes.remove(mote); + startSimulation(); + } else + motes.remove(mote); + + currentRadioMedium.unregisterMote(mote, this); + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Adds a mote to this simulation + * + * @param mote + * Mote to add + */ + public void addMote(Mote mote) { + if (isRunning()) { + stopSimulation(); + motes.add(mote); + startSimulation(); + } else + motes.add(mote); + + currentRadioMedium.registerMote(mote, this); + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Get a mote from this simulation. + * + * @param pos + * Position of mote + * @return Mote + */ + public Mote getMote(int pos) { + return motes.get(pos); + } + + /** + * Returns number of motes in this simulation. + * + * @return Number of motes + */ + public int getMotesCount() { + return motes.size(); + } + + /** + * Returns all mote types in simulation. + * + * @return All mote types + */ + public Vector getMoteTypes() { + return moteTypes; + } + + /** + * Returns mote type with given identifier. + * + * @param identifier + * Mote type identifier + * @return Mote type or null if not found + */ + public MoteType getMoteType(String identifier) { + for (MoteType moteType : getMoteTypes()) { + if (moteType.getIdentifier().equals(identifier)) + return moteType; + } + return null; + } + + /** + * Adds given mote type to simulation. + * + * @param newMoteType + */ + public void addMoteType(MoteType newMoteType) { + moteTypes.add(newMoteType); + + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Set delay time to delayTime. When all motes have been ticked, the + * simulation waits for this time before ticking again. + * + * @param delayTime + * New delay time (ms) + */ + public void setDelayTime(int delayTime) { + this.delayTime = delayTime; + + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Returns current delay time. + * + * @return Delay time (ms) + */ + public int getDelayTime() { + return delayTime; + } + + /** + * Set simulation time to simulationTime. + * + * @param simulationTime + * New simulation time (ms) + */ + public void setSimulationTime(int simulationTime) { + currentSimulationTime = simulationTime; + + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Returns current simulation time. + * + * @return Simulation time (ms) + */ + public int getSimulationTime() { + return currentSimulationTime; + } + + /** + * Set tick time to tickTime. The tick time is the simulated time every tick + * takes. When all motes have been ticked, current simulation time is + * increased with tickTime. Default tick time is 1 ms. + * + * @see #getTickTime() + * @see #getTickTimeInSeconds() + * @param tickTime + * New tick time (ms) + */ + public void setTickTime(int tickTime) { + this.tickTime = tickTime; + + this.setChanged(); + this.notifyObservers(this); + } + + /** + * Changes radio medium of this simulation to the given. + * + * @param radioMedium + * New radio medium + */ + public void setRadioMedium(RadioMedium radioMedium) { + // Remove current radio medium from observing motes + if (currentRadioMedium != null) + for (int i = 0; i < motes.size(); i++) + currentRadioMedium.unregisterMote(motes.get(i), this); + + // Change current radio medium to new one + if (radioMedium == null) { + logger.fatal("Radio medium could not be created!"); + return; + } + this.currentRadioMedium = radioMedium; + + // Add all current motes to be observered by new radio medium + for (int i = 0; i < motes.size(); i++) + currentRadioMedium.registerMote(motes.get(i), this); + } + + /** + * Get currently used radio medium. + * + * @return Currently used radio medium + */ + public RadioMedium getRadioMedium() { + return currentRadioMedium; + } + + /** + * Get current tick time (ms). + * + * @see #setTickTime(int) + * @return Current tick time (ms) + */ + public int getTickTime() { + return tickTime; + } + + /** + * Get current tick time (seconds). + * + * @see #setTickTime(int) + * @return Current tick time (seconds) + */ + public double getTickTimeInSeconds() { + return ((double) tickTime) / 1000.0; + } + + /** + * Return true is simulation is running. + * + * @return True if simulation is running + */ + public boolean isRunning() { + return isRunning && thread != null; + } + + /** + * Get current simulation title (short description). + * + * @return Title + */ + public String getTitle() { + return title; + } + + /** + * Set simulation title. + * + * @param title + * New title + */ + public void setTitle(String title) { + this.title = title; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/VisPlugin.java b/tools/cooja/java/se/sics/cooja/VisPlugin.java new file mode 100644 index 000000000..3afc48ccc --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/VisPlugin.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006, 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: VisPlugin.java,v 1.1 2006/08/21 12:12:56 fros4943 Exp $ + */ + +package se.sics.cooja; + +import javax.swing.JInternalFrame; +import javax.swing.event.InternalFrameEvent; +import javax.swing.event.InternalFrameListener; + +/** + * Abstract class VisPlugin should be implemented by plugins for COOJA Simulator. + * By extending JInternalFrame, the visual apperence is decided by the plugin itself. + * + * An implemented plugin should be registered at runtime using the following method: + * GUI.registerPlugin(Class, String) + * + * For example how to implement a plugin see classes SimControl or Vis2D. + * + * @author Fredrik Osterlind + */ +public abstract class VisPlugin extends JInternalFrame { + + /** + * Sets frame title + * @param title Frame title + */ + public VisPlugin(String title) { + super(title, true, true, true, true); + final VisPlugin thisPlugin = this; + + // Close via gui + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + // Detect frame events + addInternalFrameListener(new InternalFrameListener() { + public void internalFrameClosing(InternalFrameEvent e) { + GUI.currentGUI.removePlugin(thisPlugin, true); + } + public void internalFrameClosed(InternalFrameEvent e) { + // NOP + } + public void internalFrameOpened(InternalFrameEvent e) { + // NOP + } + public void internalFrameIconified(InternalFrameEvent e) { + // NOP + } + public void internalFrameDeiconified(InternalFrameEvent e) { + // NOP + } + public void internalFrameActivated(InternalFrameEvent e) { + // NOP + } + public void internalFrameDeactivated(InternalFrameEvent e) { + // NOP + } + } + ); + } + + /** + * This method is called when an opened plugin is about to close. + * It should release any resources such as registered observers or + * opened interface visualizers. + */ + public abstract void closePlugin(); + +} diff --git a/tools/cooja/java/se/sics/cooja/VisPluginType.java b/tools/cooja/java/se/sics/cooja/VisPluginType.java new file mode 100644 index 000000000..e30f62519 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/VisPluginType.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006, 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: VisPluginType.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation type to describe a plugin type. + * + * @author Fredrik Osterlind + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface VisPluginType { + public static final int UNDEFINED_PLUGIN = 0; + + /** + * Mote Plugin + * + * A mote plugin concerns one specific mote. + * + * An example of such a plugin may be to display + * some mote information in a frame. + * + * Mote plugins can not be instantiated from the + * regular menu bar, but are instead started from + * other plugins, for example a visualizer that let's + * a user select a mote. + * + * When constructed, a mote plugin is given a Mote. + * + * If the current simulation is removed, so are + * all instances of this plugin. + */ + public static final int MOTE_PLUGIN = 1; + + /** + * Simulation Plugin + * + * A simulation plugin concerns one specific simulation. + * + * An example of such a plugin may be to display + * number of motes and current simulation time in a window. + * + * Simulation plugins are available via the plugins menubar. + * + * When constructed, a simulation plugin is given the current + * active simulation. + * + * If the current simulation is removed, so are + * all instances of this plugin. + */ + public static final int SIM_PLUGIN = 2; + + /** + * GUI Plugin + * + * A GUI plugin does not depend on the current simulation to function. + * + * An example of such a plugin may be a control panel + * where a user can control the current simulation. + * + * GUI plugins are available via the plugins menubar. + * + * When constructed, a GUI plugin is given the current GUI. + */ + public static final int GUI_PLUGIN = 3; + + /** + * Simulation Standard Plugin + * + * This is treated exactly like a Simulation Plugin, with the + * only difference that this will automatically be opened + * when a new simulation is created. + */ + public static final int SIM_STANDARD_PLUGIN = 4; + + int value(); +} + diff --git a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java new file mode 100644 index 000000000..0c2edb5ae --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2006, 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: ContikiMote.java,v 1.1 2006/08/21 12:13:10 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote; + +import java.util.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; + +/** + * A Contiki mote executes an actual Contiki system via + * a loaded shared library and JNI. + * It contains a section mote memory, a mote interface handler and a + * Contiki mote type. + * + * The mote type is responsible for the connection to the loaded + * Contiki system. + * + * When ticked a Contiki mote polls all interfaces, copies the mote + * memory to the core, lets the Contiki system handle one event, + * fetches the updated memory and finally polls all interfaces again. + * The mote state is also updated during a mote tick. + * + * @author Fredrik Osterlind + */ +public class ContikiMote implements Mote { + private static Logger logger = Logger.getLogger(ContikiMote.class); + + private ContikiMoteType myType = null; + private SectionMoteMemory myMemory = null; + private MoteInterfaceHandler myInterfaceHandler = null; + private Simulation mySim = null; + + // Time to wake up if sleeping + private int wakeUpTime = 0; + + private int myState = STATE_ACTIVE; + + // State observable + private class StateObservable extends Observable { + private void stateChanged() { + setChanged(); + notifyObservers(); + } + } + private StateObservable stateObservable = new StateObservable(); + + + /** + * Creates a new uninitialized Contiki mote. + * + * This mote needs at least a type, a memory, a mote interface handler + * and to be connected to a simulation. + */ + public ContikiMote() { + } + + /** + * Creates a new mote of given type. + * Both the initial mote memory and the interface handler + * are supplied from the mote type. + * + * @param moteType Mote type + * @param sim Mote's simulation + */ + public ContikiMote(ContikiMoteType moteType, Simulation sim) { + this.mySim = sim; + this.myType = moteType; + this.myMemory = moteType.createInitialMemory(); + this.myInterfaceHandler = new MoteInterfaceHandler((Mote) this, moteType.getMoteInterfaces()); + + myState = STATE_ACTIVE; + } + + public void setState(int newState) { + if (myState == STATE_DEAD) { + return; + } + + if (myState == STATE_ACTIVE && newState != STATE_ACTIVE) { + myState = newState; + stateObservable.stateChanged(); + } + + if (myState == STATE_LPM && newState != STATE_LPM) { + myState = newState; + stateObservable.stateChanged(); + } + } + + public int getState() { + return myState; + } + + public void addStateObserver(Observer newObserver) { + stateObservable.addObserver(newObserver); + } + + public void deleteStateObserver(Observer newObserver) { + stateObservable.deleteObserver(newObserver); + } + + public MoteInterfaceHandler getInterfaces() { + return myInterfaceHandler; + } + + public void setInterfaces(MoteInterfaceHandler newInterfaces) { + myInterfaceHandler = newInterfaces; + } + + public MoteMemory getMemory() { + return myMemory; + } + + public void setMemory(MoteMemory memory) { + myMemory = (SectionMoteMemory) memory; + } + + public MoteType getType() { + return myType; + } + + public void setType(MoteType type) { + myType = (ContikiMoteType) type; + } + + public Simulation getSimulation() { + return mySim; + } + + public void setSimulation(Simulation simulation) { + mySim = simulation; + } + + /** + * Ticks this mote once. This is done by first polling all interfaces + * and letting them act on the stored memory before the memory is set. Then + * the mote is ticked, and the new memory is received. + * Finally all interfaces are allowing to act on the new memory in order to + * discover relevant changes. This method also checks if mote should go to sleep + * depending on Contiki specifics; pending timers and polled processes. + * + * @param simTime Current simulation time + */ + public void tick(int simTime) { + + // If mote is dead, do nothing at all + if (getState() == STATE_DEAD) + return; + + // If mote is sleeping and has a wake up time, should it wake up now? + if (getState() == STATE_LPM && wakeUpTime > 0 && wakeUpTime <= simTime) { + setState(STATE_ACTIVE); + wakeUpTime = 0; + } + + // If mote is active.. + if (getState() == STATE_ACTIVE) { + // Let all active interfaces act before tick + // Observe that each interface may put the mote to sleep at this point + myInterfaceHandler.doActiveActionsBeforeTick(); + } + + // And let passive interfaces act even if mote is sleeping + myInterfaceHandler.doPassiveActionsBeforeTick(); + + + // If mote is still active, complete this tick + if (getState() == STATE_ACTIVE) { + + // Copy mote memory to core + myType.setCoreMemory(myMemory); + + // Tick node + myType.tick(); + + // Fetch new updated memory from core + myType.getCoreMemory(myMemory); + + // Let all active interfaces act again after tick + myInterfaceHandler.doActiveActionsAfterTick(); + + } + + // Finally let all passive interfaces act + myInterfaceHandler.doPassiveActionsAfterTick(); + + // If mote is awake, should it go to sleep? + if (getState() == STATE_ACTIVE) { + // Check if this mote should sleep (no more pending timers or processes to poll) + int processRunValue = myMemory.getIntValueOf("simProcessRunValue"); + int etimersPending = myMemory.getIntValueOf("simEtimerPending"); + int nextExpirationTime = myMemory.getIntValueOf("simNextExpirationTime"); + + if (processRunValue == 0 && etimersPending == 0) { + setState(STATE_LPM); + wakeUpTime = 0; + } + + if (processRunValue == 0 && etimersPending == 1 && nextExpirationTime > 0) { + setState(STATE_LPM); + wakeUpTime = nextExpirationTime; + } + + } + } + + /** + * Returns the current Contiki mote config represented by XML elements. + * This config also includes all mote interface configs. + * + * @return Current simulation config + */ + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // Mote type identifier + element = new Element("motetype_identifier"); + element.setText(getType().getIdentifier()); + config.add(element); + + // Active interface configs (if any) + for (MoteInterface moteInterface: getInterfaces().getAllActiveInterfaces()) { + element = new Element("interface_config"); + element.setText(moteInterface.getClass().getName()); + + Collection interfaceXML = moteInterface.getConfigXML(); + if (interfaceXML != null) { + element.addContent(interfaceXML); + config.add(element); + } + } + + // Passive interface configs (if any) + for (MoteInterface moteInterface: getInterfaces().getAllPassiveInterfaces()) { + element = new Element("interface_config"); + element.setText(moteInterface.getClass().getName()); + + Collection interfaceXML = moteInterface.getConfigXML(); + if (interfaceXML != null) { + element.addContent(interfaceXML); + config.add(element); + } + } + + return config; + } + + public boolean setConfigXML(Simulation simulation, Collection configXML) { + mySim = simulation; + myState = STATE_ACTIVE; + + for (Element element: configXML) { + String name = element.getName(); + + if (name.equals("motetype_identifier")) { + myType = (ContikiMoteType) simulation.getMoteType(element.getText()); + myMemory = myType.createInitialMemory(); + myInterfaceHandler = new MoteInterfaceHandler((Mote) this, myType.getMoteInterfaces()); + + } else if (name.equals("interface_config")) { + Class moteInterfaceClass = + GUI.currentGUI.tryLoadClass(this, MoteInterface.class, element.getText().trim()); + + if (moteInterfaceClass == null) { + logger.fatal("Could not load mote interface class: " + element.getText().trim()); + return false; + } + + MoteInterface moteInterface = myInterfaceHandler.getInterfaceOfType(moteInterfaceClass); + moteInterface.setConfigXML(element.getChildren()); + } + } + + return true; + } + + public String toString() { + if (getInterfaces().getMoteID() != null) { + return "Contiki Mote, ID=" + getInterfaces().getMoteID().getMoteID(); + } else + return "Contiki Mote, ID=null"; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteInterface.java b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteInterface.java new file mode 100644 index 000000000..71ecc13e4 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteInterface.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006, 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: ContikiMoteInterface.java,v 1.1 2006/08/21 12:13:09 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote; + +/** + * A Contiki mote interface has information about which, if any, core interfaces + * it needs. + * + * All classes implementing this interface should also define a static method: + * public String[] getCoreInterfaceDependencies() { + * ... + * } + * + * The method should return the names of all needed core interfaces. + * + * @author Fredrik Osterlind + */ +public interface ContikiMoteInterface { +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java new file mode 100644 index 000000000..74798d798 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java @@ -0,0 +1,898 @@ +/* + * Copyright (c) 2006, 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: ContikiMoteType.java,v 1.1 2006/08/21 12:13:09 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.io.*; +import java.security.*; +import java.util.*; +import java.util.regex.*; +import javax.swing.*; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; + +/** + * The Contiki mote type holds the native library used to communicate with an + * underlying Contiki system. All communication with that system should always + * pass through this mote type. + *

+ * This type also contains information about which processes, sensors and core + * interfaces a mote of this type has, as well as where the Contiki OS, COOJA + * core files and an optional user platform are located. + *

+ * All core communication with the Contiki mote should be via this class. When a + * mote type is created it allocates a CoreComm to be used with this type, and + * loads a map file. The map file is used to map variable names to addresses. + *

+ * When a new mote type is created an initialization function is run on the + * Contiki system in order to create the initial memory. When a new mote is + * created the createInitialMemory() method should be called to get this initial + * memory for the mote. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Contiki Mote Type") +public class ContikiMoteType implements MoteType { + private static Logger logger = Logger.getLogger(ContikiMoteType.class); + + /** + * Map file suffix + */ + final static public String mapSuffix = ".map"; + + /** + * Library file suffix + */ + final static public String librarySuffix = ".library"; + + /** + * Make dependency file suffix + */ + final static public String dependSuffix = ".a"; + + /** + * Temporary output directory + */ + final static public File tempOutputDirectory = new File("." + File.separatorChar + "obj_cooja" + File.separatorChar); + + // Regular expressions for parsing the map file + final static private String bssSectionAddrRegExp = "^.bss[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String bssSectionSizeRegExp = "^.bss[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String dataSectionAddrRegExp = "^.data[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$"; + final static private String dataSectionSizeRegExp = "^.data[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$"; + final static private String varAddressRegExpPrefix = "^[ \t]*0x([0-9A-Fa-f]*)[ \t]*"; + final static private String varAddressRegExpSuffix = "[ \t]*$"; + final static private String varNameRegExp = "^[ \t]*(0x[0-9A-Fa-f]*)[ \t]*([^ ]*)[ \t]*$"; + final static private String varSizeRegExpPrefix = "^"; + final static private String varSizeRegExpSuffix = "[ \t]*(0x[0-9A-Fa-f]*)[ \t]*[^ ]*[ \t]*$"; + + // Mote type specific data + private String identifier = null; + private String description = null; + private String contikiBaseDir = null; + private String contikiCoreDir = null; + private Vector userPlatformDirs = null; + private Vector processes = null; + private Vector sensors = null; + private Vector coreInterfaces = null; + private Vector> moteInterfaces = null; + + // Simulation holding this mote type + private Simulation mySimulation = null; + + // Type specific class configuration + private PlatformConfig myConfig = null; + + // Core communication variables + private String libraryClassName = null; + private int offsetRelToAbs = 0; + private CoreComm myCoreComm = null; + + // Variable name to address mappings + private Properties varAddresses = new Properties(); + + // Map file contents + private Vector mapContents = new Vector(); + + // Initial memory for all motes of this type + private SectionMoteMemory initialMemory = null; + + /** + * Creates a new uninitialized Contiki mote type. This mote type needs to load + * a library file and parse a map file before it can be used. + */ + public ContikiMoteType() { + } + + /** + * Creates a new Contiki mote type. This type uses two external files: a map + * file for parsing relative addresses of Contiki variables (identifier + + * ".map") and a library file with an actual compiled Contiki system + * (identifier + ".library") + * + * @param identifier + * Unique identifier for this mote type + */ + public ContikiMoteType(String identifier) { + doInit(identifier); + } + + public Mote generateMote(Simulation simulation) { + return new ContikiMote(this, simulation); + } + + public boolean configureAndInit(JFrame parentFrame, Simulation simulation) { + return ContikiMoteTypeDialog.showDialog(parentFrame, simulation, this); + } + + /** + * This is an mote type initialization method and should normally never be + * called by any other part than the mote type constructor. It is called from + * the constructor with an identifier argument. but not from the standard + * constructor. This method may be called from the simulator when loading + * configuration files, and the libraries must be recompiled. + * + * This method allocates a core communicator, loads the Contiki library file, + * loads and parses the map file, creates a variable name to address mapping + * of the Contiki system and finally creates the Contiki mote initial memory. + * + * @param identifier + * Mote type identifier + * @return True if initialization ok, false otherwise + */ + protected boolean doInit(String identifier) { + this.identifier = identifier; + + if (myCoreComm != null) { + logger + .fatal("Core communicator not null. Is library already loaded? Aborting"); + return false; + } + + File libFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + librarySuffix); + File mapFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + mapSuffix); + + // Check that library file exists + if (!libFile.exists()) { + logger.fatal("Library file could not be found: " + libFile); + return false; + } + + // Check that map file exists + if (!mapFile.exists()) { + logger.fatal("Map file could not be found: " + mapFile); + return false; + } + + // Allocate core communicator class + libraryClassName = CoreComm.getAvailableClassName(); + myCoreComm = CoreComm.createCoreComm(libraryClassName, libFile); + + // Load map file + mapContents = loadMapFile(mapFile); + if (mapContents == null) { + logger.fatal("Map file could not be loaded: " + mapFile); + return false; + } + + // Load variable addresses from Contiki system + varAddresses.clear(); + Vector varNames = getAllVariableNames(); + for (String varName : varNames) { + int varAddress = getRelVarAddress(varName); + if (varAddress > 0) { + varAddresses.put(varName, new Integer(varAddress)); + } else + logger.warn("Parsed Contiki variable '" + varName + + "' but could not find address"); + } + + // Get offset between relative and absolute addresses + offsetRelToAbs = getReferenceAbsAddr() + - getRelVarAddr(mapContents, "referenceVar"); + + // Parse addresses of data and BSS memory sections + int relDataSectionAddr = loadRelDataSectionAddr(mapContents); + int dataSectionSize = loadDataSectionSize(mapContents); + int relBssSectionAddr = loadRelBssSectionAddr(mapContents); + int bssSectionSize = loadBssSectionSize(mapContents); + + if (relDataSectionAddr <= 0 || dataSectionSize <= 0 + || relBssSectionAddr <= 0 || bssSectionSize <= 0) { + logger.fatal("Could not parse section addresses correctly"); + return false; + } + + // Create initial memory + byte[] initialDataSection = getCoreMemory(relDataSectionAddr + + offsetRelToAbs, dataSectionSize); + byte[] initialBssSection = getCoreMemory( + relBssSectionAddr + offsetRelToAbs, bssSectionSize); + initialMemory = new SectionMoteMemory(varAddresses); + initialMemory.setMemorySegment(relDataSectionAddr, initialDataSection); + initialMemory.setMemorySegment(relBssSectionAddr, initialBssSection); + + return false; + } + + /** + * Ticks the currently loaded mote. This should not be used directly, but + * rather via ContikiMote.tick(). + */ + public void tick() { + myCoreComm.tick(); + } + + /** + * Creates and returns a copy of this mote type's initial memory (just after + * the init function has been run). When a new mote is created it should get + * it's memory from here. + * + * @return Initial memory of a mote type + */ + public SectionMoteMemory createInitialMemory() { + return initialMemory.clone(); + } + + /** + * Copy given memory to the Contiki system. This should not be used directly, + * but instead via ContikiMote.setMemory(). + * + * @param mem + * New memory + */ + public void setCoreMemory(SectionMoteMemory mem) { + for (int i = 0; i < mem.getNumberOfSections(); i++) { + setCoreMemory(mem.getStartAddrOfSection(i) + offsetRelToAbs, mem + .getSizeOfSection(i), mem.getDataOfSection(i)); + } + } + + /** + * Copy core memory to given memory. This should not be used directly, but + * instead via ContikiMote.getMemory(). + * + * @param mem + * Memory to set + */ + public void getCoreMemory(SectionMoteMemory mem) { + for (int i = 0; i < mem.getNumberOfSections(); i++) { + int startAddr = mem.getStartAddrOfSection(i); + int size = mem.getSizeOfSection(i); + mem.setMemorySegment(startAddr, getCoreMemory(startAddr + offsetRelToAbs, + size)); + } + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + logger.warn("Contiki mote type is read-only"); + } + + /** + * @return Contiki mote type's library class name + */ + public String getLibraryClassName() { + return libraryClassName; + } + + /** + * Get relative address of variable with given name. + * + * @param varName + * Name of variable + * @return Relative memory address of variable or -1 if not found + */ + protected int getRelVarAddress(String varName) { + int varAddr; + String varAddrString; + if ((varAddrString = varAddresses.getProperty(varName)) != null) { + varAddr = Integer.parseInt(varAddrString); + return varAddr; + } + + String regExp = varAddressRegExpPrefix + varName + varAddressRegExpSuffix; + String retString = getFirstMatchGroup(mapContents, regExp, 1); + + if (retString != null) { + varAddresses.setProperty(varName, Integer.toString(Integer.parseInt( + retString.trim(), 16))); + return Integer.parseInt(retString.trim(), 16); + } else + return -1; + } + + private int getReferenceAbsAddr() { + return myCoreComm.getReferenceAbsAddr(); + } + + private byte[] getCoreMemory(int start, int length) { + return myCoreComm.getMemory(start, length); + } + + private void setCoreMemory(int start, int length, byte[] mem) { + myCoreComm.setMemory(start, length, mem); + } + + private static String getFirstMatchGroup(Vector lines, String regexp, + int groupNr) { + Pattern pattern = Pattern.compile(regexp); + for (int i = 0; i < lines.size(); i++) { + Matcher matcher = pattern.matcher(lines.elementAt(i)); + if (matcher.find()) { + return matcher.group(groupNr); + } + } + return null; + } + + /** + * Returns all variable names in both data and BSS section by parsing the map + * file. These values should not be trusted completely as the parsing may + * fail. + * + * @return Variable names found in the data and bss section + */ + public Vector getAllVariableNames() { + + Vector varNames = getAllVariableNames(mapContents, + loadRelDataSectionAddr(mapContents), + loadRelDataSectionAddr(mapContents) + loadDataSectionSize(mapContents)); + + varNames.addAll(getAllVariableNames(mapContents, + loadRelBssSectionAddr(mapContents), loadRelBssSectionAddr(mapContents) + + loadBssSectionSize(mapContents))); + + return varNames; + } + + private Vector getAllVariableNames(Vector lines, + int startAddress, int endAddress) { + Vector varNames = new Vector(); + + Pattern pattern = Pattern.compile(varNameRegExp); + for (int i = 0; i < lines.size(); i++) { + Matcher matcher = pattern.matcher(lines.elementAt(i)); + if (matcher.find()) { + if (Integer.decode(matcher.group(1)).intValue() >= startAddress + && Integer.decode(matcher.group(1)).intValue() <= endAddress) { + varNames.add(matcher.group(2)); + } + } + } + return varNames; + } + + protected int getVariableSize(Vector lines, String varName) { + Pattern pattern = Pattern.compile(varSizeRegExpPrefix + varName + + varSizeRegExpSuffix); + for (int i = 0; i < lines.size(); i++) { + Matcher matcher = pattern.matcher(lines.elementAt(i)); + if (matcher.find()) { + return Integer.decode(matcher.group(1)); + } + } + return -1; + } + + private static int loadRelDataSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else + return 0; + } + + private static int loadDataSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, dataSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else + return 0; + } + + private static int loadRelBssSectionAddr(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionAddrRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else + return 0; + } + + private static int loadBssSectionSize(Vector mapFile) { + String retString = getFirstMatchGroup(mapFile, bssSectionSizeRegExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else + return 0; + } + + private static int getRelVarAddr(Vector mapContents, String varName) { + String regExp = varAddressRegExpPrefix + varName + varAddressRegExpSuffix; + String retString = getFirstMatchGroup(mapContents, regExp, 1); + + if (retString != null) + return Integer.parseInt(retString.trim(), 16); + else + return 0; + } + + private static Vector loadMapFile(File mapFile) { + Vector mapContents = new Vector(); + + try { + BufferedReader in = new BufferedReader(new InputStreamReader( + new FileInputStream(mapFile))); + + while (in.ready()) { + mapContents.add(in.readLine()); + } + } catch (FileNotFoundException e) { + logger.fatal("File not found: " + e); + return null; + } catch (IOException e) { + logger.fatal("IO error: " + e); + return null; + } + + return mapContents; + } + + /** + * Returns simulation holding this mote type + * + * @return Simulation + */ + public Simulation getSimulation() { + return mySimulation; + } + + /** + * Sets simulation holding this mote type + * + * @param simulation + * Simulation holding this mote type + */ + public void setSimulation(Simulation simulation) { + mySimulation = simulation; + } + + public String getDescription() { + return description; + } + + public void setDescription(String newDescription) { + description = newDescription; + } + + /** + * Returns path to contiki base dir + * + * @return String containing path + */ + public String getContikiBaseDir() { + return contikiBaseDir; + } + + /** + * Sets contiki base dir to path. + * + * @param path + * Contiki base dir + */ + public void setContikiBaseDir(String path) { + contikiBaseDir = path; + } + + /** + * Returns path to contiki core dir + * + * @return String containing path + */ + public String getContikiCoreDir() { + return contikiCoreDir; + } + + /** + * Sets contiki core dir to path. + * + * @param path + * Contiki core dir + */ + public void setContikiCoreDir(String path) { + contikiCoreDir = path; + } + + /** + * Returns user platform directories + * + * @return User platform directories + */ + public Vector getUserPlatformDirs() { + return userPlatformDirs; + } + + /** + * Sets user platform directories. + * + * @param dirs + * New user platform directories + */ + public void setUserPlatformDirs(Vector dirs) { + userPlatformDirs = dirs; + } + + public PlatformConfig getConfig() { + return myConfig; + } + + /** + * Sets mote type platform configuration. This may differ from the general + * simulator platform configuration. + * + * @param moteTypeConfig + * Platform configuration + */ + public void setConfig(PlatformConfig moteTypeConfig) { + myConfig = moteTypeConfig; + } + + /** + * Returns all processes of this mote type + * + * @return All processes + */ + public Vector getProcesses() { + return processes; + } + + /** + * Set startup processes + * + * @param processes + * New startup processes + */ + public void setProcesses(Vector processes) { + this.processes = processes; + } + + /** + * Returns all sensors of this mote type + * + * @return All sensors + */ + public Vector getSensors() { + return sensors; + } + + /** + * Set sensors + * + * @param sensors + * New sensors + */ + public void setSensors(Vector sensors) { + this.sensors = sensors; + } + + /** + * Returns all core interfaces of this mote type + * + * @return All core interfaces + */ + public Vector getCoreInterfaces() { + return coreInterfaces; + } + + /** + * Set core interfaces + * + * @param coreInterfaces + * New core interfaces + */ + public void setCoreInterfaces(Vector coreInterfaces) { + this.coreInterfaces = coreInterfaces; + } + + /** + * Returns all mote interfaces of this mote type + * + * @return All mote interfaces + */ + public Vector> getMoteInterfaces() { + return moteInterfaces; + } + + /** + * Set mote interfaces of this mote type + * + * @param moteInterfaces + * New mote interfaces + */ + public void setMoteInterfaces( + Vector> moteInterfaces) { + this.moteInterfaces = moteInterfaces; + } + + /** + * Create a checksum of file. Used for checking if needed files are unchanged + * when loading a saved simulation. + * + * @param file + * File containg data to checksum + * @return Checksum + */ + protected byte[] createChecksum(File file) { + int bytesRead = 1; + byte[] readBytes = new byte[128]; + MessageDigest messageDigest; + + try { + InputStream fileInputStream = new FileInputStream(file); + messageDigest = MessageDigest.getInstance("MD5"); + + while (bytesRead > 0) { + bytesRead = fileInputStream.read(readBytes); + if (bytesRead > 0) + messageDigest.update(readBytes, 0, bytesRead); + } + fileInputStream.close(); + } catch (NoSuchAlgorithmException e) { + return null; + } catch (IOException e) { + return null; + } + return messageDigest.digest(); + } + + /** + * Returns a panel with interesting data for this mote type. + * + * @return Mote type visualizer + */ + public JPanel getTypeVisualizer() { + JPanel panel = new JPanel(); + JLabel label = new JLabel(); + JPanel smallPane; + + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + // Identifier + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Identifier"); + smallPane.add(BorderLayout.WEST, label); + label = new JLabel(identifier); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + // Description + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Description"); + smallPane.add(BorderLayout.WEST, label); + label = new JLabel(description); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + // Contiki dir + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Contiki path"); + smallPane.add(BorderLayout.WEST, label); + label = new JLabel(contikiBaseDir); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + // Library class name + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("JNI Class"); + smallPane.add(BorderLayout.WEST, label); + label = new JLabel(libraryClassName); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + // Processes + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Processes"); + smallPane.add(BorderLayout.WEST, label); + panel.add(smallPane); + + for (String process : processes) { + smallPane = new JPanel(new BorderLayout()); + label = new JLabel(process); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + } + + // Sensors + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Sensors"); + smallPane.add(BorderLayout.WEST, label); + panel.add(smallPane); + + for (String sensor : sensors) { + smallPane = new JPanel(new BorderLayout()); + label = new JLabel(sensor); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + } + + // Core Interfaces + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Core interfaces"); + smallPane.add(BorderLayout.WEST, label); + panel.add(smallPane); + + for (String mInterface : coreInterfaces) { + smallPane = new JPanel(new BorderLayout()); + label = new JLabel(mInterface); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + } + + // Mote Interfaces + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Mote interfaces"); + smallPane.add(BorderLayout.WEST, label); + panel.add(smallPane); + + for (Class moteInterface : moteInterfaces) { + smallPane = new JPanel(new BorderLayout()); + label = new JLabel(moteInterface.getSimpleName()); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + } + + panel.add(Box.createRigidArea(new Dimension(0, 5))); + return panel; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // Identifier + element = new Element("identifier"); + element.setText(getIdentifier()); + config.add(element); + + // Description + element = new Element("description"); + element.setText(getDescription()); + config.add(element); + + // Contiki base directory + element = new Element("contikibasedir"); + element.setText(getContikiBaseDir()); + config.add(element); + + // Contiki core directory + element = new Element("contikicoredir"); + element.setText(getContikiCoreDir()); + config.add(element); + + // User platform directory + for (File userPlatform: userPlatformDirs) { + element = new Element("userplatformdir"); + element.setText(userPlatform.getPath()); + config.add(element); + } + + // Contiki processes + for (String process : getProcesses()) { + element = new Element("process"); + element.setText(process); + config.add(element); + } + + // Contiki sensors + for (String sensor : getSensors()) { + element = new Element("sensor"); + element.setText(sensor); + config.add(element); + } + + // Mote interfaces + for (Class moteInterface : getMoteInterfaces()) { + element = new Element("moteinterface"); + element.setText(moteInterface.getName()); + config.add(element); + } + + // Core interfaces + for (String coreInterface : getCoreInterfaces()) { + element = new Element("coreinterface"); + element.setText(coreInterface); + config.add(element); + } + + return config; + } + + public boolean setConfigXML(Simulation simulation, + Collection configXML) { + userPlatformDirs = new Vector(); + processes = new Vector(); + sensors = new Vector(); + coreInterfaces = new Vector(); + moteInterfaces = new Vector>(); + mySimulation = simulation; + + for (Element element : configXML) { + String name = element.getName(); + + if (name.equals("identifier")) { + identifier = element.getText(); + } else if (name.equals("description")) { + description = element.getText(); + } else if (name.equals("contikibasedir")) { + contikiBaseDir = element.getText(); + } else if (name.equals("contikicoredir")) { + contikiCoreDir = element.getText(); + } else if (name.equals("userplatformdir")) { + userPlatformDirs.add(new File(element.getText())); + } else if (name.equals("process")) { + processes.add(element.getText()); + } else if (name.equals("sensor")) { + sensors.add(element.getText()); + } else if (name.equals("coreinterface")) { + coreInterfaces.add(element.getText()); + } else if (name.equals("moteinterface")) { + Class moteInterfaceClass = + GUI.currentGUI.tryLoadClass(this, MoteInterface.class, element.getText().trim()); + + if (moteInterfaceClass == null) { + logger.warn("Can't find mote interface class: " + element.getText()); + } else + moteInterfaces.add(moteInterfaceClass); + } else { + logger.fatal("Unrecognized entry in loaded configuration: " + name); + } + } + + boolean createdOK = configureAndInit(GUI.frame, simulation); + return createdOK; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteTypeDialog.java b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteTypeDialog.java new file mode 100644 index 000000000..15464caeb --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteTypeDialog.java @@ -0,0 +1,2106 @@ +/* + * Copyright (c) 2006, 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: ContikiMoteTypeDialog.java,v 1.1 2006/08/21 12:13:10 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.regex.*; +import javax.swing.*; +import javax.swing.event.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.UserPlatformsDialog; + +/** + * A dialog for configuring Contiki mote types and compiling Contiki mote type + * libraries. Allows user to change mote type specific data such as + * descriptions, which processes should be started at mote initialization and + * which interfaces the type should support. + * + * The dialog takes a Contiki mote type as argument and pre-selects the values + * already set in that mote type before showing the dialog. Any changes made to + * the settings are written to the mote type if the compilation is successful + * and the user presses OK. + * + * This dialog uses external tools to scan for sources and compile libraries. + * + * @author Fredrik Osterlind + */ +public class ContikiMoteTypeDialog extends JDialog { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(ContikiMoteTypeDialog.class); + + private MoteTypeEventHandler myEventHandler = new MoteTypeEventHandler(); + private Thread compilationThread; + + /** + * Suggested mote type identifier prefix + */ + public static final String ID_PREFIX = "mtype"; + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + private ContikiMoteType myMoteType = null; + + private JTextField textID, textOutputFiles, textDescription, textContikiDir, + textCoreDir, textUserPlatforms; + private JButton createButton, testButton, rescanButton; + + private JPanel processPanel; // Holds process checkboxes + private JPanel sensorPanel; // Holds sensor checkboxes + private JPanel moteInterfacePanel; // Holds mote interface checkboxes + private JPanel coreInterfacePanel; // Holds core interface checkboxes + + private JPanel entireSensorPane; // Holds entire sensor pane (can be hidden) + private JPanel entireCoreInterfacePane; // Holds entire core interface pane + // (can be hidden) + + private boolean settingsOK = false; // Do all settings seem correct? + private boolean compilationSucceded = false; // Did compilation succeed? + private boolean libraryCreatedOK = false; // Was a library created? + + private PlatformConfig newMoteTypeConfig = null; // Mote type platform config + private Vector moteTypeUserPlatforms = new Vector(); // Mote type + // user + // platforms + + private Vector allOtherTypes = null; // Used to check for + // conflicting parameters + + private Frame myParentFrame; + private ContikiMoteTypeDialog myDialog; + + /** + * Shows a dialog for configuring a Contiki mote type and compiling the shared + * library it uses. + * + * @param parentFrame + * Parent frame for dialog + * @param simulation + * Simulation holding (or that will hold) mote type + * @param moteTypeToConfigure + * Mote type to configure + * @return True if compilation succeded and library is ready to be loaded + */ + public static boolean showDialog(Frame parentFrame, Simulation simulation, + ContikiMoteType moteTypeToConfigure) { + + final ContikiMoteTypeDialog myDialog = new ContikiMoteTypeDialog( + parentFrame); + + myDialog.myMoteType = moteTypeToConfigure; + myDialog.allOtherTypes = simulation.getMoteTypes(); + + // Set identifier of mote type + if (moteTypeToConfigure.getIdentifier() != null) { + // Identifier already preset, assuming recompilation of mote type library + // Use preset identifier (read-only) + myDialog.textID.setText(moteTypeToConfigure.getIdentifier()); + myDialog.textID.setEditable(false); + myDialog.textID.setEnabled(false); + + // Change title to indicate this is a recompilation + myDialog.setTitle("Recompile Mote Type"); + } else { + // Suggest new identifier + int counter = 0; + String testIdentifier = ""; + boolean identifierOK = false; + while (!identifierOK) { + counter++; + testIdentifier = ID_PREFIX + counter; + identifierOK = true; + + // Check if identifier is already used by some other type + for (MoteType existingMoteType : myDialog.allOtherTypes) { + if (existingMoteType != myDialog.myMoteType + && existingMoteType.getIdentifier().equals(testIdentifier)) { + identifierOK = false; + break; + } + } + + // Check if library file with given identifier has already been loaded + if (identifierOK + && CoreComm.hasLibraryFileBeenLoaded(new File( + ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + testIdentifier + + ContikiMoteType.librarySuffix))) { + identifierOK = false; + } + } + + myDialog.textID.setText(testIdentifier); + + } + + // Set preset description of mote type + if (moteTypeToConfigure.getDescription() != null) { + myDialog.textDescription.setText(moteTypeToConfigure.getDescription()); + } + + // Set preset Contiki base directory of mote type + if (moteTypeToConfigure.getContikiBaseDir() != null) { + myDialog.textContikiDir.setText(moteTypeToConfigure.getContikiBaseDir()); + } + + // Set preset Contiki core directory of mote type + if (moteTypeToConfigure.getContikiCoreDir() != null) { + myDialog.textCoreDir.setText(moteTypeToConfigure.getContikiCoreDir()); + } + + // Set preset user platform directories of mote type + if (moteTypeToConfigure.getUserPlatformDirs() != null) { + myDialog.moteTypeUserPlatforms = moteTypeToConfigure + .getUserPlatformDirs(); + String userPlatformText = null; + for (File userPlatform : myDialog.moteTypeUserPlatforms) { + if (userPlatformText == null) + userPlatformText = "'" + userPlatform.getPath() + "'"; + else + userPlatformText += ", '" + userPlatform.getPath() + "'"; + } + myDialog.textUserPlatforms.setText(userPlatformText); + } + + // Scan directories for processes, sensors and core interfaces + // TODO Really do this without starting a separate thread? + myDialog.updateVisualFields(); + myDialog.rescanDirectories(); + + // Select preset processes of mote type + if (moteTypeToConfigure.getProcesses() != null) { + for (String presetProcess : moteTypeToConfigure.getProcesses()) { + // Try to find process in current list + boolean foundAndSelectedProcess = false; + for (Component processCheckBox : myDialog.processPanel.getComponents()) { + if (presetProcess.equals(((JCheckBox) processCheckBox).getText())) { + ((JCheckBox) processCheckBox).setSelected(true); + foundAndSelectedProcess = true; + break; + } + } + + // Warn if not found + if (!foundAndSelectedProcess) { + logger.warn("Process was not found in current environment: " + + presetProcess); + } + } + } + + // Select preset sensors + if (moteTypeToConfigure.getSensors() != null) { + // Deselect all sensors already automatically selected + for (Component coreInterfaceCheckBox : myDialog.sensorPanel + .getComponents()) { + ((JCheckBox) coreInterfaceCheckBox).setSelected(false); + } + + for (String presetSensor : moteTypeToConfigure.getSensors()) { + // Try to find sensor in current list + boolean foundAndSelectedSensor = false; + for (Component sensorCheckBox : myDialog.sensorPanel.getComponents()) { + if (presetSensor.equals(((JCheckBox) sensorCheckBox).getText())) { + ((JCheckBox) sensorCheckBox).setSelected(true); + foundAndSelectedSensor = true; + break; + } + } + + // Warn if not found + if (!foundAndSelectedSensor) { + logger.warn("Sensor was not found in current environment: " + + presetSensor); + } + } + } + + // Select preset core interfaces + if (moteTypeToConfigure.getCoreInterfaces() != null) { + // Deselect all core interfaces already automatically selected + for (Component coreInterfaceCheckBox : myDialog.coreInterfacePanel + .getComponents()) { + ((JCheckBox) coreInterfaceCheckBox).setSelected(false); + } + + for (String presetCoreInterface : moteTypeToConfigure.getCoreInterfaces()) { + // Try to find core interface in current list + boolean foundAndSelectedCoreInterface = false; + for (Component coreInterfaceCheckBox : myDialog.coreInterfacePanel + .getComponents()) { + if (presetCoreInterface.equals(((JCheckBox) coreInterfaceCheckBox) + .getText())) { + ((JCheckBox) coreInterfaceCheckBox).setSelected(true); + foundAndSelectedCoreInterface = true; + break; + } + } + + // Warn if not found + if (!foundAndSelectedCoreInterface) { + logger.warn("Core interface was not found in current environment: " + + presetCoreInterface); + } + } + } + + // Select preset mote interfaces + if (moteTypeToConfigure.getMoteInterfaces() != null) { + // Deselect all mote interfaces already automatically selected + for (Component moteInterfaceCheckBox : myDialog.moteInterfacePanel + .getComponents()) { + ((JCheckBox) moteInterfaceCheckBox).setSelected(false); + } + + for (Class presetMoteInterface : moteTypeToConfigure.getMoteInterfaces()) { + // Try to find mote interface in current list + boolean foundAndSelectedMoteInterface = false; + for (Component moteInterfaceCheckBox : myDialog.moteInterfacePanel + .getComponents()) { + Class moteInterfaceClass = (Class) ((JCheckBox) moteInterfaceCheckBox) + .getClientProperty("class"); + + if (presetMoteInterface == moteInterfaceClass) { + ((JCheckBox) moteInterfaceCheckBox).setSelected(true); + foundAndSelectedMoteInterface = true; + break; + } + } + + // Warn if not found + if (!foundAndSelectedMoteInterface) { + logger.warn("Mote interface was not found in current environment: " + + presetMoteInterface); + } + } + } + + // Set position and focus of dialog + myDialog.setLocationRelativeTo(parentFrame); + myDialog.textDescription.requestFocus(); + myDialog.textDescription.select(0, myDialog.textDescription.getText() + .length()); + + myDialog.setVisible(true); + + if (myDialog.myMoteType != null) { + // Library was compiled and loaded + return true; + } + return false; + } + + private ContikiMoteTypeDialog(Frame frame) { + super(frame, "Add Mote Type", true); + + myDialog = this; + myParentFrame = frame; + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + JTextField textField; + JButton button; + + // BOTTOM BUTTON PART + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + button = new JButton("Test current settings"); + button.setActionCommand("testsettings"); + button.addActionListener(myEventHandler); + testButton = button; + this.getRootPane().setDefaultButton(button); + buttonPane.add(button); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + + buttonPane.add(Box.createHorizontalGlue()); + + button = new JButton("Clean intermediate files"); + button.setActionCommand("clean"); + button.addActionListener(myEventHandler); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(button); + + button = new JButton("Cancel"); + button.setActionCommand("cancel"); + button.addActionListener(myEventHandler); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(button); + + button = new JButton("Create"); + button.setEnabled(libraryCreatedOK); + button.setActionCommand("create"); + button.addActionListener(myEventHandler); + createButton = button; + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(button); + + // MAIN PART + + // Identifier + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Identifier"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(); + + textField.setText(""); + + textField.getDocument().addDocumentListener(myEventHandler); + textID = textField; + label.setLabelFor(textField); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(textField); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Output filenames + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Output files"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setText(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ContikiMoteType.mapSuffix + + ", " + ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ContikiMoteType.librarySuffix + + ", " + ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ContikiMoteType.dependSuffix); + textField.setEnabled(false); + textOutputFiles = textField; + label.setLabelFor(textField); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(textField); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Description + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Description"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setBackground(Color.GREEN); + textField.setText("[enter description here]"); + textField.getDocument().addDocumentListener(myEventHandler); + textDescription = textField; + label.setLabelFor(textField); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(textField); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Contiki dir + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Contiki 2.x OS path"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setText(GUI.getExternalToolsSetting("PATH_CONTIKI")); + textField.getDocument().addDocumentListener(myEventHandler); + textContikiDir = textField; + label.setLabelFor(textField); + + button = new JButton("Browse"); + button.setActionCommand("browsecontiki"); + button.addActionListener(myEventHandler); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(textField); + smallPane.add(button); + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // COOJA core platform dir + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Core platform path"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setText(textContikiDir.getText() + + GUI.getExternalToolsSetting("PATH_COOJA_CORE_RELATIVE")); + textField.setEditable(false); + textCoreDir = textField; + label.setLabelFor(textField); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(textField); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // COOJA user platform dir + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Mote type user platforms"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setText(""); + textField.setEditable(false); + textUserPlatforms = textField; + label.setLabelFor(textField); + + button = new JButton("Manage"); + button.setActionCommand("manageuserplatforms"); + button.addActionListener(myEventHandler); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(textField); + smallPane.add(button); + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Separator + mainPane.add(new JSeparator()); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Rescan button + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Scan after entering above information"); + + rescanButton = new JButton("Scan now"); + rescanButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + rescanDirectories(); + } + }); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(rescanButton); + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Separator + mainPane.add(new JSeparator()); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Processes + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Processes"); + label.setAlignmentX(Component.LEFT_ALIGNMENT); + label.setAlignmentY(Component.TOP_ALIGNMENT); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + JPanel processHolder = new JPanel(new BorderLayout()); + processHolder.setAlignmentX(Component.LEFT_ALIGNMENT); + processHolder.setAlignmentY(Component.TOP_ALIGNMENT); + + button = new JButton("Add process name"); + button.setActionCommand("addprocess"); + button.addActionListener(myEventHandler); + processHolder.add(BorderLayout.SOUTH, button); + + processPanel = new JPanel(); + + processPanel.setLayout(new BoxLayout(processPanel, BoxLayout.Y_AXIS)); + + JScrollPane tempPane = new JScrollPane(processPanel); + tempPane.setPreferredSize(new Dimension(300, 200)); + processHolder.add(BorderLayout.WEST, tempPane); + + label.setLabelFor(processPanel); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(processHolder); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Mote interfaces + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Mote Interfaces"); + label.setAlignmentX(Component.LEFT_ALIGNMENT); + label.setAlignmentY(Component.TOP_ALIGNMENT); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + JPanel moteInterfaceHolder = new JPanel(new BorderLayout()); + moteInterfaceHolder.setAlignmentX(Component.LEFT_ALIGNMENT); + moteInterfaceHolder.setAlignmentY(Component.TOP_ALIGNMENT); + + moteInterfacePanel = new JPanel(); + + moteInterfacePanel.setLayout(new BoxLayout(moteInterfacePanel, + BoxLayout.Y_AXIS)); + + tempPane = new JScrollPane(moteInterfacePanel); + tempPane.setPreferredSize(new Dimension(300, 200)); + moteInterfaceHolder.add(BorderLayout.WEST, tempPane); + + label.setLabelFor(moteInterfacePanel); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(moteInterfaceHolder); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Separator with show advanced checkbox + JCheckBox showAdvancedCheckBox = new JCheckBox("Show advanced settings"); + showAdvancedCheckBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (((JCheckBox) e.getSource()).isSelected()) { + if (entireCoreInterfacePane != null) + entireCoreInterfacePane.setVisible(true); + if (entireSensorPane != null) + entireSensorPane.setVisible(true); + } else { + if (entireCoreInterfacePane != null) + entireCoreInterfacePane.setVisible(false); + if (entireSensorPane != null) + entireSensorPane.setVisible(false); + } + } + }); + mainPane.add(new JSeparator()); + mainPane.add(showAdvancedCheckBox); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Core sensors + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Sensors"); + label.setAlignmentX(Component.LEFT_ALIGNMENT); + label.setAlignmentY(Component.TOP_ALIGNMENT); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + JPanel sensorHolder = new JPanel(new BorderLayout()); + sensorHolder.setAlignmentX(Component.LEFT_ALIGNMENT); + sensorHolder.setAlignmentY(Component.TOP_ALIGNMENT); + + // button = new JButton(GUI.lang.getString("motetype_scansens")); + // button.setActionCommand("scansensors"); + // button.addActionListener(myEventHandler); + // sensorHolder.add(BorderLayout.NORTH, button); + + button = new JButton("Add sensor name"); + button.setActionCommand("addsensor"); + button.addActionListener(myEventHandler); + sensorHolder.add(BorderLayout.SOUTH, button); + + sensorPanel = new JPanel(); + + sensorPanel.setLayout(new BoxLayout(sensorPanel, BoxLayout.Y_AXIS)); + + JScrollPane tempPane2 = new JScrollPane(sensorPanel); + tempPane2.setPreferredSize(new Dimension(300, 200)); + sensorHolder.add(BorderLayout.WEST, tempPane2); + + label.setLabelFor(sensorPanel); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(sensorHolder); + + mainPane.add(smallPane); + entireSensorPane = smallPane; + entireSensorPane.setVisible(false); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Core interfaces + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Core Interfaces"); + label.setAlignmentX(Component.LEFT_ALIGNMENT); + label.setAlignmentY(Component.TOP_ALIGNMENT); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + JPanel interfaceHolder = new JPanel(new BorderLayout()); + interfaceHolder.setAlignmentX(Component.LEFT_ALIGNMENT); + interfaceHolder.setAlignmentY(Component.TOP_ALIGNMENT); + + button = new JButton("Add interface name"); + button.setActionCommand("addinterface"); + button.addActionListener(myEventHandler); + interfaceHolder.add(BorderLayout.SOUTH, button); + + coreInterfacePanel = new JPanel(); + + coreInterfacePanel.setLayout(new BoxLayout(coreInterfacePanel, + BoxLayout.Y_AXIS)); + + JScrollPane tempPane3 = new JScrollPane(coreInterfacePanel); + tempPane3.setPreferredSize(new Dimension(300, 200)); + interfaceHolder.add(BorderLayout.WEST, tempPane3); + + label.setLabelFor(coreInterfacePanel); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + smallPane.add(interfaceHolder); + + mainPane.add(smallPane); + entireCoreInterfacePane = smallPane; + entireCoreInterfacePane.setVisible(false); + + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Add everything! + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + Container contentPane = getContentPane(); + JScrollPane mainScrollPane = new JScrollPane(mainPane); + mainScrollPane.setPreferredSize(new Dimension( + mainPane.getPreferredSize().width + 50, 500)); + contentPane.add(mainScrollPane, BorderLayout.CENTER); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + pack(); + } + + /** + * Checks which core interfaces are needed by the currently selected mote + * interfaces, and selects only them. + */ + private void recheckInterfaceDependencies() { + + // Unselect all core interfaces + for (Component checkBox : coreInterfacePanel.getComponents()) { + ((JCheckBox) checkBox).setSelected(false); + } + + // Loop through all mote interfaces + for (Component checkBox : moteInterfacePanel.getComponents()) { + JCheckBox moteIntfCheckBox = (JCheckBox) checkBox; + + // If the mote interface is selected, select needed core interfaces + if (moteIntfCheckBox.isSelected()) { + String[] neededCoreInterfaces = null; + + // Get needed core interfaces (if any) + try { + Class moteInterfaceClass = (Class) moteIntfCheckBox + .getClientProperty("class"); + if (ContikiMoteInterface.class.isAssignableFrom(moteInterfaceClass)) { + Method m = moteInterfaceClass.getDeclaredMethod( + "getCoreInterfaceDependencies", (Class[]) null); + neededCoreInterfaces = (String[]) m.invoke(null, (Object[]) null); + } + } catch (NoSuchMethodException e) { + logger.warn("Can't read core interface dependencies of " + + moteIntfCheckBox.getText() + ", assuming no core dependencies"); + } catch (InvocationTargetException e) { + logger.warn("Can't read core interface dependencies of " + + moteIntfCheckBox.getText() + ": " + e); + } catch (IllegalAccessException e) { + logger.warn("Can't read core interface dependencies of " + + moteIntfCheckBox.getText() + ": " + e); + } + + // If needed core interfaces found, select them + if (neededCoreInterfaces != null) { + // Loop through all needed core interfaces + for (String neededCoreInterface : neededCoreInterfaces) { + int coreInterfacePosition = -1; + + // Check that the core interface actually exists + for (int j = 0; j < coreInterfacePanel.getComponentCount(); j++) { + JCheckBox coreCheckBox = (JCheckBox) coreInterfacePanel + .getComponent(j); + + if (coreCheckBox.getText().equals(neededCoreInterface)) { + coreInterfacePosition = j; + coreCheckBox.setSelected(true); + break; + } + } + + // Was the core interface found? + if (coreInterfacePosition < 0) { + logger.warn("Warning! " + moteIntfCheckBox.getText() + + " needs non-existing core interface " + neededCoreInterface + + " (rescan?)"); + } + } + } + + } + } + } + + /** + * Tries to compile library using current settings. + */ + public void doTestSettings() { + libraryCreatedOK = false; + + JPanel progressPanel = new JPanel(new BorderLayout()); + final JDialog progressDialog = new JDialog(myDialog, null); + JProgressBar progressBar; + JButton button; + final MessageList taskOutput; + progressDialog.setLocationRelativeTo(myDialog); + + progressBar = new JProgressBar(0, 100); + progressBar.setValue(0); + progressBar.setStringPainted(true); + progressBar.setIndeterminate(true); + + taskOutput = new MessageList(); + + button = new JButton("Close/Abort"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (compilationThread != null && compilationThread.isAlive()) { + compilationThread.interrupt(); + } + progressDialog.dispose(); + } + }); + + progressPanel.add(BorderLayout.CENTER, new JScrollPane(taskOutput)); + progressPanel.add(BorderLayout.NORTH, progressBar); + progressPanel.add(BorderLayout.SOUTH, button); + progressPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + progressPanel.setVisible(true); + + progressDialog.getContentPane().add(progressPanel); + progressDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + progressDialog.pack(); + + progressDialog.setVisible(true); + + // Create temp output directory if not already exists + if (!ContikiMoteType.tempOutputDirectory.exists()) + ContikiMoteType.tempOutputDirectory.mkdir(); + + // Generate main contiki source file + String errorMessage = generateSourceFile(); + if (errorMessage != null) { + libraryCreatedOK = false; + progressBar.setBackground(Color.ORANGE); + progressBar.setString("Maximum number of mote types already exist"); + progressBar.setIndeterminate(false); + progressBar.setValue(0); + createButton.setEnabled(libraryCreatedOK); + return; + } + + // Test compile shared library + progressBar.setString("..compiling.."); + final File contikiDir = new File(textContikiDir.getText()); + final String identifier = textID.getText(); + File libFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + ContikiMoteType.librarySuffix); + File mapFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + ContikiMoteType.mapSuffix); + File depFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + ContikiMoteType.dependSuffix); + + if (libFile.exists()) { + libFile.delete(); + } + + if (depFile.exists()) { + depFile.delete(); + } + + if (mapFile.exists()) { + mapFile.delete(); + } + + compilationThread = new Thread(new Runnable() { + public void run() { + // Merge user platforms + Vector allUserPlatforms = (Vector) GUI.currentGUI.getUserPlatforms().clone(); + allUserPlatforms.addAll(moteTypeUserPlatforms); + compilationSucceded = ContikiMoteTypeDialog.compileLibrary(contikiDir, + allUserPlatforms, identifier, taskOutput, newMoteTypeConfig); + } + }, "compilation thread"); + compilationThread.start(); + + while (compilationThread.isAlive()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // NOP + } + } + + if (!compilationSucceded) { + if (libFile.exists()) { + libFile.delete(); + } + if (depFile.exists()) { + depFile.delete(); + } + if (mapFile.exists()) { + mapFile.delete(); + } + libraryCreatedOK = false; + } else { + libraryCreatedOK = true; + if (!libFile.exists() || !depFile.exists() || !mapFile.exists()) + libraryCreatedOK = false; + } + + if (libraryCreatedOK) { + progressBar.setBackground(Color.GREEN); + progressBar.setString("compilation succeded"); + } else { + progressBar.setBackground(Color.ORANGE); + progressBar.setString("compilation failed"); + } + progressBar.setIndeterminate(false); + progressBar.setValue(0); + createButton.setEnabled(libraryCreatedOK); + } + + /** + * @return Error message or null if source file generation ok + */ + private String generateSourceFile() { + + // SENSORS + String sensorString = ""; + String externSensorDefs = ""; + for (Component checkBox : sensorPanel.getComponents()) { + if (((JCheckBox) checkBox).isSelected()) { + if (!sensorString.equals("")) + sensorString = sensorString.concat(", "); + sensorString = sensorString.concat("&" + + ((JCheckBox) checkBox).getText()); + externSensorDefs = externSensorDefs + .concat("extern const struct sensors_sensor " + + ((JCheckBox) checkBox).getText() + ";\n"); + } + } + + if (!sensorString.equals("")) + sensorString = "SENSORS(" + sensorString + ");"; + else + sensorString = "SENSORS(NULL);"; + + // CORE INTERFACES + String externInterfaceDefs = ""; + String interfaceString = ""; + for (Component checkBox : coreInterfacePanel.getComponents()) { + if (((JCheckBox) checkBox).isSelected()) { + if (!interfaceString.equals("")) + interfaceString = interfaceString.concat(", "); + interfaceString = interfaceString.concat("&" + + ((JCheckBox) checkBox).getText()); + externInterfaceDefs = externInterfaceDefs.concat("SIM_INTERFACE_NAME(" + + ((JCheckBox) checkBox).getText() + ");\n"); + } + } + + if (!interfaceString.equals("")) + interfaceString = "SIM_INTERFACES(" + interfaceString + ");"; + else + interfaceString = "SIM_INTERFACES(NULL);"; + + // PROCESSES + String userProcessString = ""; + String externProcessDefs = ""; + for (Component checkBox : processPanel.getComponents()) { + if (((JCheckBox) checkBox).isSelected()) { + if (!userProcessString.equals("")) + userProcessString = userProcessString.concat(", "); + userProcessString = userProcessString.concat("&" + + ((JCheckBox) checkBox).getText()); + externProcessDefs = externProcessDefs.concat("PROCESS_NAME(" + + ((JCheckBox) checkBox).getText() + ");\n"); + } + } + + String coreProcessString = ""; + String processArray[] = GUI.getExternalToolsSetting( + "CONTIKI_STANDARD_PROCESSES").split(";"); + for (String processString : processArray) { + if (!coreProcessString.equals("")) + coreProcessString = coreProcessString.concat(", "); + coreProcessString = coreProcessString + "&" + processString; + } + + if (userProcessString.equals("")) { + logger + .warn("No application processes specified! Sure you don't want any?"); + } + + String processString; + if (!coreProcessString.equals("")) + processString = "PROCINIT(" + coreProcessString + ");"; + else + processString = "PROCINIT(NULL);"; + + if (!userProcessString.equals("")) + processString = processString.concat("\nAUTOSTART_PROCESSES(" + + userProcessString + ");"); + else + processString = processString.concat("\nAUTOSTART_PROCESSES(NULL);"); + + // JNI CLASS NAME + String libString = CoreComm.getAvailableClassName(); + if (libString == null) { + logger.fatal("No more libraries can be loaded!"); + return "Maximum number of mote types already exist"; + } + + // Create new source file and replace special fields + try { + Reader reader; + String mainTemplate = GUI + .getExternalToolsSetting("CONTIKI_MAIN_TEMPLATE_FILENAME"); + if ((new File(mainTemplate)).exists()) { + reader = new FileReader(mainTemplate); + } else { + InputStream input = ContikiMoteTypeDialog.class + .getResourceAsStream(File.separatorChar + mainTemplate); + if (input == null) { + throw new FileNotFoundException(mainTemplate + " not found"); + } + reader = new InputStreamReader(input); + } + + BufferedReader sourceFile = new BufferedReader(reader); + BufferedWriter destFile = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ".c"))); + String line; + while ((line = sourceFile.readLine()) != null) { + line = line + .replaceFirst("\\[PROCESS_DEFINITIONS\\]", externProcessDefs); + line = line.replaceFirst("\\[PROCESS_ARRAY\\]", processString); + + line = line.replaceFirst("\\[SENSOR_DEFINITIONS\\]", externSensorDefs); + line = line.replaceFirst("\\[SENSOR_ARRAY\\]", sensorString); + + line = line.replaceFirst("\\[INTERFACE_DEFINITIONS\\]", + externInterfaceDefs); + line = line.replaceFirst("\\[INTERFACE_ARRAY\\]", interfaceString); + + line = line.replaceFirst("\\[CLASS_NAME\\]", libString); + destFile.write(line + "\n"); + } + + destFile.close(); + sourceFile.close(); + } catch (Exception e) { + logger.debug("Exception " + e); + return "Exception " + e; + } + + return null; + } + + /** + * Compiles a mote type shared library using an external makefile. + * + * @param contikiDir + * Contiki OS main directory + * @param userPlatformDirs + * COOJA user platforms (may be null) + * @param identifier + * Filename identifier + * @param appender + * Optional component to append process output to + * @return False if an error was discovered, true otherwise + */ + public static boolean compileLibrary(File contikiDir, Vector userPlatformDirs, + String identifier, final MessageList appender, + PlatformConfig platformConfig) { + File libFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + ContikiMoteType.librarySuffix); + File mapFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + ContikiMoteType.mapSuffix); + File depFile = new File(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + identifier + ContikiMoteType.dependSuffix); + + // Recheck that contiki path exists + if (!contikiDir.exists()) { + appender.addMessage("Bad Contiki OS path", MessageList.ERROR); + logger.fatal("Contiki path does not exist"); + return false; + } + if (!contikiDir.isDirectory()) { + appender.addMessage("Bad Contiki OS path", MessageList.ERROR); + logger.fatal("Contiki path is not a directory"); + return false; + } + + if (libFile.exists()) { + appender.addMessage("Bad output filenames", MessageList.ERROR); + logger.fatal("Could not overwrite already existing library"); + return false; + } + + if (CoreComm.hasLibraryFileBeenLoaded(libFile)) { + appender.addMessage("Bad output filenames", MessageList.ERROR); + logger + .fatal("A library has already been loaded with the same name before"); + return false; + } + + if (depFile.exists()) { + appender.addMessage("Bad output filenames", MessageList.ERROR); + logger.fatal("Could not overwrite already existing dependency file"); + return false; + } + + if (mapFile.exists()) { + appender.addMessage("Bad output filenames", MessageList.ERROR); + logger.fatal("Could not overwrite already existing map file"); + return false; + } + + try { + // Let Contiki 2.x regular make file compile + String[] cmd = new String[]{ + GUI.getExternalToolsSetting("PATH_MAKE"), + libFile.getPath().replace(File.separatorChar, '/'), + "-f", + contikiDir.getPath().replace(File.separatorChar, '/') + + "/Makefile.include"}; + + String projectDirs = System.getProperty("PROJECTDIRS", ""); + if (userPlatformDirs != null) { + for (File userPlatform : userPlatformDirs) { + projectDirs += " " + + userPlatform.getPath().replace(File.separatorChar, '/'); + } + } + + String[] projectSourceFiles = platformConfig.getStringArrayValue( + ContikiMoteType.class, "C_SOURCES"); + String sourceFiles = ""; + if (userPlatformDirs != null) { + for (String sourceFile : projectSourceFiles) { + sourceFiles += " " + sourceFile; + } + } + + String[] env = new String[]{ + "CONTIKI=" + contikiDir.getPath().replace(File.separatorChar, '/'), + "TARGET=cooja", "TYPEID=" + identifier, + "LD_ARGS_1=" + GUI.getExternalToolsSetting("LINKER_ARGS_1", ""), + "LD_ARGS_2=" + GUI.getExternalToolsSetting("LINKER_ARGS_2", ""), + "EXTRA_CC_ARGS=" + GUI.getExternalToolsSetting("COMPILER_ARGS", ""), + "CC=" + GUI.getExternalToolsSetting("PATH_C_COMPILER"), + "LD=" + GUI.getExternalToolsSetting("PATH_LINKER"), "COMPILE_MAIN=1", + "PROJECTDIRS=" + projectDirs, "PROJECT_SOURCEFILES=" + sourceFiles, + "PATH=" + System.getenv("PATH")}; + + Process p = Runtime.getRuntime().exec(cmd, env, null); + + final BufferedReader input = new BufferedReader(new InputStreamReader(p + .getInputStream())); + final BufferedReader err = new BufferedReader(new InputStreamReader(p + .getErrorStream())); + + Thread readInput = new Thread(new Runnable() { + public void run() { + String readLine; + try { + while ((readLine = input.readLine()) != null) { + if (appender != null && readLine != null) { + appender.addMessage(readLine); + } + } + } catch (IOException e) { + logger.warn("Error while reading from process"); + } + } + }, "read input stream thread"); + + Thread readError = new Thread(new Runnable() { + public void run() { + String readLine; + try { + while ((readLine = err.readLine()) != null) { + if (appender != null && readLine != null) { + appender.addMessage(readLine, MessageList.ERROR); + } + } + } catch (IOException e) { + logger.warn("Error while reading from process"); + } + } + }, "read input stream thread"); + + readInput.start(); + readError.start(); + + while (readInput.isAlive() || readError.isAlive()) { + Thread.sleep(100); + } + + input.close(); + err.close(); + + p.waitFor(); + if (p.exitValue() != 0) + return false; + } catch (Exception e) { + logger.fatal("Error while compiling library: " + e); + return false; + } + return true; + } + + /** + * Scans a directory for sourcefiles which defines a Contiki process. + * + * @param rootDirectory + * Top directory to search in + * @return Process definitions found under rootDirectory, {sourcefile, + * processname} + */ + public static Vector scanForProcesses(File rootDirectory) { + if (!rootDirectory.isDirectory()) { + logger.fatal("Not a directory: " + rootDirectory); + return null; + } + + if (!rootDirectory.exists()) { + logger.fatal("Does not exist: " + rootDirectory); + return null; + } + + Vector processes = new Vector(); + + // Scan in rootDirectory + try { + String line; + String cmdString = GUI.getExternalToolsSetting("CMD_GREP_PROCESSES") + + " '" + rootDirectory.getPath().replace(File.separatorChar, '/') + + "'/*.[ch]"; + Pattern pattern = Pattern.compile(GUI + .getExternalToolsSetting("REGEXP_PARSE_PROCESSES")); + + String[] cmd = new String[3]; + cmd[0] = GUI.getExternalToolsSetting("PATH_SHELL"); + cmd[1] = "-c"; + cmd[2] = cmdString; + + Process p = Runtime.getRuntime().exec(cmd); + BufferedReader input = new BufferedReader(new InputStreamReader(p + .getInputStream())); + while ((line = input.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + processes.add(new String[]{matcher.group(1), matcher.group(2)}); + } + } + input.close(); + + BufferedReader err = new BufferedReader(new InputStreamReader(p + .getErrorStream())); + if (err.ready()) + logger.warn("Error occured during scan:"); + while ((line = err.readLine()) != null) { + logger.warn(line); + } + err.close(); + } catch (IOException err) { + logger.fatal("Error while scanning for processes: " + err); + err.printStackTrace(); + } catch (Exception err) { + logger.fatal("Error while scanning for processes: " + err); + err.printStackTrace(); + } + return processes; + } + + /** + * Scans a directory and all subdirectories for sourcefiles which defines a + * Contiki sensor. + * + * @param rootDirectory + * Top directory to search in + * @return Sensor definitions found under rootDirectory, {sourcefile, + * sensorname} + */ + public static Vector scanForSensors(File rootDirectory) { + if (!rootDirectory.isDirectory()) { + logger.fatal("Not a directory: " + rootDirectory); + return null; + } + + if (!rootDirectory.exists()) { + logger.fatal("Does not exist: " + rootDirectory); + return null; + } + + Vector sensors = new Vector(); + + // Scan in rootDirectory + try { + String line; + String cmdString = GUI.getExternalToolsSetting("CMD_GREP_SENSORS") + " '" + + rootDirectory.getPath().replace(File.separatorChar, '/') + "'"; + Pattern pattern = Pattern.compile(GUI + .getExternalToolsSetting("REGEXP_PARSE_SENSORS")); + + String[] cmd = new String[3]; + cmd[0] = GUI.getExternalToolsSetting("PATH_SHELL"); + cmd[1] = "-c"; + cmd[2] = cmdString; + + Process p = Runtime.getRuntime().exec(cmd); + BufferedReader input = new BufferedReader(new InputStreamReader(p + .getInputStream())); + while ((line = input.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + sensors.add(new String[]{matcher.group(1), matcher.group(2)}); + } + } + input.close(); + + BufferedReader err = new BufferedReader(new InputStreamReader(p + .getErrorStream())); + if (err.ready()) + logger.warn("Error occured during scan:"); + while ((line = err.readLine()) != null) { + logger.warn(line); + } + err.close(); + } catch (IOException err) { + logger.fatal("Error while scanning for sensors: " + err); + err.printStackTrace(); + } catch (Exception err) { + logger.fatal("Error while scanning for sensors: " + err); + err.printStackTrace(); + } + return sensors; + } + + /** + * Scans a directory and all subdirectories for sourcefiles which defines a + * COOJA core interface. + * + * @param rootDirectory + * Top directory to search in + * @return Core interface definitions found under rootDirectory, {sourcefile, + * interfacename} + */ + public static Vector scanForInterfaces(File rootDirectory) { + if (!rootDirectory.isDirectory()) { + logger.fatal("Not a directory: " + rootDirectory); + return null; + } + + if (!rootDirectory.exists()) { + logger.fatal("Does not exist: " + rootDirectory); + return null; + } + + Vector interfaces = new Vector(); + + // Scan in rootDirectory + try { + String line; + String cmdString = GUI.getExternalToolsSetting("CMD_GREP_INTERFACES") + + " '" + rootDirectory.getPath().replace(File.separatorChar, '/') + + "'"; + Pattern pattern = Pattern.compile(GUI + .getExternalToolsSetting("REGEXP_PARSE_INTERFACES")); + + String[] cmd = new String[3]; + cmd[0] = GUI.getExternalToolsSetting("PATH_SHELL"); + cmd[1] = "-c"; + cmd[2] = cmdString; + + Process p = Runtime.getRuntime().exec(cmd); + BufferedReader input = new BufferedReader(new InputStreamReader(p + .getInputStream())); + while ((line = input.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + interfaces.add(new String[]{matcher.group(1), matcher.group(2)}); + } + } + input.close(); + + BufferedReader err = new BufferedReader(new InputStreamReader(p + .getErrorStream())); + if (err.ready()) + logger.warn("Error occured during scan:"); + while ((line = err.readLine()) != null) { + logger.warn(line); + } + err.close(); + } catch (IOException err) { + logger.fatal("Error while scanning for interfaces: " + err); + err.printStackTrace(); + } catch (Exception err) { + logger.fatal("Error while scanning for interfaces: " + err); + err.printStackTrace(); + } + return interfaces; + } + + private void autoSelectDependencyProcesses(String processName, + String sourceFilename, boolean confirmSelection) { + + /* + * Try to autofind and select dependency processes (via + * AUTOSTART_PROCESSES()) If this procedure fails, nothing will be reported + * to user + */ + + // Open source code file + FileReader reader = null; + try { + reader = new FileReader(textCoreDir.getText() + File.separatorChar + + sourceFilename); + } catch (Exception ex) { + } + for (File userPlatform : GUI.currentGUI.getUserPlatforms()) { + if (reader == null) { + try { + reader = new FileReader(userPlatform.getPath() + File.separatorChar + + sourceFilename); + } catch (Exception ex) { + } + } + } + for (File userPlatform : moteTypeUserPlatforms) { + if (reader == null) { + try { + reader = new FileReader(userPlatform.getPath() + File.separatorChar + + sourceFilename); + } catch (Exception ex) { + } + } + } + if (reader == null) { + // Could not locate source file + return; + } + + // Find which processes were set to autostart + BufferedReader sourceFile = new BufferedReader(reader); + String line; + try { + String autostartExpression = "^AUTOSTART_PROCESSES([^$]*)$"; + + Pattern pattern = Pattern.compile(autostartExpression); + + while ((line = sourceFile.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + // Parse autostart processes + String[] allProcesses = matcher.group(1).split(","); + for (String autostartProcess : allProcesses) { + autostartProcess = autostartProcess.replaceAll("[&; \\(\\)]", ""); + + // Does this process already exist? + boolean processAlreadyExists = false; + for (Component checkBox : processPanel.getComponents()) { + String existingProcess = ((JCheckBox) checkBox).getText(); + if (existingProcess.equals(autostartProcess)) { + processAlreadyExists = true; + } + } + + if (!processAlreadyExists) { + + if (confirmSelection) { + Object[] options = {"Create", "Cancel"}; + + String question = "The process [PROC1] depends on the following process: [PROC2]\nDo you want to add this as well?"; + String title = "Add dependency process?"; + question = question.replaceFirst("\\[PROC1\\]", processName); + question = question.replaceFirst("\\[PROC2\\]", + autostartProcess); + int answer = JOptionPane.showOptionDialog(myDialog, question, + title, JOptionPane.DEFAULT_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + + if (answer == JOptionPane.YES_OPTION) { + JCheckBox processCheckBox = new JCheckBox(autostartProcess, + true); + processCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + + processCheckBox.setActionCommand("process_clicked: " + + autostartProcess); + processCheckBox.addActionListener(myEventHandler); + + processPanel.add(processCheckBox); + myDialog.pack(); + } + } else { + JCheckBox processCheckBox = new JCheckBox(autostartProcess, + true); + processCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + + processCheckBox.setActionCommand("process_clicked: " + + autostartProcess); + processCheckBox.addActionListener(myEventHandler); + + processPanel.add(processCheckBox); + myDialog.pack(); + } + } + } + + } + } + } catch (Exception ex) { + return; + } + } + + private void pathsWereUpdated() { + updateVisualFields(); + + // Remove all prevously scanned entries + coreInterfacePanel.removeAll(); + moteInterfacePanel.removeAll(); + processPanel.removeAll(); + sensorPanel.removeAll(); + coreInterfacePanel.repaint(); + moteInterfacePanel.repaint(); + processPanel.repaint(); + sensorPanel.repaint(); + createButton.setEnabled(libraryCreatedOK = false); + + settingsOK = false; + testButton.setEnabled(settingsOK); + } + + private void updateVisualFields() { + settingsOK = true; + + // Check for non-unique identifier + textID.setBackground(Color.WHITE); + textID.setToolTipText(null); + + for (MoteType otherType : allOtherTypes) { + if (otherType != myMoteType + && otherType.getIdentifier().equalsIgnoreCase(textID.getText())) { + textID.setBackground(Color.RED); + textID.setToolTipText("Conflicting name - must be unique"); + settingsOK = false; + break; + } + } + + // Check for non-unique description + textDescription.setBackground(Color.WHITE); + textDescription.setToolTipText(null); + + for (MoteType otherType : allOtherTypes) { + if (otherType != myMoteType + && otherType.getDescription().equals(textDescription.getText())) { + textDescription.setBackground(Color.RED); + textDescription.setToolTipText("Conflicting name - must be unique"); + settingsOK = false; + break; + } + } + + // Warn if spaces in Contiki path + textContikiDir.setBackground(Color.WHITE); + textContikiDir.setToolTipText(null); + if (textContikiDir.getText().contains(" ")) { + textContikiDir.setBackground(Color.ORANGE); + textContikiDir + .setToolTipText("Compilation may not work correctly with spaced paths"); + } + textCoreDir.setText(textContikiDir.getText() + + GUI.getExternalToolsSetting("PATH_COOJA_CORE_RELATIVE")); + textCoreDir.setBackground(Color.WHITE); + textCoreDir.setToolTipText(null); + if (textCoreDir.getText().contains(" ")) { + textCoreDir.setBackground(Color.ORANGE); + textCoreDir + .setToolTipText("Compilation may not work correctly with spaced paths"); + } + + // Warn if spaces in a user platform path + textUserPlatforms.setBackground(Color.WHITE); + textUserPlatforms.setToolTipText(null); + for (File userPlatform : moteTypeUserPlatforms) { + if (userPlatform.getPath().contains(" ")) { + textUserPlatforms.setBackground(Color.ORANGE); + textUserPlatforms + .setToolTipText("Compilation may not work correctly with spaced paths"); + } + } + + // Update output text field + textOutputFiles.setText(ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ContikiMoteType.mapSuffix + + ", " + ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ContikiMoteType.librarySuffix + + ", " + ContikiMoteType.tempOutputDirectory.getPath() + + File.separatorChar + textID.getText() + ContikiMoteType.dependSuffix); + + createButton.setEnabled(libraryCreatedOK = false); + testButton.setEnabled(settingsOK); + } + + /** + * Scans Contiki base + (optional) user platform for Contiki processes, + * sensors and core interfaces. The new mote type config is recreated every + * time this method is run. If a user platform is specified, it looks for a + * special class config file there, and appends it to the new mote type + * config. By reading that config all available mote interfaces are parsed - + * which will all be selected initially. This method also selects the core + * interfaces needed by the mote interfaces. + * + * Finally any pre-specified processes (via shortcut start) will be selected. + */ + private void rescanDirectories() { + + boolean pathErrorFound = false; + + // Check that Contiki path is correct + if (!new File(myDialog.textContikiDir.getText()).isDirectory()) { + // Contiki path specified does not exist + textContikiDir.setBackground(Color.RED); + textContikiDir.setToolTipText("Incorrect path"); + pathErrorFound = true; + } + + // Check that cooja main platform path is correct + if (!new File(myDialog.textCoreDir.getText()).isDirectory()) { + // Cooja main platform specified does not exist + textContikiDir.setBackground(Color.RED); + textContikiDir.setToolTipText("Incorrect path"); + textCoreDir.setBackground(Color.RED); + textCoreDir.setToolTipText("Incorrect path"); + pathErrorFound = true; + } + + // Check that all user platforms are valid + for (File userPlatform : moteTypeUserPlatforms) { + File userPlatformConfig = new File(userPlatform.getPath() + + File.separatorChar + GUI.PLATFORM_CONFIG_FILENAME); + if (!userPlatformConfig.exists()) { + textUserPlatforms.setBackground(Color.RED); + textUserPlatforms.setToolTipText("Invalid user platform: " + + userPlatform); + pathErrorFound = true; + } + } + + if (pathErrorFound) { + // Remove all prevously scanned entries + coreInterfacePanel.removeAll(); + processPanel.removeAll(); + sensorPanel.removeAll(); + coreInterfacePanel.repaint(); + processPanel.repaint(); + sensorPanel.repaint(); + testButton.setEnabled(settingsOK = false); + createButton.setEnabled(libraryCreatedOK = false); + return; + } + + // Scan for mote interfaces (+ recreate node type class configuration) + myEventHandler.actionPerformed(new ActionEvent(myDialog.createButton, + ActionEvent.ACTION_PERFORMED, "scanmoteinterfaces")); + + // Scan for processes + myEventHandler.actionPerformed(new ActionEvent(myDialog.createButton, + ActionEvent.ACTION_PERFORMED, "scanprocesses")); + + // Scan for sensors + myDialog.myEventHandler.actionPerformed(new ActionEvent( + myDialog.createButton, ActionEvent.ACTION_PERFORMED, "scansensors")); + + // Scan for core interfaces + myDialog.myEventHandler.actionPerformed(new ActionEvent( + myDialog.createButton, ActionEvent.ACTION_PERFORMED, + "scancoreinterfaces")); + + // Recheck dependencies between selected mote interfaces and available + // core interfaces + myDialog.myEventHandler.actionPerformed(new ActionEvent( + myDialog.createButton, ActionEvent.ACTION_PERFORMED, + "recheck_interface_dependencies")); + + // Check if COOJA was started with a recommended process (select process) + if (System.getProperty("QUICKSTART_APP") != null) { + + // Pre-select recommended process + String wantedSourceFilename = System.getProperty("QUICKSTART_APP"); + + for (Component checkBox : myDialog.processPanel.getComponents()) { + JCheckBox processCheckBox = (JCheckBox) checkBox; + String processFilename = processCheckBox.getToolTipText(); + + if (processFilename.startsWith(wantedSourceFilename)) { + // We found the recommended process, select it + processCheckBox.setSelected(true); + myDialog.autoSelectDependencyProcesses(processCheckBox.getText(), + processFilename, false); + break; + } + } + } + + settingsOK = true; + testButton.setEnabled(settingsOK); + } + + private class MoteTypeEventHandler + implements + ActionListener, + DocumentListener { + public void insertUpdate(DocumentEvent e) { + if (myDialog.isVisible()) + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + pathsWereUpdated(); + } + }); + } + public void removeUpdate(DocumentEvent e) { + if (myDialog.isVisible()) + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + pathsWereUpdated(); + } + }); + } + public void changedUpdate(DocumentEvent e) { + if (myDialog.isVisible()) + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + pathsWereUpdated(); + } + }); + } + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("cancel")) { + // Cancel creation of mote type + myMoteType = null; + dispose(); + } else if (e.getActionCommand().equals("clean")) { + // Delete any created intermediate files + File objectDir = new File("obj_cooja"); + if (objectDir.exists() && objectDir.isDirectory()) { + File[] objectFiles = objectDir.listFiles(); + for (File objectFile : objectFiles) + objectFile.delete(); + + objectDir.delete(); + } + } else if (e.getActionCommand().equals("create")) { + // Create mote type and set various data + myMoteType.doInit(textID.getText()); + myMoteType.setDescription(textDescription.getText()); + myMoteType.setContikiBaseDir(textContikiDir.getText()); + myMoteType.setContikiCoreDir(textCoreDir.getText()); + myMoteType.setUserPlatformDirs(moteTypeUserPlatforms); + myMoteType.setConfig(newMoteTypeConfig); + + // Set startup processes + Vector processes = new Vector(); + for (Component checkBox : processPanel.getComponents()) { + if (((JCheckBox) checkBox).isSelected()) { + processes.add(((JCheckBox) checkBox).getText()); + } + } + myMoteType.setProcesses(processes); + + // Set registered sensors + Vector sensors = new Vector(); + for (Component checkBox : sensorPanel.getComponents()) { + if (((JCheckBox) checkBox).isSelected()) { + sensors.add(((JCheckBox) checkBox).getText()); + } + } + myMoteType.setSensors(sensors); + + // Set registered core interfaces + Vector coreInterfaces = new Vector(); + for (Component checkBox : coreInterfacePanel.getComponents()) { + if (((JCheckBox) checkBox).isSelected()) { + coreInterfaces.add(((JCheckBox) checkBox).getText()); + } + } + myMoteType.setCoreInterfaces(coreInterfaces); + + // Set registered mote interfaces + Vector> moteInterfaces = new Vector>(); + for (Component checkBox : moteInterfacePanel.getComponents()) { + JCheckBox interfaceCheckBox = (JCheckBox) checkBox; + if (interfaceCheckBox.isSelected()) { + moteInterfaces + .add((Class) interfaceCheckBox + .getClientProperty("class")); + } + } + myMoteType.setMoteInterfaces(moteInterfaces); + + dispose(); + } else if (e.getActionCommand().equals("testsettings")) { + testButton.requestFocus(); + Thread testSettingsThread = new Thread(new Runnable() { + public void run() { + doTestSettings(); + } + }, "test settings thread"); + testSettingsThread.start(); + } else if (e.getActionCommand().equals("browsecontiki")) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new java.io.File(".")); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fc.setDialogTitle("Contiki OS base directory"); + + if (fc.showOpenDialog(myDialog) == JFileChooser.APPROVE_OPTION) { + textContikiDir.setText(fc.getSelectedFile().getPath()); + } + createButton.setEnabled(libraryCreatedOK = false); + pathsWereUpdated(); + } else if (e.getActionCommand().equals("manageuserplatforms")) { + Vector newPlatforms = UserPlatformsDialog.showDialog( + myParentFrame, moteTypeUserPlatforms, GUI.currentGUI + .getUserPlatforms()); + if (newPlatforms != null) { + moteTypeUserPlatforms = newPlatforms; + String userPlatformText = null; + for (File userPlatform : newPlatforms) { + if (userPlatformText == null) + userPlatformText = "'" + userPlatform.getPath() + "'"; + else + userPlatformText += " + '" + userPlatform.getPath() + "'"; + } + textUserPlatforms.setText(userPlatformText); + + createButton.setEnabled(libraryCreatedOK = false); + pathsWereUpdated(); + } + } else if (e.getActionCommand().equals("scanprocesses")) { + // Clear process panel + processPanel.removeAll(); + Vector processes = new Vector(); + + // Scan core platform for processes + processes.addAll(ContikiMoteTypeDialog.scanForProcesses(new File( + textCoreDir.getText()))); + + // If user platforms exists, scan those too + for (File userPlatform : GUI.currentGUI.getUserPlatforms()) { + processes.addAll(ContikiMoteTypeDialog + .scanForProcesses(userPlatform)); + } + if (moteTypeUserPlatforms != null) { + for (File userPlatform : moteTypeUserPlatforms) { + processes.addAll(ContikiMoteTypeDialog + .scanForProcesses(userPlatform)); + } + } + + if (processes != null) { + for (String[] processInfo : processes) { + JCheckBox processCheckBox = new JCheckBox(processInfo[1], false); + processCheckBox.setToolTipText(processInfo[0]); + processCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + + processCheckBox.setActionCommand("process_clicked: " + + processInfo[1]); + processCheckBox.addActionListener(myEventHandler); + + processPanel.add(processCheckBox); + } + } else { + logger.warn("No processes found during scan"); + testButton.setEnabled(settingsOK = false); + } + + processPanel.repaint(); + myDialog.pack(); + createButton.setEnabled(libraryCreatedOK = false); + + } else if (e.getActionCommand().equals("scansensors")) { + // Clear sensor panel + sensorPanel.removeAll(); + Vector sensors = new Vector(); + + // Scan core platform for sensors + sensors.addAll(ContikiMoteTypeDialog.scanForSensors(new File( + textCoreDir.getText()))); + + // If user platforms exists, scan those too + for (File userPlatform : GUI.currentGUI.getUserPlatforms()) { + sensors.addAll(ContikiMoteTypeDialog.scanForSensors(userPlatform)); + } + if (moteTypeUserPlatforms != null) { + for (File userPlatform : moteTypeUserPlatforms) { + sensors.addAll(ContikiMoteTypeDialog.scanForSensors(userPlatform)); + } + } + + if (sensors != null) { + for (String[] sensorInfo : sensors) { + JCheckBox sensorCheckBox = new JCheckBox(sensorInfo[1], true); + sensorCheckBox.setToolTipText(sensorInfo[0]); + sensorCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + + sensorPanel.add(sensorCheckBox); + } + } else { + logger.warn("No sensors found during scan"); + testButton.setEnabled(settingsOK = false); + } + + sensorPanel.repaint(); + myDialog.pack(); + createButton.setEnabled(libraryCreatedOK = false); + } else if (e.getActionCommand().equals("scancoreinterfaces")) { + // Clear core interface panel + coreInterfacePanel.removeAll(); + Vector interfaces = new Vector(); + + // Scan core platform for core interfaces + interfaces.addAll(ContikiMoteTypeDialog.scanForInterfaces(new File( + textCoreDir.getText()))); + + // If user platforms exists, scan those too + for (File userPlatform : GUI.currentGUI.getUserPlatforms()) { + interfaces.addAll(ContikiMoteTypeDialog + .scanForInterfaces(userPlatform)); + } + if (moteTypeUserPlatforms != null) { + for (File userPlatform : moteTypeUserPlatforms) { + interfaces.addAll(ContikiMoteTypeDialog + .scanForInterfaces(userPlatform)); + } + } + + if (interfaces != null) { + for (String[] interfaceInfo : interfaces) { + JCheckBox interfaceCheckBox = new JCheckBox(interfaceInfo[1], false); + interfaceCheckBox.setToolTipText(interfaceInfo[0]); + interfaceCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + coreInterfacePanel.add(interfaceCheckBox); + } + } else { + logger.warn("No core interfaces found during scan"); + testButton.setEnabled(settingsOK = false); + } + recheckInterfaceDependencies(); + + coreInterfacePanel.repaint(); + myDialog.pack(); + createButton.setEnabled(libraryCreatedOK = false); + + } else if (e.getActionCommand().equals("scanmoteinterfaces")) { + // Clear core interface panel + moteInterfacePanel.removeAll(); + + // Clone general simulator config + newMoteTypeConfig = GUI.currentGUI.getPlatformConfig().clone(); + + // Merge with all user platform configs (if any) + for (File userPlatform : moteTypeUserPlatforms) { + File userPlatformConfig = new File(userPlatform.getPath() + + File.separatorChar + GUI.PLATFORM_CONFIG_FILENAME); + if (userPlatformConfig.exists()) { + try { + newMoteTypeConfig.appendConfig(userPlatformConfig); + } catch (Exception ex) { + logger.fatal("Error when parsing user platform config: " + ex); + return; + } + } else + logger.fatal("Could not find user platform config file: " + + userPlatformConfig); + } + + // Get all mote interfaces available from config + String[] moteInterfaces = newMoteTypeConfig.getStringArrayValue( + ContikiMoteType.class, "MOTE_INTERFACES"); + Vector> moteIntfClasses = new Vector>(); + + // Find and load the mote interface classes + for (String moteInterface : moteInterfaces) { + + Class newMoteInterfaceClass = GUI.currentGUI.tryLoadClass(this, MoteInterface.class, + moteInterface); + + if (newMoteInterfaceClass == null) { + logger.warn("Failed to load mote interface: " + moteInterface); + } else { + moteIntfClasses.add(newMoteInterfaceClass); + //logger.info("Loaded mote interface: " + newMoteInterfaceClass); + } + } + + // Create and add checkboxes for all mote interfaces + if (moteIntfClasses.size() > 0) { + for (Class moteIntfClass : moteIntfClasses) { + JCheckBox interfaceCheckBox = new JCheckBox(GUI + .getDescriptionOf(moteIntfClass), true); + interfaceCheckBox.putClientProperty("class", moteIntfClass); + interfaceCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + + interfaceCheckBox + .setActionCommand("recheck_interface_dependencies"); + interfaceCheckBox.addActionListener(myEventHandler); + + moteInterfacePanel.add(interfaceCheckBox); + } + } else { + logger + .warn("Error occured during parsing of mote interfaces (no found)"); + testButton.setEnabled(settingsOK = false); + } + + moteInterfacePanel.repaint(); + myDialog.pack(); + createButton.setEnabled(libraryCreatedOK = false); + } else if (e.getActionCommand().equals("addprocess")) { + String newProcessName = JOptionPane.showInputDialog(myDialog, + "Enter process name"); + if (newProcessName != null) { + JCheckBox processCheckBox = new JCheckBox(newProcessName, false); + processCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + processCheckBox.setSelected(true); + + processCheckBox + .setActionCommand("process_clicked: " + newProcessName); + processCheckBox.addActionListener(myEventHandler); + + processPanel.add(processCheckBox); + } + myDialog.pack(); + } else if (e.getActionCommand().equals("addsensor")) { + String newSensorName = JOptionPane.showInputDialog(myDialog, + "Enter sensor name"); + if (newSensorName != null) { + JCheckBox sensorCheckBox = new JCheckBox(newSensorName, false); + sensorCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + sensorCheckBox.setSelected(true); + sensorPanel.add(sensorCheckBox); + } + myDialog.pack(); + } else if (e.getActionCommand().equals("addinterface")) { + String newInterfaceName = JOptionPane.showInputDialog(myDialog, + "Enter interface name"); + if (newInterfaceName != null) { + JCheckBox interfaceCheckBox = new JCheckBox(newInterfaceName, false); + interfaceCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT); + interfaceCheckBox.setSelected(true); + coreInterfacePanel.add(interfaceCheckBox); + } + myDialog.pack(); + } else if (e.getActionCommand().equals("recheck_interface_dependencies")) { + recheckInterfaceDependencies(); + } else if (e.getActionCommand().startsWith("process_clicked")) { + + boolean processWasSelected = false; + String sourceFilename = null; + String processName = e.getActionCommand().split(": ")[1].trim(); + + // Was the process selected or unselected? + for (Component checkBox : processPanel.getComponents()) { + JCheckBox processCheckbox = (JCheckBox) checkBox; + if (processCheckbox.isSelected() + && processCheckbox.getText().equals(processName)) { + processWasSelected = true; + sourceFilename = ((JCheckBox) checkBox).getToolTipText(); + break; + } + } + + if (!processWasSelected || sourceFilename == null) + return; + + autoSelectDependencyProcesses(processName, sourceFilename, true); + + } else + logger.warn("Unhandled action: " + e.getActionCommand()); + + createButton.setEnabled(libraryCreatedOK = false); + + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiBeeper.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiBeeper.java new file mode 100644 index 000000000..d1ff84698 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiBeeper.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2006, 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: ContikiBeeper.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.util.Collection; +import javax.swing.JPanel; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.Beeper; + +/** + * Ths class represents a beeper. + * + * It needs read access to the following core variables: + *

    + *
  • char simBeeped (1=on, else off) + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • beep_interface + *
+ *

+ * This observable is changed and notifies observers whenever the beeper changes + * state. + * + * @author Fredrik Osterlind + */ +public class ContikiBeeper extends Beeper implements ContikiMoteInterface { + private Mote mote = null; + private SectionMoteMemory moteMem = null; + private static Logger logger = Logger.getLogger(ContikiBeeper.class); + + /** + * Assuming beep always lasts for 0.1 seconds. ESB measured energy + * consumption: 16.69 mA. Total energy consumption of a beep is then: + * 0.1*16.69 + */ + private final double ENERGY_CONSUMPTION_BEEP; + + private double myEnergyConsumption = 0.0; + + private boolean justBeeped = false; + + /** + * Creates an interface to the beeper at mote. + * + * @param mote + * Beeper's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiBeeper(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_BEEP = mote.getType().getConfig().getDoubleValue( + ContikiBeeper.class, "BEEP_CONSUMPTION_mQ"); + + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + } + + public boolean isBeeping() { + return justBeeped; + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"beep_interface"}; + } + + public void doActionsBeforeTick() { + // Nothing to do + justBeeped = false; + } + + public void doActionsAfterTick() { + if (moteMem.getByteValueOf("simBeeped") == 1) { + this.setChanged(); + this.notifyObservers(mote); + justBeeped = true; + moteMem.setByteValueOf("simBeeped", (byte) 0); + myEnergyConsumption = ENERGY_CONSUMPTION_BEEP; + } else + myEnergyConsumption = 0.0; + } + + public JPanel getInterfaceVisualizer() { + return null; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + public double energyConsumptionPerTick() { + return myEnergyConsumption; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiButton.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiButton.java new file mode 100644 index 000000000..9e6cd6d17 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiButton.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2006, 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: ContikiButton.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.awt.event.*; +import java.util.Collection; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.Button; + +/** + * This class represents a button. + * + * It needs read/write access to the following core variables: + *

    + *
  • char simButtonIsDown (1=down, else up) + *
  • char simButtonChanged (1=changed, else not changed) + *
  • char simButtonIsActive (1=active, else inactive) + *
+ * Dependency core interfaces are: + *
    + *
  • button_interface + *
+ *

+ * This observable notifies observers when the button changes state (between + * pressed and released). + * + * @author Fredrik Osterlind + */ +public class ContikiButton extends Button implements ContikiMoteInterface { + private SectionMoteMemory moteMem; + private Mote mote; + + private boolean shouldBeReleased = false; + private static Logger logger = Logger.getLogger(ContikiButton.class); + + private final boolean RAISES_EXTERNAL_INTERRUPT; + + /** + * Creates an interface to the button at mote. + * + * @param mote + * Button's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiButton(Mote mote) { + // Read class configurations of this mote type + RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig() + .getBooleanValue(ContikiButton.class, "EXTERNAL_INTERRUPT_bool"); + + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"button_interface"}; + } + + /** + * Clicks button. Button will be down for one tick, and then released. + */ + public void clickButton() { + pressButton(); + shouldBeReleased = true; + } + + public void releaseButton() { + moteMem.setByteValueOf("simButtonIsDown", (byte) 0); + + if (moteMem.getByteValueOf("simButtonIsActive") == 1) { + moteMem.setByteValueOf("simButtonChanged", (byte) 1); + + // If mote is inactive, wake it up + if (RAISES_EXTERNAL_INTERRUPT) + mote.setState(Mote.STATE_ACTIVE); + + setChanged(); + notifyObservers(); + } + } + + public void pressButton() { + moteMem.setByteValueOf("simButtonIsDown", (byte) 1); + + if (moteMem.getByteValueOf("simButtonIsActive") == 1) { + moteMem.setByteValueOf("simButtonChanged", (byte) 1); + + // If mote is inactive, wake it up + if (RAISES_EXTERNAL_INTERRUPT) + mote.setState(Mote.STATE_ACTIVE); + + setChanged(); + notifyObservers(); + } + } + + public boolean isPressed() { + return moteMem.getByteValueOf("simButtonIsDown") == 1; + } + + public void doActionsBeforeTick() { + // Nothing to do + } + + public void doActionsAfterTick() { + // If a button is pressed and should be clicked, release it now + if (shouldBeReleased) { + releaseButton(); + shouldBeReleased = false; + } + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + final JButton clickButton = new JButton("Click button"); + + panel.add(clickButton); + + clickButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + clickButton(); + } + }); + + return panel; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + public double energyConsumptionPerTick() { + return 0.0; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiClock.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiClock.java new file mode 100644 index 000000000..b3577c464 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiClock.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2006, 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: ContikiClock.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.util.Collection; +import javax.swing.JPanel; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.Clock; + +/** + * The class represents a clock and controls the core time. + * + * It needs read/write access to the following core variables: + *

    + *
  • int simCurrentTime + *
+ * Dependency core interfaces are: + *
    + *
  • clock_interface + *
+ *

+ * This observable never updates. + * + * @author Fredrik Osterlind + */ +public class ContikiClock extends Clock implements ContikiMoteInterface { + + private Mote mote = null; + private SectionMoteMemory moteMem = null; + + private int timeDrift = 0; + + /** + * Creates a time connected to mote. + * + * @param mote + * Mote to connect this time to. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiClock(Mote mote) { + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"clock_interface"}; + } + + public void setTime(int newTime) { + moteMem.setIntValueOf("simCurrentTime", newTime); + } + + public int getTime() { + return moteMem.getIntValueOf("simCurrentTime"); + } + + public void doActionsBeforeTick() { + // Update core time to correspond with the simulation time + setTime((int) mote.getSimulation().getSimulationTime() + timeDrift); + } + + public void doActionsAfterTick() { + // Nothing to do + } + + public JPanel getInterfaceVisualizer() { + return null; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + public double energyConsumptionPerTick() { + return 0.0; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiIPAddress.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiIPAddress.java new file mode 100644 index 000000000..ccc52fc1e --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiIPAddress.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2006, 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: ContikiIPAddress.java,v 1.1 2006/08/21 12:13:04 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.IPAddress; + +/** + * This class represents an uIP IP address. + * + * It needs write access to the following core variables: + *

    + *
  • char simIPa + *
  • char simIPb + *
  • char simIPc + *
  • char simIPd + *
  • char simIPChanged (1 if new IP should be set) + *
+ *

+ * The new IP will be "simIPa.simIPb.simIPc.simIPd". Dependency core interfaces + * are: + *

    + *
  • ip_interface + *
+ * + * This observable notifies observers if the IP address is set or changed. + * + * @author Fredrik Osterlind + */ +public class ContikiIPAddress extends IPAddress implements ContikiMoteInterface { + private SectionMoteMemory moteMem = null; + private static Logger logger = Logger.getLogger(ContikiIPAddress.class); + private boolean setIP; + + char a = 0, b = 0, c = 0, d = 0; + + /** + * Creates an interface to the IP address at mote. + * + * @param mote + * IP address' mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiIPAddress(Mote mote) { + this.moteMem = (SectionMoteMemory) mote.getMemory(); + setIP = false; + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"ip_interface"}; + } + + public String getIPString() { + return "" + (int) a + "." + (int) b + "." + (int) c + "." + (int) d; + } + + public void setIPString(String ipAddress) { + String[] ipArray = ipAddress.split("\\."); + if (ipArray.length < 4) { + logger.warn("Could not set ip address (" + ipAddress + ")"); + } else + setIPNumber((char) Integer.parseInt(ipArray[0]), (char) Integer + .parseInt(ipArray[1]), (char) Integer.parseInt(ipArray[2]), + (char) Integer.parseInt(ipArray[3])); + } + + public void setIPNumber(char a, char b, char c, char d) { + setIP = true; + this.a = a; + this.b = b; + this.c = c; + this.d = d; + } + + public void doActionsBeforeTick() { + if (setIP) { + setIP = false; + moteMem.setByteValueOf("simIPa", (byte) a); + moteMem.setByteValueOf("simIPb", (byte) b); + moteMem.setByteValueOf("simIPc", (byte) c); + moteMem.setByteValueOf("simIPd", (byte) d); + moteMem.setByteValueOf("simIPChanged", (byte) 1); + + setChanged(); + notifyObservers(); + } + } + + public void doActionsAfterTick() { + // Nothing to do + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + final JLabel ipLabel = new JLabel(); + + ipLabel.setText("Current address: " + (int) a + "." + (int) b + "." + + (int) c + "." + (int) d); + + panel.add(ipLabel); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + ipLabel.setText("Current address: " + (int) a + "." + (int) b + "." + + (int) c + "." + (int) d); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + 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); + } + + public double energyConsumptionPerTick() { + // Virtual interface, does not require any energy + return 0.0; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + Element element; + + // Infinite boolean + element = new Element("ipv4address"); + element.setText(getIPString()); + config.add(element); + + return config; + } + + public void setConfigXML(Collection configXML) { + for (Element element : configXML) { + if (element.getName().equals("ipv4address")) { + setIPString(element.getText()); + } + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiLED.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiLED.java new file mode 100644 index 000000000..13df38ea4 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiLED.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2006, 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: ContikiLED.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.awt.*; +import java.util.*; +import javax.swing.JPanel; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.LED; + +/** + * This class represents three mote LEDs. + * + * It needs read access to the following core variables: + *
    + *
  • char simLedsValue + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • leds_interface + *
+ *

+ * This observable is changed and notifies observers whenever any led has + * changed. + * + * @author Fredrik Osterlind + */ +public class ContikiLED extends LED implements ContikiMoteInterface { + private static Logger logger = Logger.getLogger(ContikiLED.class); + private Mote mote = null; + private SectionMoteMemory moteMem = null; + private byte oldLedValue = 0; + + private static final byte LEDS_GREEN = 1; + private static final byte LEDS_YELLOW = 2; + private static final byte LEDS_RED = 4; + + private static final Color DARK_GREEN = new Color(0, 100, 0); + private static final Color DARK_YELLOW = new Color(100, 100, 0); + private static final Color DARK_RED = new Color(100, 0, 0); + private static final Color GREEN = new Color(0, 255, 0); + private static final Color YELLOW = new Color(255, 255, 0); + private static final Color RED = new Color(255, 0, 0); + + private double myEnergyConsumption = 0.0; + + /** + * Approximate energy consumption of a green led (mA). ESB measured value: + * 5.69 mA. TODO Measure energy consumption + */ + public final double ENERGY_CONSUMPTION_GREEN_LED; + + /** + * Approximate energy consumption of a yellow led (mA). ESB measured value: + * 5.69 mA. TODO Measure energy consumption + */ + public final double ENERGY_CONSUMPTION_YELLOW_LED; + + /** + * Approximate energy consumption of a red led (mA). ESB measured value: 5.69 + * mA. + */ + public final double ENERGY_CONSUMPTION_RED_LED; + + private double energyOfGreenLedPerTick = -1; + private double energyOfYellowLedPerTick = -1; + private double energyOfRedLedPerTick = -1; + + public ContikiLED() { + ENERGY_CONSUMPTION_GREEN_LED = 0; + ENERGY_CONSUMPTION_YELLOW_LED = 0; + ENERGY_CONSUMPTION_RED_LED = 0; + } + + /** + * Creates an interface to the led at mote. + * + * @param mote + * Led's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiLED(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_GREEN_LED = mote.getType().getConfig() + .getDoubleValue(ContikiLED.class, "GREEN_LED_CONSUMPTION_mA"); + ENERGY_CONSUMPTION_YELLOW_LED = mote.getType().getConfig() + .getDoubleValue(ContikiLED.class, "YELLOW_LED_CONSUMPTION_mA"); + ENERGY_CONSUMPTION_RED_LED = mote.getType().getConfig() + .getDoubleValue(ContikiLED.class, "RED_LED_CONSUMPTION_mA"); + + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + + if (energyOfGreenLedPerTick < 0) { + energyOfGreenLedPerTick = ENERGY_CONSUMPTION_GREEN_LED + * mote.getSimulation().getTickTimeInSeconds(); + energyOfYellowLedPerTick = ENERGY_CONSUMPTION_YELLOW_LED + * mote.getSimulation().getTickTimeInSeconds(); + energyOfRedLedPerTick = ENERGY_CONSUMPTION_RED_LED + * mote.getSimulation().getTickTimeInSeconds(); + } + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"leds_interface"}; + } + + public boolean isAnyOn() { + return oldLedValue > 0; + } + + public boolean isGreenOn() { + return (oldLedValue & LEDS_GREEN) > 0; + } + + public boolean isYellowOn() { + return (oldLedValue & LEDS_YELLOW) > 0; + } + + public boolean isRedOn() { + return (oldLedValue & LEDS_RED) > 0; + } + + public void doActionsBeforeTick() { + // Nothing to do + } + + public void doActionsAfterTick() { + if (checkLedStatus()) { + this.setChanged(); + this.notifyObservers(mote); + } + } + + private boolean checkLedStatus() { + boolean ledChanged; + + byte newLedsValue = moteMem.getByteValueOf("simLedsValue"); + if (newLedsValue != oldLedValue) { + ledChanged = true; + } else { + ledChanged = false; + } + + myEnergyConsumption = 0.0; + if ((newLedsValue & LEDS_GREEN) > 0) + myEnergyConsumption += energyOfGreenLedPerTick; + if ((newLedsValue & LEDS_YELLOW) > 0) + myEnergyConsumption += energyOfYellowLedPerTick; + if ((newLedsValue & LEDS_RED) > 0) + myEnergyConsumption += energyOfRedLedPerTick; + + oldLedValue = newLedsValue; + return ledChanged; + } + + public JPanel getInterfaceVisualizer() { + final JPanel panel = new JPanel() { + public void paintComponent(Graphics g) { + super.paintComponent(g); + + if (isGreenOn()) { + g.setColor(GREEN); + g.fillOval(20, 20, 20, 20); + } else { + g.setColor(DARK_GREEN); + g.fillOval(20, 20, 20, 20); + } + + if (isYellowOn()) { + g.setColor(YELLOW); + g.fillOval(60, 20, 20, 20); + } else { + g.setColor(DARK_YELLOW); + g.fillOval(60, 20, 20, 20); + } + + if (isRedOn()) { + g.setColor(RED); + g.fillOval(100, 20, 20, 20); + } else { + g.setColor(DARK_RED); + g.fillOval(100, 20, 20, 20); + } + } + }; + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + panel.repaint(); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + panel.putClientProperty("intf_obs", observer); + + panel.setMinimumSize(new Dimension(140, 60)); + panel.setPreferredSize(new Dimension(140, 60)); + + 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 double energyConsumptionPerTick() { + return myEnergyConsumption; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiLog.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiLog.java new file mode 100644 index 000000000..755a13e3a --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiLog.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2006, 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: ContikiLog.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.awt.*; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.Log; + + +/** + * The class Log is an abstract interface to a mote's logging output. It needs + * read access to the following core variables: + *

    + *
  • char simLoggedFlag + * (1=mote has new outgoing log messages, else no new) + *
  • int simLoggedLength + * (length of new log message) + *
  • byte[] simLoggedData (data of new log messages) + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • simlog_interface + *
+ *

+ * This observable is changed and notifies observers whenever a log message has + * been received from the core (checked after each tick). The public method + * getLastLogMessages gives access to the last log message(s). + * + * @author Fredrik Osterlind + */ +public class ContikiLog extends Log implements ContikiMoteInterface { + private static Logger logger = Logger.getLogger(ContikiLog.class); + private Mote mote = null; + private SectionMoteMemory moteMem = null; + + private String lastLogMessage = null; + + /** + * Creates an interface to mote's logging output. + * + * @param mote Log's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiLog(Mote mote) { + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[] { "simlog_interface" }; + } + + public void doActionsBeforeTick() { + // Nothing to do + } + + public void doActionsAfterTick() { + if (moteMem.getByteValueOf("simLoggedFlag") == 1) { + int totalLength = moteMem.getIntValueOf("simLoggedLength"); + byte[] bytes = moteMem.getByteArray("simLoggedData", totalLength); + char[] chars = new char[bytes.length]; + for (int i=0; i < chars.length; i++) + chars[i] = (char) bytes[i]; + + String message = String.valueOf(chars); + lastLogMessage = message; + + moteMem.setByteValueOf("simLoggedFlag", (byte) 0); + moteMem.setIntValueOf("simLoggedLength", (int) 0); + + this.setChanged(); + this.notifyObservers(mote); + } + } + + public String getLastLogMessages() { + return lastLogMessage; + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + final JTextArea logTextPane = new JTextArea(); + logTextPane.setOpaque(false); + logTextPane.setEditable(false); + + if (lastLogMessage == null) + logTextPane.setText(""); + else + logTextPane.append(lastLogMessage); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + logTextPane.append(lastLogMessage); + logTextPane.setCaretPosition(logTextPane.getDocument().getLength()); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + panel.putClientProperty("intf_obs", observer); + + JScrollPane scrollPane = new JScrollPane(logTextPane); + scrollPane.setPreferredSize(new Dimension(100,100)); + panel.add(BorderLayout.NORTH, new JLabel("Last log messages:")); + panel.add(BorderLayout.CENTER, scrollPane); + 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 double energyConsumptionPerTick() { + // Does not require energy + return 0.0; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiMoteID.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiMoteID.java new file mode 100644 index 000000000..f080c6746 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiMoteID.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2006, 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: ContikiMoteID.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.MoteID; + +/** + * Ths class represents a mote ID number. + * + * It needs write access to the following core variables: + *

    + *
  • int simMoteID + *
  • char simMoteIDChanged + *
+ * When the mote id is set or changed, the random generator will also be seeded + * with this id (core function random_init()). + *

+ * Dependency core interfaces are: + *

    + *
  • moteid_interface + *
+ * This observable notifies observers when the mote ID is set or changed. + * + * @author Fredrik Osterlind + */ +public class ContikiMoteID extends MoteID implements ContikiMoteInterface { + private SectionMoteMemory moteMem = null; + private static Logger logger = Logger.getLogger(ContikiMoteID.class); + private boolean setMoteID; + + int moteID = 0; + + /** + * Creates an interface to the mote ID at mote. + * + * @param mote + * Mote ID's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiMoteID(Mote mote) { + this.moteMem = (SectionMoteMemory) mote.getMemory(); + setMoteID = false; + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"moteid_interface"}; + } + + public int getMoteID() { + return moteID; + } + + public void setMoteID(int newID) { + setMoteID = true; + moteID = newID; + + setChanged(); + notifyObservers(); + } + + public void doActionsBeforeTick() { + if (setMoteID) { + setMoteID = false; + moteMem.setIntValueOf("simMoteID", moteID); + moteMem.setByteValueOf("simMoteIDChanged", (byte) 1); + } + setChanged(); + notifyObservers(); + } + + public void doActionsAfterTick() { + // Nothing to do + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + final JLabel idLabel = new JLabel(); + + idLabel.setText("Mote ID: " + moteID); + + panel.add(idLabel); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + idLabel.setText("Mote ID: " + moteID); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + 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); + } + + public double energyConsumptionPerTick() { + return 0.0; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + Element element; + + // Infinite boolean + element = new Element("id"); + element.setText(Integer.toString(moteID)); + config.add(element); + + return config; + } + + public void setConfigXML(Collection configXML) { + for (Element element : configXML) { + if (element.getName().equals("id")) { + setMoteID(Integer.parseInt(element.getText())); + } + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiPIR.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiPIR.java new file mode 100644 index 000000000..13cc4d032 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiPIR.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006, 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: ContikiPIR.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.awt.event.*; +import java.util.Collection; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.PIR; + +/** + * This class represents a passive infrared sensor. + * + * It needs read/write access to the following core variables: + *
    + *
  • char simPirChanged (1=changed, else not changed) + *
  • char simPirIsActive (1=active, else inactive) + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • pir_interface + *
+ *

+ * This observable notifies observers if a change is discovered by the PIR. + * + * @author Fredrik Osterlind + */ +public class ContikiPIR extends PIR implements ContikiMoteInterface { + private static Logger logger = Logger.getLogger(ContikiPIR.class); + + /** + * Approximate energy consumption of an active PIR sensor. ESB measured energy + * consumption is 0.4 mA. TODO Measure energy consumption + */ + public final double ENERGY_CONSUMPTION_PIR_mA; + + private final boolean RAISES_EXTERNAL_INTERRUPT; + + private double energyActivePerTick = -1; + + private Mote mote; + private SectionMoteMemory moteMem; + private double myEnergyConsumption = 0.0; + + /** + * Creates an interface to the pir at mote. + * + * @param mote + * Button's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiPIR(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_PIR_mA = mote.getType().getConfig().getDoubleValue( + ContikiPIR.class, "ACTIVE_CONSUMPTION_mA"); + RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig() + .getBooleanValue(ContikiPIR.class, "EXTERNAL_INTERRUPT_bool"); + + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + + if (energyActivePerTick < 0) + energyActivePerTick = ENERGY_CONSUMPTION_PIR_mA + * mote.getSimulation().getTickTimeInSeconds(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"pir_interface"}; + } + + public void triggerChange() { + if (moteMem.getByteValueOf("simPirIsActive") == 1) { + moteMem.setByteValueOf("simPirChanged", (byte) 1); + + // If mote is inactive, wake it up + if (RAISES_EXTERNAL_INTERRUPT) + mote.setState(Mote.STATE_ACTIVE); + + this.setChanged(); + this.notifyObservers(); + } + } + + public void doActionsBeforeTick() { + if (moteMem.getByteValueOf("simPirIsActive") == 1) { + myEnergyConsumption = energyActivePerTick; + } else + myEnergyConsumption = 0.0; + } + + public void doActionsAfterTick() { + // Nothing to do + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + final JButton clickButton = new JButton("Signal PIR"); + + panel.add(clickButton); + + clickButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + triggerChange(); + } + }); + + return panel; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + public double energyConsumptionPerTick() { + return myEnergyConsumption; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java new file mode 100644 index 000000000..6ed40450d --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2006, 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: ContikiRS232.java,v 1.1 2006/08/21 12:13:04 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; + +/** + * The class represents a simple RS232/Serial interface (only shows String + * format). + * + * It needs read/write access to the following core variables: + *

    + *
  • char simSerialSendingFlag (1=mote is sending data) + *
  • int simSerialSendingLength (length of data being sent from mote) + *
  • byte[] simSerialSendingData (data being sent from mote) + *
  • char simSerialRecevingFlag (1=mote is receving data) + *
  • int simSerialReceivingLength (length of data being received at mote) + *
  • byte[] simSerialReceivingData (data being received at mote) + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • rs232_interface + *
+ *

+ * This observable is changed and notifies observers whenever a serial message + * has been received from the core (checked after each tick). The public method + * getSerialMessages gives access to the last data. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Serial port (RS232)") +public class ContikiRS232 extends MoteInterface implements ContikiMoteInterface { + private static Logger logger = Logger.getLogger(ContikiRS232.class); + + private Mote mote = null; + private SectionMoteMemory moteMem = null; + + private String lastSerialMessage = null; + + private final boolean RAISES_EXTERNAL_INTERRUPT; + private JTextArea logTextPane = null; + + /** + * Approximate energy consumption of every sent character over RS232 (mQ). + */ + public final double ENERGY_CONSUMPTION_PER_CHAR_mQ; + + private double myEnergyConsumption = 0.0; + + /** + * Creates an interface to the RS232 at mote. + * + * @param mote + * RS232's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiRS232(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_PER_CHAR_mQ = mote.getType().getConfig() + .getDoubleValue(ContikiRS232.class, "CONSUMPTION_PER_CHAR_mQ"); + RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig() + .getBooleanValue(ContikiRS232.class, "EXTERNAL_INTERRUPT_bool"); + + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"rs232_interface"}; + } + + public void doActionsBeforeTick() { + // Nothing to do + } + + public void doActionsAfterTick() { + if (moteMem.getByteValueOf("simSerialSendingFlag") == 1) { + int totalLength = moteMem.getIntValueOf("simSerialSendingLength"); + byte[] bytes = moteMem.getByteArray("simSerialSendingData", totalLength); + char[] chars = new char[bytes.length]; + for (int i = 0; i < chars.length; i++) + chars[i] = (char) bytes[i]; + + myEnergyConsumption = ENERGY_CONSUMPTION_PER_CHAR_mQ * totalLength; + + String message = String.valueOf(chars); + lastSerialMessage = message; + + moteMem.setByteValueOf("simSerialSendingFlag", (byte) 0); + moteMem.setIntValueOf("simSerialSendingLength", (int) 0); + + this.setChanged(); + this.notifyObservers(mote); + } else + myEnergyConsumption = 0.0; + } + + /** + * Returns all serial messages sent by mote the last tick that anything was + * sent. + * + * @return Last serial messages sent by mote. + */ + public String getSerialMessages() { + return lastSerialMessage; + } + + /** + * Send a serial message to mote. + * + * @param message + * Message that mote should receive + */ + public void sendSerialMessage(String message) { + + if (logTextPane != null) { + logTextPane.append("> " + message + "\n"); + } + + // Flag for incoming data + moteMem.setByteValueOf("simSerialReceivingFlag", (byte) 1); + + byte[] dataToAppend = message.getBytes(); + + // Increase receiving size + int oldSize = moteMem.getIntValueOf("simSerialReceivingLength"); + moteMem.setIntValueOf("simSerialReceivingLength", oldSize + + dataToAppend.length); + int newSize = moteMem.getIntValueOf("simSerialReceivingLength"); + + // Write buffer characters + byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize); + byte[] newData = new byte[newSize]; + + for (int i = 0; i < oldData.length; i++) + newData[i] = oldData[i]; + + for (int i = 0; i < message.length(); i++) + newData[i + oldSize] = dataToAppend[i]; + + moteMem.setByteArray("simSerialReceivingData", newData); + + if (RAISES_EXTERNAL_INTERRUPT) + mote.setState(Mote.STATE_ACTIVE); + + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + + if (logTextPane == null) + logTextPane = new JTextArea(); + + // Send RS232 data visualizer + JPanel sendPane = new JPanel(); + final JTextField sendTextField = new JTextField(15); + JButton sendButton = new JButton("Send data"); + sendButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + sendSerialMessage(sendTextField.getText()); + } + }); + sendPane.add(BorderLayout.WEST, sendTextField); + sendPane.add(BorderLayout.EAST, sendButton); + + // Receive RS232 data visualizer + logTextPane.setOpaque(false); + logTextPane.setEditable(false); + + if (lastSerialMessage == null) + logTextPane.setText(""); + else + logTextPane.append(lastSerialMessage); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + logTextPane.append("< " + lastSerialMessage + "\n"); + logTextPane.setCaretPosition(logTextPane.getDocument().getLength()); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + panel.putClientProperty("intf_obs", observer); + + JScrollPane scrollPane = new JScrollPane(logTextPane); + scrollPane.setPreferredSize(new Dimension(100, 100)); + panel.add(BorderLayout.NORTH, new JLabel("Last serial data:")); + panel.add(BorderLayout.CENTER, scrollPane); + panel.add(BorderLayout.SOUTH, sendPane); + 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 double energyConsumptionPerTick() { + return myEnergyConsumption; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java new file mode 100644 index 000000000..89d4663d4 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2006, 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: ContikiRadio.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; +import se.sics.cooja.interfaces.Radio; + +/** + * This class represents a radio transciever. + * + * It needs read/write access to the following core variables: + *

    + *
  • char simSentPacket (1=mote has new outgoing data, else no new outgoing + * data) + *
  • char simReceivedPacket (1=mote has new incoming data, else no new + * incoming data) + *
  • char simEtherBusy (1=ether is busy, MAC may try to resend later, else + * not busy) + *
  • int simReceivedPacketSize (size of new received data packet) + *
  • int simSentPacketSize (size of new sent data packet) + *
  • byte[] simSentPacketData (data of new sent data packet) + *
  • byte[] simReceivedPacketData (data of new received data packet) + *
  • char simRadioHWOn (radio hardware status (on/off)) + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • radio_interface + *
+ *

+ * This observable is changed and notifies observers whenever either the send + * status or listen status is changed. If current listen status is HEARS_PACKET + * just before a mote tick, the current packet data is transferred to the core. + * Otherwise no data will be transferred. If core has sent a packet, current + * sent status will be set to SENT_SOMETHING when returning from the mote tick + * that sent the packet. This status will be reset to SENT_NOTHING just before + * next tick. + * + * @author Fredrik Osterlind + */ +public class ContikiRadio extends Radio implements ContikiMoteInterface { + private Mote myMote; + private SectionMoteMemory myMoteMemory; + private static Logger logger = Logger.getLogger(ContikiRadio.class); + + /** + * Approximate energy consumption of an active radio. ESB measured energy + * consumption is 5 mA. TODO Measure energy consumption + */ + public final double ENERGY_CONSUMPTION_RADIO_mA; + + private final boolean RAISES_EXTERNAL_INTERRUPT; + + private double energyActiveRadioPerTick = -1; + + private int mySendState = SENT_NOTHING; + private int myListenState = HEARS_NOTHING; + + private byte[] packetToMote = null; + private byte[] packetFromMote = null; + + private boolean radioOn = true; + + private double myEnergyConsumption=0.0; + + /** + * Creates an interface to the radio at mote. + * + * @param mote + * Radio's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiRadio(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_RADIO_mA = mote.getType().getConfig().getDoubleValue(ContikiRadio.class, "ACTIVE_CONSUMPTION_mA"); + RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig().getBooleanValue(ContikiRadio.class, "EXTERNAL_INTERRUPT_bool"); + + this.myMote = mote; + this.myMoteMemory = (SectionMoteMemory) mote.getMemory(); + + if (energyActiveRadioPerTick < 0) + energyActiveRadioPerTick = ENERGY_CONSUMPTION_RADIO_mA * mote.getSimulation().getTickTimeInSeconds(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[] { "radio_interface" }; + } + + public byte[] getLastPacketSent() { + return packetFromMote; + } + + public byte[] getLastPacketReceived() { + return packetToMote; + } + + public void receivePacket(byte[] data) { + packetToMote = data; + } + + public int getSendState() { + return mySendState; + } + + public int getListenState() { + return myListenState; + } + + public void setListenState(int newStatus) { + if (newStatus != myListenState) { + myListenState = newStatus; + this.setChanged(); + this.notifyObservers(myMote.getInterfaces().getPosition()); + } + + // If mote is inactive, wake it up + if (RAISES_EXTERNAL_INTERRUPT) + myMote.setState(Mote.STATE_ACTIVE); + } + + public void advanceListenState() { + if (myListenState == HEARS_NOTHING) { + setListenState(HEARS_PACKET); + } else + setListenState(HEARS_NOISE); + } + + public void doActionsBeforeTick() { + // If radio hardware is turned off, we don't need to do anything.. + if (!radioOn) { + myEnergyConsumption = 0.0; + return; + } + myEnergyConsumption = energyActiveRadioPerTick; + + // Set ether status + if (getListenState() == HEARS_PACKET || + getListenState() == HEARS_NOISE || + getSendState() == SENT_SOMETHING) { + myMoteMemory.setByteValueOf("simEtherBusy", (byte) 1); + } else { + myMoteMemory.setByteValueOf("simEtherBusy", (byte) 0); + } + + if (getListenState() == HEARS_NOTHING) { + // Haven't heard anything, nothing to do + } else if (getListenState() == HEARS_PACKET) { + // Heard only one packet, transfer to mote ok + myMoteMemory.setByteValueOf("simReceivedPacket", (byte) 1); + myMoteMemory.setIntValueOf("simReceivedPacketSize", packetToMote.length); + myMoteMemory.setByteArray("simReceivedPacketData", packetToMote); + } else if (getListenState() == HEARS_NOISE) { + // Heard several packets or noise, transfer failed + } + + // Reset send flag + setSendStatus(SENT_NOTHING); + } + + public void doActionsAfterTick() { + // Check new radio hardware status + if (myMoteMemory.getByteValueOf("simRadioHWOn") == 1) { + radioOn = true; + } else { + radioOn = false; + return; + } + + // Reset listen flag + setListenState(HEARS_NOTHING); + + if (fetchPacketFromCore()) { + setSendStatus(SENT_SOMETHING); + } + } + + private void setSendStatus(int newStatus) { + if (newStatus != mySendState) { + mySendState = newStatus; + this.setChanged(); + this.notifyObservers(myMote.getInterfaces().getPosition()); + } + } + + private boolean fetchPacketFromCore() { + if (myMoteMemory.getByteValueOf("simSentPacket") == 1) { + // TODO Increase energy consumption, we are sending a packet... + + myMoteMemory.setByteValueOf("simSentPacket", (byte) 0); + + int size = myMoteMemory.getIntValueOf("simSentPacketSize"); + + packetFromMote = myMoteMemory.getByteArray("simSentPacketData", size); + + myMoteMemory.setIntValueOf("simSentPacketSize", 0); + + return true; + } + return false; + } + + public JPanel getInterfaceVisualizer() { + // Location + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + final JLabel listenLabel = new JLabel(); + final JLabel sendLabel = new JLabel(); + + if (getListenState() == HEARS_NOISE) + listenLabel.setText("Current listen status: hears noise"); + else if (getListenState() == HEARS_NOTHING) + listenLabel.setText("Current listen status: hears nothing"); + else if (getListenState() == HEARS_PACKET) + listenLabel.setText("Current listen status: hears a packet"); + + if (getSendState() == SENT_NOTHING) + sendLabel.setText("Current sending status: sent nothing"); + else if (getSendState() == SENT_SOMETHING) + sendLabel.setText("Current sending status: sent a packet"); + + panel.add(listenLabel); + panel.add(sendLabel); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + if (getListenState() == HEARS_NOISE) + listenLabel.setText("Current listen status: hears noise"); + else if (getListenState() == HEARS_NOTHING) + listenLabel.setText("Current listen status: hears nothing"); + else if (getListenState() == HEARS_PACKET) + listenLabel.setText("Current listen status: hears a packet"); + + if (getSendState() == SENT_NOTHING) + sendLabel.setText("Current sending status: sent nothing"); + else if (getSendState() == SENT_SOMETHING) + sendLabel.setText("Current sending status: sent a packet"); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + 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); + } + + public double energyConsumptionPerTick() { + return myEnergyConsumption; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiVib.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiVib.java new file mode 100644 index 000000000..e826af0b6 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiVib.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006, 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: ContikiVib.java,v 1.1 2006/08/21 12:13:05 fros4943 Exp $ + */ + +package se.sics.cooja.contikimote.interfaces; + +import java.awt.event.*; +import java.util.Collection; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.contikimote.ContikiMoteInterface; + +/** + * This class represents a vibration sensor. + * + * It needs read/write access to the following core variables: + *

    + *
  • char simVibChanged (1=changed, else not changed) + *
  • char simVibIsActive (1=active, else inactive) + *
+ *

+ * Dependency core interfaces are: + *

    + *
  • vib_interface + *
+ *

+ * This observable never notifies observers. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Vibration sensor") +public class ContikiVib extends MoteInterface implements ContikiMoteInterface { + private static Logger logger = Logger.getLogger(ContikiVib.class); + + /** + * Approximate energy consumption of an active vibrator sensor. ESB measured + * energy consumption is 1.58 mA. + */ + public final double ENERGY_CONSUMPTION_VIB_mA; + + private final boolean RAISES_EXTERNAL_INTERRUPT; + + private double energyActiveVibPerTick = -1; + + private Mote mote; + private SectionMoteMemory moteMem; + private double myEnergyConsumption = 0.0; + + /** + * Creates an interface to the vibration sensor at mote. + * + * @param mote + * Vib's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public ContikiVib(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_VIB_mA = mote.getType().getConfig().getDoubleValue( + ContikiVib.class, "ACTIVE_CONSUMPTION_mA"); + RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig() + .getBooleanValue(ContikiVib.class, "EXTERNAL_INTERRUPT_bool"); + + this.mote = mote; + this.moteMem = (SectionMoteMemory) mote.getMemory(); + + if (energyActiveVibPerTick < 0) + energyActiveVibPerTick = ENERGY_CONSUMPTION_VIB_mA + * mote.getSimulation().getTickTimeInSeconds(); + } + + public static String[] getCoreInterfaceDependencies() { + return new String[]{"vib_interface"}; + } + + /** + * Simulates a change in the vibration sensor. + */ + public void triggerChange() { + if (moteMem.getByteValueOf("simVibIsActive") == 1) { + moteMem.setByteValueOf("simVibChanged", (byte) 1); + + // If mote is inactive, wake it up + if (RAISES_EXTERNAL_INTERRUPT) + mote.setState(Mote.STATE_ACTIVE); + } + } + + public void doActionsBeforeTick() { + if (moteMem.getByteValueOf("simVibIsActive") == 1) { + myEnergyConsumption = energyActiveVibPerTick; // ESB measured value + } else + myEnergyConsumption = 0.0; + } + + public void doActionsAfterTick() { + // Nothing to do + } + + public JPanel getInterfaceVisualizer() { + JPanel panel = new JPanel(); + final JButton clickButton = new JButton("Vibrate!"); + + panel.add(clickButton); + + clickButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + triggerChange(); + } + }); + + return panel; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + public double energyConsumptionPerTick() { + return myEnergyConsumption; + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML) { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib1.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib1.java new file mode 100644 index 000000000..53e1cad79 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib1.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib1.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib1 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib1(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib2.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib2.java new file mode 100644 index 000000000..adee132f5 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib2.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib2.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib2 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib2(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib3.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib3.java new file mode 100644 index 000000000..71b74342f --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib3.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib3.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib3 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib3(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib4.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib4.java new file mode 100644 index 000000000..2e45617b3 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib4.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib4.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib4 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib4(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib5.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib5.java new file mode 100644 index 000000000..7b10f0cf2 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib5.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib5.java,v 1.1 2006/08/21 12:12:57 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib5 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib5(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib6.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib6.java new file mode 100644 index 000000000..db0d160d3 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib6.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib6.java,v 1.1 2006/08/21 12:12:58 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib6 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib6(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib7.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib7.java new file mode 100644 index 000000000..6e2815708 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib7.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib7.java,v 1.1 2006/08/21 12:12:58 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib7 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib7(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/corecomm/Lib8.java b/tools/cooja/java/se/sics/cooja/corecomm/Lib8.java new file mode 100644 index 000000000..ceb3abf63 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/corecomm/Lib8.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Lib8.java,v 1.1 2006/08/21 12:12:58 fros4943 Exp $ + */ + +package se.sics.cooja.corecomm; +import java.io.File; + +import se.sics.cooja.*; + +/** + * @see CoreComm + * @author Fredrik Osterlind + */ +public class Lib8 extends CoreComm { + + /** + * Loads library libFile. + * + * @see CoreComm + * @param libFile Library file + */ + public Lib8(File libFile) { + System.load(libFile.getAbsolutePath()); + init(); + } + + public native void tick(); + public native void init(); + public native int getReferenceAbsAddr(); + public native byte[] getMemory(int start, int length); + public native void setMemory(int start, int length, byte[] mem); + +} diff --git a/tools/cooja/java/se/sics/cooja/dialogs/AddMoteDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/AddMoteDialog.java new file mode 100644 index 000000000..01328fb85 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/AddMoteDialog.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2006, 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: AddMoteDialog.java,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + */ + +package se.sics.cooja.dialogs; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; +import java.text.*; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.*; + +/** + * A dialog for adding motes. + * + * @author Fredrik Osterlind + */ +public class AddMoteDialog extends JDialog { + + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(AddMoteDialog.class); + + private AddMotesEventHandler myEventHandler = new AddMotesEventHandler(); + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + private Vector newMotes = null; + + private boolean settingsOK = true; + private JButton addButton; + + private MoteType moteType = null; + + private JFormattedTextField numberOfMotesField, startX, endX, startY, endY, + startZ, endZ; + private JComboBox positionDistributionBox, ipDistributionBox; + + /** + * Shows a dialog which enables a user to create and add motes of the given + * type. + * + * @param parentFrame + * Parent frame for dialog + * @param moteType + * Mote type + * @return New motes or null if aborted + */ + public static Vector showDialog(Frame parentFrame, MoteType moteType) { + + AddMoteDialog myDialog = new AddMoteDialog(parentFrame, moteType); + myDialog.setLocationRelativeTo(parentFrame); + myDialog.checkSettings(); + + if (myDialog != null) { + myDialog.setVisible(true); + } + return myDialog.newMotes; + } + + private AddMoteDialog(Frame frame, MoteType moteType) { + super(frame, "Add motes (" + moteType.getDescription() + ")", true); + this.moteType = moteType; + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + JFormattedTextField numberField; + JButton button; + JComboBox comboBox; + NumberFormat integerFormat = NumberFormat.getIntegerInstance(); + NumberFormat doubleFormat = NumberFormat.getNumberInstance(); + + // BOTTOM BUTTON PART + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + buttonPane.add(Box.createHorizontalGlue()); + + button = new JButton("Cancel"); + button.setActionCommand("cancel"); + button.addActionListener(myEventHandler); + buttonPane.add(button); + + button = new JButton("Create and Add"); + button.setEnabled(settingsOK); + button.setActionCommand("add"); + button.addActionListener(myEventHandler); + this.getRootPane().setDefaultButton(button); + addButton = button; + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(button); + + // MAIN PART + + // Number of new motes + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Number of new motes"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + numberField = new JFormattedTextField(integerFormat); + numberField.setValue(new Integer(1)); + numberField.setColumns(10); + numberField.addPropertyChangeListener("value", myEventHandler); + numberOfMotesField = numberField; + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(numberField); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // IP address distribution + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("IP Addressing"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + Vector> ipDistributors = GUI.currentGUI + .getRegisteredIPDistributors(); + String[] ipDistributions = new String[ipDistributors.size()]; + for (int i = 0; i < ipDistributions.length; i++) + ipDistributions[i] = GUI.getDescriptionOf(ipDistributors.get(i)); + + comboBox = new JComboBox(ipDistributions); + + comboBox.setSelectedIndex(0); + comboBox.addActionListener(myEventHandler); + comboBox.addFocusListener(myEventHandler); + ipDistributionBox = comboBox; + label.setLabelFor(comboBox); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(comboBox); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Position distribution + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Positioning"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + Vector> positioners = GUI.currentGUI + .getRegisteredPositioners(); + String[] posDistributions = new String[positioners.size()]; + for (int i = 0; i < posDistributions.length; i++) + posDistributions[i] = GUI.getDescriptionOf(positioners.get(i)); + + comboBox = new JComboBox(posDistributions); + + comboBox.setSelectedIndex(0); + comboBox.addActionListener(myEventHandler); + comboBox.addFocusListener(myEventHandler); + positionDistributionBox = comboBox; + label.setLabelFor(comboBox); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(comboBox); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Position interval X + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + + label = new JLabel("Position interval"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + + label = new JLabel("X "); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + + numberField = new JFormattedTextField(doubleFormat); + numberField.setValue(new Double(0.0)); + numberField.setColumns(4); + numberField.addPropertyChangeListener("value", myEventHandler); + startX = numberField; + smallPane.add(numberField); + smallPane.add(Box.createHorizontalStrut(10)); + + label = new JLabel("<->"); + label.setPreferredSize(new Dimension(LABEL_WIDTH / 4, LABEL_HEIGHT)); + smallPane.add(label); + + numberField = new JFormattedTextField(doubleFormat); + numberField.setValue(new Double(100.0)); + numberField.setColumns(4); + numberField.addPropertyChangeListener("value", myEventHandler); + endX = numberField; + smallPane.add(numberField); + smallPane.add(Box.createHorizontalStrut(10)); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Position interval Y + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + + label = new JLabel(""); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + + label = new JLabel("Y "); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + + numberField = new JFormattedTextField(doubleFormat); + numberField.setValue(new Double(0.0)); + numberField.setColumns(4); + numberField.addPropertyChangeListener("value", myEventHandler); + startY = numberField; + smallPane.add(numberField); + smallPane.add(Box.createHorizontalStrut(10)); + + label = new JLabel("<->"); + label.setPreferredSize(new Dimension(LABEL_WIDTH / 4, LABEL_HEIGHT)); + smallPane.add(label); + + numberField = new JFormattedTextField(doubleFormat); + numberField.setValue(new Double(100.0)); + numberField.setColumns(4); + numberField.addPropertyChangeListener("value", myEventHandler); + endY = numberField; + smallPane.add(numberField); + smallPane.add(Box.createHorizontalStrut(10)); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + // Position interval Z + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + + label = new JLabel(""); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + + label = new JLabel("Z "); + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + + numberField = new JFormattedTextField(doubleFormat); + numberField.setValue(new Double(0.0)); + numberField.setColumns(4); + numberField.addPropertyChangeListener("value", myEventHandler); + startZ = numberField; + smallPane.add(numberField); + smallPane.add(Box.createHorizontalStrut(10)); + + label = new JLabel("<->"); + label.setPreferredSize(new Dimension(LABEL_WIDTH / 4, LABEL_HEIGHT)); + smallPane.add(label); + + numberField = new JFormattedTextField(doubleFormat); + numberField.setValue(new Double(0.0)); + numberField.setColumns(4); + numberField.addPropertyChangeListener("value", myEventHandler); + endZ = numberField; + smallPane.add(numberField); + smallPane.add(Box.createHorizontalStrut(10)); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + Container contentPane = getContentPane(); + contentPane.add(mainPane, BorderLayout.NORTH); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + pack(); + } + + private void checkSettings() { + // Check settings + settingsOK = true; + + // Check X interval + if (((Number) startX.getValue()).doubleValue() > ((Number) endX.getValue()) + .doubleValue()) { + startX.setBackground(Color.RED); + startX.setToolTipText("Malformed interval"); + endX.setBackground(Color.RED); + endX.setToolTipText("Malformed interval"); + settingsOK = false; + } else { + startX.setBackground(Color.WHITE); + startX.setToolTipText(null); + endX.setBackground(Color.WHITE); + endX.setToolTipText(null); + } + + // Check Y interval + if (((Number) startY.getValue()).doubleValue() > ((Number) endY.getValue()) + .doubleValue()) { + startY.setBackground(Color.RED); + startY.setToolTipText("Malformed interval"); + endY.setBackground(Color.RED); + endY.setToolTipText("Malformed interval"); + settingsOK = false; + } else { + startY.setBackground(Color.WHITE); + startY.setToolTipText(null); + endY.setBackground(Color.WHITE); + endY.setToolTipText(null); + } + + // Check Z interval + if (((Number) startZ.getValue()).doubleValue() > ((Number) endZ.getValue()) + .doubleValue()) { + startZ.setBackground(Color.RED); + startZ.setToolTipText("Malformed interval"); + endZ.setBackground(Color.RED); + endZ.setToolTipText("Malformed interval"); + settingsOK = false; + } else { + startZ.setBackground(Color.WHITE); + startZ.setToolTipText(null); + endZ.setBackground(Color.WHITE); + endZ.setToolTipText(null); + } + + // Check number of new motes + if (((Number) numberOfMotesField.getValue()).intValue() < 1) { + numberOfMotesField.setBackground(Color.RED); + numberOfMotesField.setToolTipText("Must be >= 1"); + settingsOK = false; + } else { + numberOfMotesField.setBackground(Color.WHITE); + numberOfMotesField.setToolTipText(null); + } + + addButton.setEnabled(settingsOK); + } + + private class AddMotesEventHandler + implements + ActionListener, + FocusListener, + PropertyChangeListener { + public void propertyChange(PropertyChangeEvent e) { + checkSettings(); + } + public void focusGained(FocusEvent e) { + // NOP + } + public void focusLost(FocusEvent e) { + checkSettings(); + } + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("cancel")) { + newMotes = null; + dispose(); + } else if (e.getActionCommand().equals("add")) { + newMotes = new Vector(); + + // Create new motes + int motesToAdd = ((Number) numberOfMotesField.getValue()).intValue(); + while (newMotes.size() < motesToAdd) { + Mote newMote = moteType.generateMote(GUI.currentSimulation); + newMotes.add(newMote); + } + + // Position new motes + Class positionerClass = null; + for (Class positioner : GUI.currentGUI + .getRegisteredPositioners()) { + if (GUI.getDescriptionOf(positioner).equals( + (String) positionDistributionBox.getSelectedItem())) + positionerClass = positioner; + } + + Positioner positioner = Positioner.generateInterface(positionerClass, + ((Number) numberOfMotesField.getValue()).intValue(), + ((Number) startX.getValue()).doubleValue(), ((Number) endX + .getValue()).doubleValue(), ((Number) startY.getValue()) + .doubleValue(), ((Number) endY.getValue()).doubleValue(), + ((Number) startZ.getValue()).doubleValue(), ((Number) endZ + .getValue()).doubleValue()); + + if (positioner == null) { + logger.fatal("Could not create positioner"); + dispose(); + return; + } + + for (int i = 0; i < newMotes.size(); i++) { + Position newPosition = newMotes.get(i).getInterfaces().getPosition(); + if (newPosition != null) { + double[] newPositionArray = positioner.getNextPosition(); + if (newPositionArray.length >= 3) + newPosition.setCoordinates(newPositionArray[0], + newPositionArray[1], newPositionArray[2]); + else if (newPositionArray.length >= 2) + newPosition.setCoordinates(newPositionArray[0], + newPositionArray[1], 0); + else if (newPositionArray.length >= 1) + newPosition.setCoordinates(newPositionArray[0], 0, 0); + else + newPosition.setCoordinates(0, 0, 0); + } + } + + // Set unique mote id's for all new motes + int nextMoteID = 1; + for (int i = 0; i < GUI.currentSimulation.getMotesCount(); i++) { + MoteID moteID = GUI.currentSimulation.getMote(i).getInterfaces() + .getMoteID(); + if (moteID != null && moteID.getMoteID() >= nextMoteID) + nextMoteID = moteID.getMoteID() + 1; + } + + for (int i = 0; i < newMotes.size(); i++) { + MoteID moteID = newMotes.get(i).getInterfaces().getMoteID(); + if (moteID != null) { + moteID.setMoteID(nextMoteID++); + } + } + + // IP address new motes + Class ipDistClass = null; + for (Class ipDistributor : GUI.currentGUI + .getRegisteredIPDistributors()) { + if (GUI.getDescriptionOf(ipDistributor).equals( + (String) ipDistributionBox.getSelectedItem())) + ipDistClass = ipDistributor; + } + + IPDistributor ipDistributor = IPDistributor.generateInterface( + ipDistClass, newMotes); + + if (ipDistributor == null) { + logger.fatal("Could not create IP distributor"); + dispose(); + return; + } + + for (int i = 0; i < newMotes.size(); i++) { + String newIPString = ipDistributor.getNextIPAddress(); + if (newMotes.get(i).getInterfaces().getIPAddress() != null) + newMotes.get(i).getInterfaces().getIPAddress().setIPString( + newIPString); + } + + dispose(); + } + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/dialogs/CreateSimDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/CreateSimDialog.java new file mode 100644 index 000000000..f593e4f65 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/CreateSimDialog.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2006, 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: CreateSimDialog.java,v 1.1 2006/08/21 12:13:02 fros4943 Exp $ + */ + +package se.sics.cooja.dialogs; + +import java.awt.*; +import java.awt.event.*; +import java.io.File; +import java.text.*; +import java.util.Vector; + +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * A dialog for creating and configuring a simulation. + * + * @author Fredrik Osterlind + */ +public class CreateSimDialog extends JDialog { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(CreateSimDialog.class); + + private AddSimEventHandler myEventHandler = new AddSimEventHandler(); + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + private Simulation mySimulation = null; + + private CreateSimDialog myDialog; + + private JFormattedTextField delayTime, simulationTime, tickTime; + private JTextField title; + private JComboBox radioMediumBox; + + private JTextField logFilename; + private JCheckBox logCheckBox; + + /** + * Shows a dialog for configuring a simulation. + * + * @param parentFrame Parent frame for dialog + * @param simulationToConfigure Simulation to configure + * @return True if simulation configured correctly + */ + public static boolean showDialog(Frame parentFrame, Simulation simulationToConfigure) { + CreateSimDialog myDialog = new CreateSimDialog(parentFrame); + + myDialog.mySimulation = simulationToConfigure; + + // Set title + if (simulationToConfigure.getTitle() != null) { + // Title already preset + myDialog.title.setText(simulationToConfigure.getTitle()); + } else { + // Suggest title + myDialog.title.setText("[enter simulation title]"); + } + + // Set delay time + myDialog.delayTime.setValue(new Integer(simulationToConfigure.getDelayTime())); + + // Set simulation time + myDialog.simulationTime.setValue(new Integer(simulationToConfigure.getSimulationTime())); + + // Set tick time + myDialog.tickTime.setValue(new Integer(simulationToConfigure.getTickTime())); + + // Select radio medium + if (simulationToConfigure.getRadioMedium() != null) { + Class radioMediumClass = + simulationToConfigure.getRadioMedium().getClass(); + + String currentDescription = GUI.getDescriptionOf(radioMediumClass); + + for (int i=0; i < myDialog.radioMediumBox.getItemCount(); i++) { + String menuDescription = (String) myDialog.radioMediumBox.getItemAt(i); + if (menuDescription.equals(currentDescription)) { + myDialog.radioMediumBox.setSelectedIndex(i); + break; + } + } + } + + // Set position and focus of dialog + myDialog.setLocationRelativeTo(parentFrame); + myDialog.title.requestFocus(); + myDialog.title.select(0, myDialog.title.getText().length()); + + myDialog.setVisible(true); + + if (myDialog.mySimulation != null) { + // Simulation configured correctly + return true; + } + return false; + } + + private CreateSimDialog(Frame frame) { + super(frame, "Create new simulation", true); + + myDialog = this; + + JPanel mainPane = new JPanel(); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + + JLabel label; + JTextField textField; + JPanel smallPane; + JButton button; + JComboBox comboBox; + JFormattedTextField numberField; + NumberFormat integerFormat = NumberFormat.getIntegerInstance(); + + + // BOTTOM BUTTON PART + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + buttonPane.add(Box.createHorizontalGlue()); + + button = new JButton("Cancel"); + button.setActionCommand("cancel"); + button.addActionListener(myEventHandler); + buttonPane.add(button); + + button = new JButton("Create"); + button.setActionCommand("create"); + button.addActionListener(myEventHandler); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + myDialog.rootPane.setDefaultButton(button); + buttonPane.add(button); + + + // MAIN PART + + // Title + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Simulation title"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setText("[no title]"); + textField.setColumns(25); + title = textField; + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(textField); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + // Radio Medium selection + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Radio Medium"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + + Vector radioMediumDescriptions = new Vector(); + for (Class radioMediumClass: GUI.currentGUI.getRegisteredRadioMediums()) { + String description = GUI.getDescriptionOf(radioMediumClass); + radioMediumDescriptions.add(description); + } + + comboBox = new JComboBox(radioMediumDescriptions); + + comboBox.setSelectedIndex(0); + radioMediumBox = comboBox; + label.setLabelFor(comboBox); + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(comboBox); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + + // Radio Medium Logging selection + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + logCheckBox = new JCheckBox("Log all radio traffic?"); + logCheckBox.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + + textField = new JTextField(); + textField.setText("[filename]"); + textField.setColumns(25); + logFilename = textField; + + smallPane.add(logCheckBox); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(textField); + + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + + // Delay time + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Delay time (ms)"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + + numberField = new JFormattedTextField(integerFormat); + numberField.setValue(new Integer(100)); + numberField.setColumns(4); + delayTime = numberField; + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(150)); + smallPane.add(numberField); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + // Simulation start time + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Simulation start time (ms)"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + + numberField = new JFormattedTextField(integerFormat); + numberField.setValue(new Integer(0)); + numberField.setColumns(4); + simulationTime = numberField; + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(150)); + smallPane.add(numberField); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + // Tick time + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Tick time (ms)"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + + numberField = new JFormattedTextField(integerFormat); + numberField.setValue(new Integer(1)); + numberField.setColumns(4); + tickTime = numberField; + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(150)); + smallPane.add(numberField); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + + mainPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + Container contentPane = getContentPane(); + contentPane.add(mainPane, BorderLayout.NORTH); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + pack(); + } + + private class AddSimEventHandler implements ActionListener { + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("cancel")) { + mySimulation = null; + dispose(); + } else if (e.getActionCommand().equals("create")) { + mySimulation.setDelayTime(((Number) delayTime.getValue()).intValue()); + mySimulation.setSimulationTime(((Number) simulationTime.getValue()).intValue()); + mySimulation.setTickTime(((Number) tickTime.getValue()).intValue()); + mySimulation.setTitle(title.getText()); + + String currentRadioMediumDescription = (String) radioMediumBox.getSelectedItem(); + for (Class radioMediumClass: GUI.currentGUI.getRegisteredRadioMediums()) { + String radioMediumDescription = GUI.getDescriptionOf(radioMediumClass); + + if (currentRadioMediumDescription.equals(radioMediumDescription)) { + try { + mySimulation.setRadioMedium(radioMediumClass.newInstance()); + } catch (Exception ex) { + logger.fatal("Exception when creating radio medium: " + ex); + mySimulation.setRadioMedium(null); + } + break; + } + } + + if (logCheckBox.isSelected()) { + ConnectionLogger connLogger = new ConnectionLogger(new File(logFilename.getText())); + mySimulation.getRadioMedium().setConnectionLogger(connLogger); + } + + dispose(); + } + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/dialogs/ExternalToolsDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/ExternalToolsDialog.java new file mode 100644 index 000000000..2d3d6b379 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/ExternalToolsDialog.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2006, 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: ExternalToolsDialog.java,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + */ + +package se.sics.cooja.dialogs; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * A dialog for viewing/editing external tools settings. + * Allows user to change paths and arguments to compilers, linkers etc. + * + * @author Fredrik Osterlind + */ +public class ExternalToolsDialog extends JDialog { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(ExternalToolsDialog.class); + + private ExternalToolsEventHandler myEventHandler = new ExternalToolsEventHandler(); + + private final static int LABEL_WIDTH = 220; + private final static int LABEL_HEIGHT = 15; + + private ExternalToolsDialog myDialog; + + private JTextField textFields[]; + + /** + * Creates a dialog for viewing/editing external tools settings. + * + * @param parentFrame + * Parent frame for dialog + */ + public static void showDialog(Frame parentFrame) { + ExternalToolsDialog myDialog = new ExternalToolsDialog(parentFrame); + myDialog.setLocationRelativeTo(parentFrame); + + if (myDialog != null) { + myDialog.setVisible(true); + } + } + + private ExternalToolsDialog(Frame frame) { + super(frame, "Edit Settings", true); + + myDialog = this; + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + JButton button; + JTextField textField; + + // BOTTOM BUTTON PART + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + buttonPane.add(Box.createHorizontalGlue()); + + button = new JButton("Cancel"); + button.setActionCommand("cancel"); + button.addActionListener(myEventHandler); + buttonPane.add(button); + + button = new JButton("Reset"); + button.setActionCommand("reset"); + button.addActionListener(myEventHandler); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(button); + + button = new JButton("OK (Saves)"); + button.setActionCommand("ok"); + button.addActionListener(myEventHandler); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(button); + + // MAIN PART + textFields = new JTextField[GUI.getExternalToolsSettingsCount()]; + for (int i = 0; i < GUI.getExternalToolsSettingsCount(); i++) { + // Add text fields for every changable property + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel(GUI.getExternalToolsSettingName(i)); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + textField = new JTextField(35); + textField.setText(""); + textField.addFocusListener(myEventHandler); + textFields[i] = textField; + + smallPane.add(label); + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(textField); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0, 5))); + } + + // Set actual used values into all text fields + updateTextFields(); + + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + Container contentPane = getContentPane(); + contentPane.add(mainPane, BorderLayout.NORTH); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + pack(); + } + + private void updateTextFields() { + for (int i = 0; i < GUI.getExternalToolsSettingsCount(); i++) { + textFields[i].setText(GUI.getExternalToolsSetting(GUI.getExternalToolsSettingName(i), "")); + } + } + + private class ExternalToolsEventHandler + implements + ActionListener, + FocusListener { + public void focusGained(FocusEvent e) { + // NOP + } + public void focusLost(FocusEvent e) { + // NOP + } + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("reset")) { + GUI.loadExternalToolsDefaultSettings(); + updateTextFields(); + } else if (e.getActionCommand().equals("ok")) { + for (int i = 0; i < GUI.getExternalToolsSettingsCount(); i++) { + GUI.setExternalToolsSetting(GUI.getExternalToolsSettingName(i), textFields[i].getText() + .trim()); + } + GUI.saveExternalToolsUserSettings(); + myDialog.dispose(); + } else if (e.getActionCommand().equals("cancel")) { + myDialog.dispose(); + } else + logger.debug("Unhandled command: " + e.getActionCommand()); + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/dialogs/MessageList.java b/tools/cooja/java/se/sics/cooja/dialogs/MessageList.java new file mode 100644 index 000000000..ec3699c08 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/MessageList.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2006, 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: MessageList.java,v 1.1 2006/08/21 12:13:01 fros4943 Exp $ + * + * ----------------------------------------------------------------- + * + * Author : Adam Dunkels, Joakim Eriksson, Niclas Finne, Fredrik Osterlind + * Created : 2006-06-14 + * Updated : $Date: 2006/08/21 12:13:01 $ + * $Revision: 1.1 $ + */ +package se.sics.cooja.dialogs; +import java.awt.Color; +import java.awt.Component; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; + +public class MessageList extends JList { + + public static final int NORMAL = 0; + public static final int WARNING = 1; + public static final int ERROR = 2; + + private Color[] foregrounds = new Color[] { null, Color.red }; + private Color[] backgrounds = new Color[] { null, null }; + + public MessageList() { + super.setModel(new DefaultListModel()); + setCellRenderer(new MessageRenderer()); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + } + + public Color getForeground(int type) { + Color c = type > 0 && type <= foregrounds.length + ? foregrounds[type - 1] : null; + return c == null ? getForeground() : c; + } + + public void setForeground(int type, Color color) { + if (type > 0 && type <= foregrounds.length) { + foregrounds[type - 1] = color; + } else if (type == NORMAL) { + setForeground(color); + } + } + + public Color getBackground(int type) { + Color c = type > 0 && type <= backgrounds.length + ? backgrounds[type - 1] : null; + return c == null ? getBackground() : c; + } + + public void setBackground(int type, Color color) { + if (type > 0 && type <= backgrounds.length) { + backgrounds[type - 1] = color; + } else if (type == NORMAL) { + setBackground(color); + } + } + + public void addMessage(String message) { + addMessage(message, NORMAL); + } + + public void addMessage(String message, int type) { + MessageContainer msg = new MessageContainer(message, type); + ((DefaultListModel) getModel()).addElement(msg); + ensureIndexIsVisible(getModel().getSize() - 1); + } + + public void clearMessages() { + ((DefaultListModel) getModel()).clear(); + } + + public void setModel(ListModel model) { + throw new IllegalArgumentException("changing model not permitted"); + } + + + // ------------------------------------------------------------------- + // MessageContainer + // ------------------------------------------------------------------- + + private static class MessageContainer { + public final int type; + public final String message; + + public MessageContainer(String message, int type) { + this.message = message; + this.type = type; + } + + public String toString() { + return message; + } + + } // end of inner class MessageContainer + + + // ------------------------------------------------------------------- + // Renderer for messages + // ------------------------------------------------------------------- + + private static class MessageRenderer extends DefaultListCellRenderer { + + public Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + super.getListCellRendererComponent(list, value, index, isSelected, + cellHasFocus); + MessageContainer msg = (MessageContainer) value; + setForeground(((MessageList) list).getForeground(msg.type)); + setBackground(((MessageList) list).getBackground(msg.type)); + return this; + } + + } // end of inner class MessageRenderer + +} // end of MessagList diff --git a/tools/cooja/java/se/sics/cooja/dialogs/UserPlatformsDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/UserPlatformsDialog.java new file mode 100644 index 000000000..97504fb57 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/UserPlatformsDialog.java @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2006, 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: UserPlatformsDialog.java,v 1.1 2006/08/21 12:13:02 fros4943 Exp $ + */ + +package se.sics.cooja.dialogs; + +import java.awt.*; +import java.awt.event.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; +import javax.swing.*; + +import org.apache.log4j.Logger; + +import se.sics.cooja.GUI; +import se.sics.cooja.PlatformConfig; + +/** + * This dialog allows a user to manage the user platforms configuration. User + * platforms can be added, removed or reordered. The resulting platform + * configuration can also be viewed. + * + * This dialog reads from the external platform configuration files in each user + * platform, as well as from any specified default configuration files. + * + * @author Fredrik Osterlind + */ +public class UserPlatformsDialog extends JDialog { + + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(UserPlatformsDialog.class); + + private List changablePlatformsList = new List(); + private List fixedPlatformsList = null; + private Vector fixedUserPlatforms = null; + private Vector changableUserPlatforms = null; + + private UserPlatformsDialog myDialog; + private Frame myParentFrame; + + /** + * Allows user to alter the given user platforms list by adding new, + * reordering or removing user platforms. Only the changable user platforms + * may be changed, + * + * @param parentFrame + * Parent frame + * @param changablePlatforms + * Changeable user platforms + * @param fixedPlatforms + * Fixed user platform + * @return Null if dialog aborted, else the new CHANGEABLE user platform list. + */ + public static Vector showDialog(Frame parentFrame, + Vector changablePlatforms, Vector fixedPlatforms) { + UserPlatformsDialog myDialog = new UserPlatformsDialog(parentFrame, + changablePlatforms, fixedPlatforms); + myDialog.setLocationRelativeTo(parentFrame); + + if (myDialog != null) { + myDialog.setVisible(true); + } + + return myDialog.changableUserPlatforms; + } + + private UserPlatformsDialog(Frame frame, Vector changablePlatforms, + Vector fixedPlatforms) { + super(frame, "Manage User Platforms", true); + + myParentFrame = frame; + myDialog = this; + + JPanel mainPane = new JPanel(); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + JButton button; + + // BOTTOM BUTTON PART + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + buttonPane.add(Box.createHorizontalGlue()); + + button = new JButton("Cancel"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + changableUserPlatforms = null; + dispose(); + } + }); + buttonPane.add(button); + + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + + button = new JButton("OK"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + changableUserPlatforms = new Vector(); + for (String directory : changablePlatformsList.getItems()) { + File userPlatform = new File(directory); + if (userPlatform.exists() && userPlatform.isDirectory()) + changableUserPlatforms.add(userPlatform); + else + logger.fatal("Can't find user platform: " + userPlatform); + } + dispose(); + } + }); + buttonPane.add(button); + this.getRootPane().setDefaultButton(button); + + // LIST PART + JPanel listPane = new JPanel(); + listPane.setLayout(new BoxLayout(listPane, BoxLayout.X_AXIS)); + listPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + JPanel listPane2 = new JPanel(); + listPane2.setLayout(new BoxLayout(listPane2, BoxLayout.Y_AXIS)); + + if (fixedPlatforms != null) { + fixedPlatformsList = new List(); + fixedPlatformsList.setEnabled(false); + listPane2.add(new JLabel("Fixed:")); + listPane2.add(fixedPlatformsList); + } + + listPane2.add(new JLabel("Changable:")); + listPane2.add(changablePlatformsList); + + listPane.add(listPane2); + + smallPane = new JPanel(); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.Y_AXIS)); + + button = new JButton("Move up"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int selectedIndex = changablePlatformsList.getSelectedIndex(); + if (selectedIndex <= 0) + return; + + File file = new File(changablePlatformsList.getItem(selectedIndex)); + + removeUserPlatform(selectedIndex); + addUserPlatform(file, selectedIndex - 1); + changablePlatformsList.select(selectedIndex - 1); + } + }); + smallPane.add(button); + + button = new JButton("Move down"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int selectedIndex = changablePlatformsList.getSelectedIndex(); + if (selectedIndex < 0) + return; + if (selectedIndex >= changablePlatformsList.getItemCount() - 1) + return; + + File file = new File(changablePlatformsList.getItem(selectedIndex)); + removeUserPlatform(selectedIndex); + addUserPlatform(file, selectedIndex + 1); + changablePlatformsList.select(selectedIndex + 1); + } + }); + smallPane.add(button); + + smallPane.add(Box.createRigidArea(new Dimension(10, 10))); + + button = new JButton("Remove"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (changablePlatformsList.getSelectedIndex() < 0) + return; + + removeUserPlatform(changablePlatformsList.getSelectedIndex()); + } + }); + smallPane.add(button); + + listPane.add(smallPane); + + // ADD/REMOVE PART + JPanel addRemovePane = new JPanel(); + addRemovePane.setLayout(new BoxLayout(addRemovePane, BoxLayout.X_AXIS)); + addRemovePane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + button = new JButton("View resulting config"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + // Create default configuration + PlatformConfig config = new PlatformConfig(); + try { + config.appendConfig(new File(GUI.PLATFORM_DEFAULT_CONFIG_FILENAME)); + } catch (FileNotFoundException ex) { + logger.fatal("Could not find default platform config file: " + + GUI.PLATFORM_DEFAULT_CONFIG_FILENAME); + return; + } catch (IOException ex) { + logger.fatal("Error when reading default platform config file: " + + GUI.PLATFORM_DEFAULT_CONFIG_FILENAME); + return; + } + + // Add the fixed platform configurations + if (fixedPlatformsList != null) { + for (String userPlatform : fixedPlatformsList.getItems()) { + File userPlatformConfig = new File(userPlatform + File.separatorChar + + GUI.PLATFORM_CONFIG_FILENAME); + try { + config.appendConfig(userPlatformConfig); + } catch (Exception ex) { + logger.fatal("Error when merging configurations: " + ex); + return; + } + } + } + + // Add the user platform configurations + for (String userPlatform : changablePlatformsList.getItems()) { + File userPlatformConfig = new File(userPlatform + File.separatorChar + + GUI.PLATFORM_CONFIG_FILENAME); + try { + config.appendConfig(userPlatformConfig); + } catch (Exception ex) { + logger.fatal("Error when merging configurations: " + ex); + return; + } + } + + // Show merged configuration + ConfigViewer.showDialog(myParentFrame, config); + } + }); + addRemovePane.add(button); + + addRemovePane.add(Box.createRigidArea(new Dimension(10, 0))); + + button = new JButton("Add manually"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + String newUserPlatformPath = JOptionPane.showInputDialog(myDialog, + "Enter path to user platform", "Enter path", + JOptionPane.QUESTION_MESSAGE); + if (newUserPlatformPath != null) { + addUserPlatform(new File(newUserPlatformPath)); + } + } + }); + addRemovePane.add(button); + + addRemovePane.add(Box.createRigidArea(new Dimension(10, 0))); + + button = new JButton("Browse"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new java.io.File(".")); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fc.setDialogTitle("Select user platform"); + + if (fc.showOpenDialog(myDialog) == JFileChooser.APPROVE_OPTION) { + addUserPlatform(fc.getSelectedFile()); + } + } + }); + addRemovePane.add(button); + + // Add components + Container contentPane = getContentPane(); + mainPane.add(listPane); + mainPane.add(addRemovePane); + contentPane.add(mainPane, BorderLayout.CENTER); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + // Add fixed user platforms if any + if (fixedPlatforms != null) { + for (File userPlatform : fixedPlatforms) { + fixedPlatformsList.add(userPlatform.getPath()); + } + } + + // Add already existing user platforms + for (File userPlatform : changablePlatforms) { + addUserPlatform(userPlatform); + } + + pack(); + } + + private void addUserPlatform(File userPlatform) { + addUserPlatform(userPlatform, changablePlatformsList.getItemCount()); + } + + private void addUserPlatform(File userPlatform, int index) { + // Check that file exists, is a directory and contains the correct files + if (!userPlatform.exists()) { + logger.fatal("Can't find user platform: " + userPlatform); + return; + } + if (!userPlatform.isDirectory()) { + logger.fatal("User platform is not a directory: " + userPlatform); + return; + } + + File userPlatformConfigFile = new File(userPlatform.getPath() + + File.separatorChar + GUI.PLATFORM_CONFIG_FILENAME); + if (!userPlatformConfigFile.exists()) { + logger.fatal("User platform has no configuration file: " + + userPlatformConfigFile); + return; + } + + changablePlatformsList.add(userPlatform.getPath(), index); + } + + private void removeUserPlatform(int index) { + changablePlatformsList.remove(index); + } + +} + +/** + * Modal frame that shows all keys with their respective values of a given class + * configuration. + * + * @author Fredrik Osterlind + */ +class ConfigViewer extends JDialog { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(ConfigViewer.class); + + public static void showDialog(Frame parentFrame, PlatformConfig config) { + ConfigViewer myDialog = new ConfigViewer(parentFrame, config); + myDialog.setLocationRelativeTo(parentFrame); + + if (myDialog != null) { + myDialog.setVisible(true); + } + } + + private ConfigViewer(Frame frame, PlatformConfig config) { + super(frame, "Current class configuration", true); + + JPanel mainPane = new JPanel(new BorderLayout()); + JLabel label; + JButton button; + + // BOTTOM BUTTON PART + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + buttonPane.add(Box.createHorizontalGlue()); + + button = new JButton("Close"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + buttonPane.add(button); + + // LIST PART + JPanel keyPane = new JPanel(); + keyPane.setLayout(new BoxLayout(keyPane, BoxLayout.Y_AXIS)); + mainPane.add(keyPane, BorderLayout.WEST); + + JPanel valuePane = new JPanel(); + valuePane.setLayout(new BoxLayout(valuePane, BoxLayout.Y_AXIS)); + mainPane.add(valuePane, BorderLayout.CENTER); + + label = new JLabel("KEY"); + label.setForeground(Color.RED); + keyPane.add(label); + label = new JLabel("VALUE"); + label.setForeground(Color.RED); + valuePane.add(label); + + Enumeration allPropertyNames = config.getPropertyNames(); + while (allPropertyNames.hasMoreElements()) { + String propertyName = allPropertyNames.nextElement(); + + keyPane.add(new JLabel(propertyName)); + valuePane.add(new JLabel(config.getStringValue(propertyName))); + } + + // Add components + Container contentPane = getContentPane(); + contentPane.add(new JScrollPane(mainPane), BorderLayout.CENTER); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + pack(); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Battery.java b/tools/cooja/java/se/sics/cooja/interfaces/Battery.java new file mode 100644 index 000000000..45c8ee71f --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Battery.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2006, 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: Battery.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import java.util.*; + +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; + +/** + * A Battery represents the energy source for a mote. This implementation has no + * connection with any underlying simulated software, hence a mote does not know + * the current energy levels. + *

+ * This Battery decreases current energy left each tick depending on the current + * mote state. If the mote is sleeping all passive interfaces' energy + * consumptions will be summed up and detracted from the current energy. If the + * mote is awake both the active and passive interfaces' energy consumptions + * will be used. Also, the energy used by the CPU (depends on mote state) will + * be detracted each tick. + *

+ * This observable is changed and notifies observers every time the energy left + * is changed. When current energy left has decreased below 0 the mote state is + * set to dead. + * + * @see MoteInterface + * @see MoteInterface#energyConsumptionPerTick() + * + * @author Fredrik Osterlind + */ +@ClassDescription("Battery") +public class Battery extends MoteInterface implements PassiveMoteInterface { + + /** + * Approximate energy consumption of a mote's CPU in active mode (mA). ESB + * measured energy consumption is 1.49 mA. + */ + public final double ENERGY_CONSUMPTION_AWAKE_mA; + + /** + * Approximate energy consumption of a mote's CPU in low power mode (mA). ESB + * measured energy consumption is 1.34 mA. + */ + public final double ENERGY_CONSUMPTION_LPM_mA; + + /** + * Initial energy of battery in milli coulomb (mQ). ESB mote: 3 regular AA + * batteries, each ~1.25 Ah. 3 * 1.25 Ah = 3 * 1.25 * 3600 Q = 13,500 Q = + * 13,500,000 mQ + */ + public final double INITIAL_ENERGY; + + private double energyConsumptionLPMPerTick = -1.0; + private double energyConsumptionAwakePerTick = -1.0; + + private Mote mote = null; + private static Logger logger = Logger.getLogger(Battery.class); + + private double myEnergy; + private boolean hasInfiniteEnergy; + + /** + * Creates a new battery connected to given mote. + * + * @see #INITIAL_ENERGY + * @param mote + * Mote holding battery + */ + public Battery(Mote mote) { + // Read class configurations of this mote type + ENERGY_CONSUMPTION_AWAKE_mA = mote.getType().getConfig() + .getDoubleValue(Battery.class, "CPU_AWAKE_mA"); + ENERGY_CONSUMPTION_LPM_mA = mote.getType().getConfig().getDoubleValue( + Battery.class, "CPU_LPM_mA"); + INITIAL_ENERGY = mote.getType().getConfig().getDoubleValue( + Battery.class, "INITIAL_ENERGY_mQ"); + hasInfiniteEnergy = mote.getType().getConfig().getBooleanValue( + Battery.class, "INFINITE_ENERGY_bool"); + + if (energyConsumptionAwakePerTick < 0) { + energyConsumptionAwakePerTick = ENERGY_CONSUMPTION_AWAKE_mA + * mote.getSimulation().getTickTimeInSeconds(); + energyConsumptionLPMPerTick = ENERGY_CONSUMPTION_LPM_mA + * mote.getSimulation().getTickTimeInSeconds(); + } + + this.mote = mote; + myEnergy = INITIAL_ENERGY; + } + + public void doActionsBeforeTick() { + // Nothing to do + } + + public void doActionsAfterTick() { + // If infinite energy, do nothing + if (hasInfiniteEnergy) + return; + + // If mote is dead, do nothing + if (mote.getState() == Mote.STATE_DEAD) + return; + + // Check mote state + if (mote.getState() == Mote.STATE_LPM) { + // Mote is sleeping. Sum up energy usage. + double totalEnergyConsumption = 0.0; + totalEnergyConsumption += energyConsumptionLPMPerTick; + + for (MoteInterface passiveInterface : mote.getInterfaces() + .getAllPassiveInterfaces()) { + totalEnergyConsumption += passiveInterface.energyConsumptionPerTick(); + } + + decreaseEnergy(totalEnergyConsumption); + } else { + // Mote is awake. Sum up energy usage. + double totalEnergyConsumption = 0.0; + totalEnergyConsumption += energyConsumptionAwakePerTick; + + for (MoteInterface activeInterface : mote.getInterfaces() + .getAllActiveInterfaces()) { + totalEnergyConsumption += activeInterface.energyConsumptionPerTick(); + } + for (MoteInterface passiveInterface : mote.getInterfaces() + .getAllPassiveInterfaces()) { + totalEnergyConsumption += passiveInterface.energyConsumptionPerTick(); + } + + decreaseEnergy(totalEnergyConsumption); + } + + // Check if we are out of energy + if (getCurrentEnergy() <= 0.0) { + setChanged(); + notifyObservers(); + mote.setState(Mote.STATE_DEAD); + } + } + + /** + * @param inf + * Set infinite energy state + */ + public void setInfiniteEnergy(boolean inf) { + hasInfiniteEnergy = inf; + + setChanged(); + notifyObservers(); + } + + /** + * @return True if this battery has inifinite energy + */ + public boolean hasInfiniteEnergy() { + return hasInfiniteEnergy; + } + + /** + * @return Initial energy + */ + public double getInitialEnergy() { + return INITIAL_ENERGY; + } + + /** + * @return Current energy left + */ + public double getCurrentEnergy() { + return myEnergy; + } + + private void decreaseEnergy(double consumption) { + if (!hasInfiniteEnergy) { + myEnergy -= consumption; + setChanged(); + notifyObservers(); + } + } + + public JPanel getInterfaceVisualizer() { + // Battery energy left + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + final JLabel energyLabel = new JLabel(""); + final JLabel energyPercentLabel = new JLabel(""); + + if (hasInfiniteEnergy()) { + energyLabel.setText("INFINITE"); + energyPercentLabel.setText(""); + } else { + energyLabel.setText("Energy left (mQ) = " + getCurrentEnergy()); + energyPercentLabel.setText("Energy left (%) = " + + (getCurrentEnergy() / getInitialEnergy() * 100) + "%"); + } + + panel.add(energyLabel); + panel.add(energyPercentLabel); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + if (hasInfiniteEnergy()) { + energyLabel.setText("INFINITE"); + energyPercentLabel.setText(""); + } else { + energyLabel.setText("Energy left (mQ) = " + getCurrentEnergy()); + energyPercentLabel.setText("Energy left (%) = " + + (getCurrentEnergy() / getInitialEnergy() * 100) + "%"); + } + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + 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); + } + + public double energyConsumptionPerTick() { + // The battery itself does not require any power. + return 0.0; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + Element element; + + // Infinite boolean + element = new Element("infinite"); + element.setText(Boolean.toString(hasInfiniteEnergy)); + config.add(element); + + return config; + } + + public void setConfigXML(Collection configXML) { + for (Element element : configXML) { + if (element.getName().equals("infinite")) { + hasInfiniteEnergy = Boolean.parseBoolean(element.getText()); + } + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Beeper.java b/tools/cooja/java/se/sics/cooja/interfaces/Beeper.java new file mode 100644 index 000000000..90d4f9fad --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Beeper.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006, 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: Beeper.java,v 1.1 2006/08/21 12:12:58 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A Beeper represents a mote beeper. An implementation should notify all + * observers when the beeper changes state and typically requires more energy if + * beeping than when quiet. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Beeper") +public abstract class Beeper extends MoteInterface { + + /** + * @return True if beeper is beeping + */ + public abstract boolean isBeeping(); +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Button.java b/tools/cooja/java/se/sics/cooja/interfaces/Button.java new file mode 100644 index 000000000..df060b83c --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Button.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006, 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: Button.java,v 1.1 2006/08/21 12:12:58 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A Button represents a mote button. An implementation should notify all + * observers when the button changes state, and may simulate external interrupts + * by waking up a mote if button state changes. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Button") +public abstract class Button extends MoteInterface { + + /** + * Clicks button. Button will be pressed for some time and then automatically + * released. + */ + public abstract void clickButton(); + + /** + * Releases button (if pressed). + */ + public abstract void releaseButton(); + + /** + * Presses button (if not already pressed). + */ + public abstract void pressButton(); + + /** + * @return True if button is pressed + */ + public abstract boolean isPressed(); +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Clock.java b/tools/cooja/java/se/sics/cooja/interfaces/Clock.java new file mode 100644 index 000000000..5e60202fd --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Clock.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006, 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: Clock.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A Clock represents a mote's internal clock. Notice that the overall + * simulation time and the mote's own time may differ. + * + * This observable never needs to update. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Clock") +public abstract class Clock extends MoteInterface { + + /** + * Set mote's time to given time. + * + * @param newTime + * New time + */ + public abstract void setTime(int newTime); + + /** + * @return Current time + */ + public abstract int getTime(); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java b/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java new file mode 100644 index 000000000..59b4aceb5 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006, 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: IPAddress.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A IPAdress represents a mote Internet address. An implementation should notify all + * observers if the address is set or changed. + * + * @author Fredrik Osterlind + */ +@ClassDescription("IPv4 Address") +public abstract class IPAddress extends MoteInterface { + + /** + * Get current IP address on the form a.b.c.d. + * @return IP address string + */ + public abstract String getIPString(); + + /** + * Change/Set IP address. + * @param ipAddress IP string on the form a.b.c.d + */ + public abstract void setIPString(String ipAddress); + + /** + * Change/Set IP address. + * @param a First byte of IP address + * @param b Second byte of IP address + * @param c Third byte of IP address + * @param d Fourth byte of IP address + */ + public abstract void setIPNumber(char a, char b, char c, char d); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/LED.java b/tools/cooja/java/se/sics/cooja/interfaces/LED.java new file mode 100644 index 000000000..9e384c514 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/LED.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2006, 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: LED.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A LED represents three mote LEDs (green, yellow and red). An implementation should notify all + * observers if any of the LEDs states are changed. + * + * @author Fredrik Osterlind + */ +@ClassDescription("LEDs") +public abstract class LED extends MoteInterface { + + /** + * @return True if any LED is on, false otherwise + */ + public abstract boolean isAnyOn(); + + /** + * @return True if green LED is on, false otherwise + */ + public abstract boolean isGreenOn(); + + /** + * @return True if yellow LED is on, false otherwise + */ + public abstract boolean isYellowOn(); + + /** + * @return True if red LED is on, false otherwise + */ + public abstract boolean isRedOn(); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Log.java b/tools/cooja/java/se/sics/cooja/interfaces/Log.java new file mode 100644 index 000000000..457a0a3ef --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Log.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006, 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: Log.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A Log represents a mote logging output. An implementation should notify all + * observers whenever new logging output is available. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Log Output") +public abstract class Log extends MoteInterface { + + /** + * @return Last log messages available + */ + public abstract String getLastLogMessages(); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/MoteID.java b/tools/cooja/java/se/sics/cooja/interfaces/MoteID.java new file mode 100644 index 000000000..bc94c5136 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/MoteID.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2006, 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: MoteID.java,v 1.1 2006/08/21 12:12:58 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A MoteID represents a mote ID number. An implementation should notify all + * observers if the mote ID is set or changed. + * + * @author Fredrik Osterlind + */ +@ClassDescription("ID") +public abstract class MoteID extends MoteInterface { + + /** + * @return Current mote ID number + */ + public abstract int getMoteID(); + + /** + * Sets mote ID to given number. + * @param newID New mote ID number + */ + public abstract void setMoteID(int newID); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/PIR.java b/tools/cooja/java/se/sics/cooja/interfaces/PIR.java new file mode 100644 index 000000000..70f90aaee --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/PIR.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006, 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: PIR.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A PIR represents a passive infrared sensor. An implementation should notify all + * observers if the PIR discovers any changes. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Passive IR") +public abstract class PIR extends MoteInterface { + + /** + * Simulates a change in the PIR sensor. + */ + public abstract void triggerChange(); + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Position.java b/tools/cooja/java/se/sics/cooja/interfaces/Position.java new file mode 100644 index 000000000..c0bd536cb --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Position.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2006, 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: Position.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import java.text.NumberFormat; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; + +/** + * A Position represents the simulated 3D position of a mote. This + * implementation has no connection with any underlying simulated software, + * hence a mote does not know its current position. + *

+ * This observable is changed and notifies observers whenever new coordinates + * are set. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Position") +public class Position extends MoteInterface { + private static Logger logger = Logger.getLogger(Position.class); + private Mote mote = null; + private double[] coords = new double[3]; + + /** + * Creates a position for given mote with coordinates (x=0, y=0, z=0). + * + * @param mote + * Led's mote. + * @see Mote + * @see se.sics.cooja.MoteInterfaceHandler + */ + public Position(Mote mote) { + this.mote = mote; + + coords[0] = 0.0f; + coords[1] = 0.0f; + coords[2] = 0.0f; + } + + /** + * Updates coordiantes of associated mote to (x,y,z). + * + * @param x + * New X coordinate + * @param y + * New Y coordinate + * @param z + * New Z coordinate + */ + public void setCoordinates(double x, double y, double z) { + coords[0] = x; + coords[1] = y; + coords[2] = z; + + this.setChanged(); + this.notifyObservers(mote); + } + + /** + * @return X coordinate + */ + public double getXCoordinate() { + return coords[0]; + } + + /** + * @return Y coordinate + */ + public double getYCoordinate() { + return coords[1]; + } + + /** + * @return Z coordinate + */ + public double getZCoordinate() { + return coords[2]; + } + + /** + * Calculates distance from this position to given position. + * + * @param pos + * Compared position + * @return Distance + */ + public double getDistanceTo(Position pos) { + return Math.sqrt(Math.abs(coords[0] - pos.getXCoordinate()) + * Math.abs(coords[0] - pos.getXCoordinate()) + + Math.abs(coords[1] - pos.getYCoordinate()) + * Math.abs(coords[1] - pos.getYCoordinate()) + + Math.abs(coords[2] - pos.getZCoordinate()) + * Math.abs(coords[2] - pos.getZCoordinate())); + } + + /** + * Calculates distance from associated mote to another mote. + * + * @param m + * Another mote + * @return Distance + */ + public double getDistanceTo(Mote m) { + return getDistanceTo(m.getInterfaces().getPosition()); + } + + public void doActionsBeforeTick() { + // Nothing to do + } + + public void doActionsAfterTick() { + // Nothing to do + } + + public JPanel getInterfaceVisualizer() { + + // Location + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + final NumberFormat form = NumberFormat.getNumberInstance(); + + final JLabel positionLabel = new JLabel(); + positionLabel.setText("(" + form.format(getXCoordinate()) + "," + + form.format(getYCoordinate()) + "," + form.format(getZCoordinate()) + + ")"); + + panel.add(positionLabel); + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + positionLabel.setText("(" + form.format(getXCoordinate()) + "," + + form.format(getYCoordinate()) + "," + + form.format(getZCoordinate()) + ")"); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + 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); + } + + public double energyConsumptionPerTick() { + return 0.0; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + Element element; + + // X coordinate + element = new Element("x"); + element.setText(Double.toString(getXCoordinate())); + config.add(element); + + // Y coordinate + element = new Element("y"); + element.setText(Double.toString(getYCoordinate())); + config.add(element); + + // Z coordinate + element = new Element("z"); + element.setText(Double.toString(getZCoordinate())); + config.add(element); + + return config; + } + + public void setConfigXML(Collection configXML) { + double x = 0, y = 0, z = 0; + + for (Element element : configXML) { + if (element.getName().equals("x")) { + x = Double.parseDouble(element.getText()); + } + + if (element.getName().equals("y")) { + y = Double.parseDouble(element.getText()); + } + + if (element.getName().equals("z")) { + z = Double.parseDouble(element.getText()); + } + } + + setCoordinates(x, y, z); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/interfaces/Radio.java b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java new file mode 100644 index 000000000..c530386f8 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/interfaces/Radio.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006, 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: Radio.java,v 1.1 2006/08/21 12:12:59 fros4943 Exp $ + */ + +package se.sics.cooja.interfaces; + +import se.sics.cooja.*; + +/** + * A Radio represents a mote radio transceiver. An implementation should notify + * all observers both when packets are received and transmitted. The static + * constants should be used for describing the radio status when the observers + * are notified. + * + * @see #SENT_NOTHING + * @see #SENT_SOMETHING + * @see #HEARS_NOTHING + * @see #HEARS_PACKET + * @see #HEARS_NOISE + * @author Fredrik Osterlind + */ +@ClassDescription("Packet Radio") +public abstract class Radio extends MoteInterface { + + /** + * This radio has not sent anything last tick. + */ + public static final int SENT_NOTHING = 1; + + /** + * This radio has sent something last tick. + */ + public static final int SENT_SOMETHING = 2; + + /** + * This radio is not hearing anything. + */ + public static final int HEARS_NOTHING = 1; + + /** + * This radio is hearing exactly one packet right now. + */ + public static final int HEARS_PACKET = 2; + + /** + * This radio is hearing a lot of noise right now (may be several packets). + */ + public static final int HEARS_NOISE = 3; + + /** + * @return Last packet data sent from this radio. + */ + public abstract byte[] getLastPacketSent(); + + /** + * @return Last packet data received by this radio. + */ + public abstract byte[] getLastPacketReceived(); + + /** + * Send given packet data to this radio. The radio may or may not receive the + * data correctly depending on the current listen state. + * + * @param data + */ + public abstract void receivePacket(byte[] data); + + /** + * @return Current send state + * @see #SENT_NOTHING + * @see #SENT_SOMETHING + */ + public abstract int getSendState(); + + /** + * @return Current listen state + * + * @see #setListenState(int) + * @see #HEARS_NOTHING + * @see #HEARS_PACKET + * @see #HEARS_NOISE + */ + public abstract int getListenState(); + + /** + * Changes listen state to given state + * @param newState + * New listen state + * + * @see #getListenState() + * @see #HEARS_NOTHING + * @see #HEARS_PACKET + * @see #HEARS_NOISE + */ + public abstract void setListenState(int newState); + + /** + * Advances listen state one step. If listen state was 'hears nothing', it + * will become 'hears packet'. If it was 'hears packet', it will become 'hears + * noise'. If it was 'hears noise', it will stay that way. + * + * @see #getListenState() + */ + public abstract void advanceListenState(); + +} diff --git a/tools/cooja/java/se/sics/cooja/ipdistributors/IdIPDistributor.java b/tools/cooja/java/se/sics/cooja/ipdistributors/IdIPDistributor.java new file mode 100644 index 000000000..b45262ee6 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/ipdistributors/IdIPDistributor.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006, 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: IdIPDistributor.java,v 1.1 2006/08/21 12:13:06 fros4943 Exp $ + */ + +package se.sics.cooja.ipdistributors; +import java.util.Vector; +import se.sics.cooja.*; + +/** + * Generates IP addresses on the form 10.[id/256 mod 256*256].[id mod 256].1. + * + * Observe! + * - ID must be set before this is called (otherwise IP=0.0.0.0). + * - Only supports 256*256 motes, (IPs will wrap if above). + * + * @author Fredrik Osterlind + */ +@ClassDescription("From ID (10.id.id.1)") +public class IdIPDistributor extends IPDistributor { + private Vector generatedIPAddresses; + + /** + * Creates a Id IP distributor. + * @param newMotes All motes which later will be assigned IP numbers. + */ + public IdIPDistributor(Vector newMotes) { + generatedIPAddresses = new Vector(); + + for (int i=0; i < newMotes.size(); i++) { + if (newMotes.get(i).getInterfaces().getMoteID() != null) { + int moteId = newMotes.get(i).getInterfaces().getMoteID().getMoteID(); + generatedIPAddresses.add("10." + + (moteId / 256 % (256*256)) + + "." + + (moteId % 256) + + ".1"); + } else + generatedIPAddresses.add("0.0.0.0"); + } + + } + + public String getNextIPAddress() { + if (generatedIPAddresses.size() > 0) + return generatedIPAddresses.remove(0); + else + return "0.0.0.0"; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/ipdistributors/RandomIPDistributor.java b/tools/cooja/java/se/sics/cooja/ipdistributors/RandomIPDistributor.java new file mode 100644 index 000000000..74ad8cd17 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/ipdistributors/RandomIPDistributor.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2006, 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: RandomIPDistributor.java,v 1.1 2006/08/21 12:13:06 fros4943 Exp $ + */ + +package se.sics.cooja.ipdistributors; +import java.util.Vector; +import se.sics.cooja.*; + +/** + * Generates IP addresses randomly on the form 10.10.[1-20].[1-20]. + * Nothing prevents several motes from getting the same IP number. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Random (10.10.?.?)") +public class RandomIPDistributor extends IPDistributor { + + /** + * Creates a random IP distributor. + * @param newMotes All motes which later will be assigned IP numbers. + */ + public RandomIPDistributor(Vector newMotes) { + // NOP + } + + public String getNextIPAddress() { + return "" + 10 + "." + 10 + "." + (Math.round(Math.random()*20) + 1) + "." + (Math.round(Math.random()*20) + 1); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/ipdistributors/SpatialIPDistributor.java b/tools/cooja/java/se/sics/cooja/ipdistributors/SpatialIPDistributor.java new file mode 100644 index 000000000..72763d092 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/ipdistributors/SpatialIPDistributor.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006, 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: SpatialIPDistributor.java,v 1.1 2006/08/21 12:13:07 fros4943 Exp $ + */ + +package se.sics.cooja.ipdistributors; +import java.util.Vector; +import se.sics.cooja.*; + +/** + * Generates spatial IP addresses on the form 10.[z-coord].[y-coord].[x-coord]. + * The smallest coordinate in each interval will be mapped onto address 1, + * and the biggest coordinate onto address 200. + * Nothing prevents several motes from getting the same IP number. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Spatial (10.x.y.z)") +public class SpatialIPDistributor extends IPDistributor { + private double lowestX, biggestX, lowestY, biggestY, lowestZ, biggestZ; + private Vector generatedIPAddresses; + + /** + * Creates a random IP distributor. + * @param newMotes All motes which later will be assigned IP numbers. + */ + public SpatialIPDistributor(Vector newMotes) { + lowestX = newMotes.get(0).getInterfaces().getPosition().getXCoordinate(); + biggestX = newMotes.get(0).getInterfaces().getPosition().getXCoordinate(); + lowestY = newMotes.get(0).getInterfaces().getPosition().getYCoordinate(); + biggestY = newMotes.get(0).getInterfaces().getPosition().getYCoordinate(); + lowestZ = newMotes.get(0).getInterfaces().getPosition().getZCoordinate(); + biggestZ = newMotes.get(0).getInterfaces().getPosition().getZCoordinate(); + + for (int i=0; i < newMotes.size(); i++) { + if (newMotes.get(i).getInterfaces().getPosition().getXCoordinate() < lowestX) + lowestX = newMotes.get(i).getInterfaces().getPosition().getXCoordinate(); + if (newMotes.get(i).getInterfaces().getPosition().getXCoordinate() > biggestX) + biggestX = newMotes.get(i).getInterfaces().getPosition().getXCoordinate(); + + if (newMotes.get(i).getInterfaces().getPosition().getYCoordinate() < lowestY) + lowestY = newMotes.get(i).getInterfaces().getPosition().getYCoordinate(); + if (newMotes.get(i).getInterfaces().getPosition().getYCoordinate() > biggestY) + biggestY = newMotes.get(i).getInterfaces().getPosition().getYCoordinate(); + + if (newMotes.get(i).getInterfaces().getPosition().getZCoordinate() < lowestZ) + lowestZ = newMotes.get(i).getInterfaces().getPosition().getZCoordinate(); + if (newMotes.get(i).getInterfaces().getPosition().getZCoordinate() > biggestZ) + biggestZ = newMotes.get(i).getInterfaces().getPosition().getZCoordinate(); + } + + generatedIPAddresses = new Vector(); + for (int i=0; i < newMotes.size(); i++) { + String ipAddress = "10."; + int partIP; + + // Z coord + partIP = (int) (1 + 199*(newMotes.get(i).getInterfaces().getPosition().getZCoordinate() - lowestZ) / (biggestZ - lowestZ)); + ipAddress = ipAddress.concat(partIP + "."); + + // Y coord + partIP = (int) (1 + 199*(newMotes.get(i).getInterfaces().getPosition().getYCoordinate() - lowestY) / (biggestY - lowestY)); + ipAddress = ipAddress.concat(partIP + "."); + + // X coord + partIP = (int) (1 + 199*(newMotes.get(i).getInterfaces().getPosition().getXCoordinate() - lowestX) / (biggestX - lowestX)); + ipAddress = ipAddress.concat(partIP + ""); + + generatedIPAddresses.add(ipAddress); + } + } + + public String getNextIPAddress() { + if (generatedIPAddresses.size() > 0) + return generatedIPAddresses.remove(0); + else + return "0.0.0.0"; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/motes/DummyMote.java b/tools/cooja/java/se/sics/cooja/motes/DummyMote.java new file mode 100644 index 000000000..da9cb72dc --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/motes/DummyMote.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2006, 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: DummyMote.java,v 1.1 2006/08/21 12:13:12 fros4943 Exp $ + */ + +package se.sics.cooja.motes; + +import java.util.Collection; +import java.util.Observer; +import java.util.Properties; +import java.util.Random; +import java.util.Vector; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.Position; + +/** + * A dummy mote is a purely Java-based mote, and can be used as an example of + * how to implement motes other than the usual Contiki mote. + * + * The dummy mote uses an empty section mote memory without any variable + * mappings. + * + * The mote interface handler has a position interface, added when the mote is + * constructed. + * + * When the dummy mote is ticked all (one!) interfaces are polled and a random + * variable decides if the position should be changed. The node never leaves the + * active state. + * + * @author Fredrik Osterlind + */ +public class DummyMote implements Mote { + + private static Logger logger = Logger.getLogger(DummyMote.class); + + private MoteType myType = null; + private SectionMoteMemory myMemory = null; + private MoteInterfaceHandler myInterfaceHandler = null; + private Simulation mySim = null; + + private Random myRandom = new Random(); + + /** + * Creates a new uninitialized dummy mote. + */ + public DummyMote() { + } + + /** + * Creates a new dummy mote of the given type in the given simulation. An + * empty mote memory and a position interface is added to this mote. + * + * @param moteType + * Mote type + * @param sim + * Simulation + */ + public DummyMote(MoteType moteType, Simulation sim) { + mySim = sim; + myType = moteType; + + // Create memory + myMemory = new SectionMoteMemory(new Properties()); + + // Create interface handler + myInterfaceHandler = new MoteInterfaceHandler(); + Position myPosition = new Position(this); + myPosition.setCoordinates(myRandom.nextDouble() * 100, myRandom + .nextDouble() * 100, myRandom.nextDouble() * 100); + myInterfaceHandler.addPassiveInterface(myPosition); + } + + public void setState(int newState) { + logger.fatal("Dummy mote can not change state"); + } + + public int getState() { + return Mote.STATE_ACTIVE; + } + + public void addStateObserver(Observer newObserver) { + } + + public void deleteStateObserver(Observer newObserver) { + } + + public MoteInterfaceHandler getInterfaces() { + return myInterfaceHandler; + } + + public void setInterfaces(MoteInterfaceHandler moteInterfaceHandler) { + myInterfaceHandler = moteInterfaceHandler; + } + + public MoteMemory getMemory() { + return myMemory; + } + + public void setMemory(MoteMemory memory) { + myMemory = (SectionMoteMemory) memory; + } + + public MoteType getType() { + return myType; + } + + public void setType(MoteType type) { + myType = type; + } + + public Simulation getSimulation() { + return mySim; + } + + public void setSimulation(Simulation simulation) { + this.mySim = simulation; + } + + public void tick(int simTime) { + + // Perform some dummy task + if (myRandom.nextDouble() > 0.9) { + // Move mote randomly + Position myPosition = myInterfaceHandler.getPosition(); + myPosition.setCoordinates(myPosition.getXCoordinate() + + myRandom.nextDouble() - 0.5, myPosition.getYCoordinate() + + myRandom.nextDouble() - 0.5, myPosition.getZCoordinate() + + myRandom.nextDouble() - 0.5); + } + } + + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // We need to save the mote type identifier + element = new Element("motetype_identifier"); + element.setText(getType().getIdentifier()); + config.add(element); + + // The position interface should also save its config + element = new Element("interface_config"); + element.setText(myInterfaceHandler.getPosition().getClass().getName()); + + Collection interfaceXML = myInterfaceHandler.getPosition().getConfigXML(); + if (interfaceXML != null) { + element.addContent(interfaceXML); + config.add(element); + } + + return config; + } + + public boolean setConfigXML(Simulation simulation, + Collection configXML) { + mySim = simulation; + myMemory = new SectionMoteMemory(new Properties()); + myInterfaceHandler = new MoteInterfaceHandler(); + myInterfaceHandler.addPassiveInterface(new Position(this)); + + for (Element element : configXML) { + String name = element.getName(); + + if (name.equals("motetype_identifier")) { + myType = simulation.getMoteType(element.getText()); + } else if (name.equals("interface_config")) { + Class moteInterfaceClass = GUI.currentGUI + .tryLoadClass(this, MoteInterface.class, element.getText().trim()); + + if (moteInterfaceClass == null) { + logger.warn("Can't find mote interface class: " + element.getText()); + return false; + } + + MoteInterface moteInterface = myInterfaceHandler + .getInterfaceOfType(moteInterfaceClass); + moteInterface.setConfigXML(element.getChildren()); + } + + } + return true; + } + + public String toString() { + if (getInterfaces().getMoteID() != null) { + return "Dummy Mote, ID=" + getInterfaces().getMoteID().getMoteID(); + } else + return "Dummy Mote, ID=null"; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/motes/DummyMoteType.java b/tools/cooja/java/se/sics/cooja/motes/DummyMoteType.java new file mode 100644 index 000000000..99f4f13e7 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/motes/DummyMoteType.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006, 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: DummyMoteType.java,v 1.1 2006/08/21 12:13:12 fros4943 Exp $ + */ + +package se.sics.cooja.motes; + +import java.util.*; + +import javax.swing.*; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; + +@ClassDescription("Dummy Mote Type") +public class DummyMoteType implements MoteType { + private static Logger logger = Logger.getLogger(DummyMoteType.class); + + // Mote type specific data + private String identifier = null; + private String description = null; + + public DummyMoteType() { + } + + public DummyMoteType(String identifier) { + this.identifier = identifier; + description = "Dummy Mote Type #" + identifier; + } + + public Mote generateMote(Simulation simulation) { + return new DummyMote(this, simulation); + } + + public boolean configureAndInit(JFrame parentFrame, Simulation simulation) { + + if (identifier == null) { + // Create unique identifier + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + counter++; + identifier = "dummy" + counter; + identifierOK = true; + + // Check if identifier is already used by some other type + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType != this + && existingMoteType.getIdentifier().equals(identifier)) { + identifierOK = false; + break; + } + } + } + + if (description == null) { + // Create description + description = "Dummy Mote Type #" + counter; + } + + } + + if (description == null) { + // Create description + description = "Dummy Mote Type #" + identifier; + } + + return true; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public JPanel getTypeVisualizer() { + return null; + } + + public PlatformConfig getConfig() { + return null; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // Identifier + element = new Element("identifier"); + element.setText(getIdentifier()); + config.add(element); + + // Description + element = new Element("description"); + element.setText(getDescription()); + config.add(element); + + return config; + } + + public boolean setConfigXML(Simulation simulation, Collection configXML) { + for (Element element : configXML) { + String name = element.getName(); + + if (name.equals("identifier")) { + identifier = element.getText(); + } else if (name.equals("description")) { + description = element.getText(); + } else { + logger.fatal("Unrecognized entry in loaded configuration: " + name); + } + } + + boolean createdOK = configureAndInit(GUI.frame, simulation); + return createdOK; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/LogListener.java b/tools/cooja/java/se/sics/cooja/plugins/LogListener.java new file mode 100644 index 000000000..7b45f007a --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/LogListener.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2006, 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: LogListener.java,v 1.1 2006/08/21 12:13:08 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.Insets; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.Log; + +/** + * A simple mote log listener. + * When instantiated, is registers as a listener on all currently existing + * motes' log interfaces. (Observe that if new motes are added to a simulation, + * a new log listener must be created to listen to those motes also). + * + * @author Fredrik Osterlind + */ +@ClassDescription("Log Listener") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class LogListener extends VisPlugin { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(LogListener.class); + + private JTextArea logTextArea; + private Observer logObserver; + private Simulation simulation; + + /** + * Create a new simulation control panel. + * + * @param simulationToControl Simulation to control + */ + public LogListener(final Simulation simulationToControl) { + super("Log Listener - Listening on ?? mote logs"); + simulation = simulationToControl; + int nrLogs = 0; + + // Log observer + logObserver = new Observer() { + public void update(Observable obs, Object obj) { + logTextArea.append("\n"); + + Mote mote = (Mote) obj; + Log moteLogInterface = (Log) obs; + String outputString = "TIME:" + simulation.getSimulationTime() + "\t"; + if (mote != null && mote.getInterfaces().getMoteID() != null) { + outputString = outputString.concat("ID:" + mote.getInterfaces().getMoteID().getMoteID() + "\t"); + } + outputString = outputString.concat(moteLogInterface.getLastLogMessages()); + + logTextArea.append(outputString); + logTextArea.setCaretPosition(logTextArea.getDocument().getLength()); + } + }; + + // Register as loglistener on all currently active motes + for (int i=0; i < simulation.getMotesCount(); i++) { + if (simulation.getMote(i).getInterfaces().getLog() != null) { + simulation.getMote(i).getInterfaces().getLog().addObserver(logObserver); + nrLogs++; + } + } + + // Main panel + logTextArea = new JTextArea(8,50); + logTextArea.setMargin(new Insets(5,5,5,5)); + logTextArea.setEditable(false); + logTextArea.setCursor(null); + + setContentPane(new JScrollPane(logTextArea)); + setTitle("Log Listener - Listening on " + nrLogs + " mote logs"); + pack(); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + public void closePlugin() { + // Remove log observer from all log interfaces + for (int i=0; i < simulation.getMotesCount(); i++) { + if (simulation.getMote(i).getInterfaces().getLog() != null) + simulation.getMote(i).getInterfaces().getLog().deleteObserver(logObserver); + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/MoteInformation.java b/tools/cooja/java/se/sics/cooja/plugins/MoteInformation.java new file mode 100644 index 000000000..810f3a74f --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/MoteInformation.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2006, 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: MoteInformation.java,v 1.1 2006/08/21 12:13:07 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; + +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * MoteInformation is a simple information window for motes. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Mote Information") +@VisPluginType(VisPluginType.MOTE_PLUGIN) +public class MoteInformation extends VisPlugin { + private static Logger logger = Logger.getLogger(MoteInformation.class); + + private static final long serialVersionUID = 1L; + + private Mote mote; + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + private final JLabel stateLabel; + + private Observer stateObserver; + private Vector visibleMoteInterfaces = new Vector(); + + /** + * Create a new mote information window. + * + * @param moteToView Mote to view + */ + public MoteInformation(Mote moteToView) { + super("Mote Information (" + moteToView + ")"); + + mote = moteToView; + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + + // Remove mote button + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Remove mote"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.WEST, label); + + JButton button = new JButton("Remove"); + button.setActionCommand("removeMote"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + GUI.currentSimulation.removeMote(mote); + dispose(); + } + }); + + smallPane.add(BorderLayout.EAST, button); + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + + // Visualize mote type + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("-- STATE --"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.WEST, label); + if (mote.getState() == Mote.STATE_ACTIVE) + label = new JLabel("active"); + else if (mote.getState() == Mote.STATE_LPM) + label = new JLabel("low power mode"); + else + label = new JLabel("dead"); + + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + stateLabel = label; + + smallPane.add(BorderLayout.EAST, label); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + + + // Visualize mote type + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("-- MOTE TYPE --"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.NORTH, label); + JPanel moteVis = mote.getType().getTypeVisualizer(); + if (moteVis != null) { + moteVis.setBorder(BorderFactory.createEtchedBorder()); + smallPane.add(moteVis); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + } + + + // All interfaces + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("-- INTERFACES --"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.NORTH, label); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,10))); + + for (int i=0; i < mote.getInterfaces().getAllActiveInterfaces().size(); i++) { + smallPane = new JPanel(); + smallPane.setLayout(new BorderLayout()); + + MoteInterface moteInterface = mote.getInterfaces().getAllActiveInterfaces().get(i); + String interfaceDescription = GUI.getDescriptionOf(moteInterface); + JPanel interfaceVisualizer = moteInterface.getInterfaceVisualizer(); + label = new JLabel(interfaceDescription); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + smallPane.add(BorderLayout.NORTH, label); + + if (interfaceVisualizer != null) { + interfaceVisualizer.setBorder(BorderFactory.createEtchedBorder()); + smallPane.add(BorderLayout.CENTER, interfaceVisualizer); + + // Tag each visualized interface to easier release them later + interfaceVisualizer.putClientProperty("my_interface", moteInterface); + visibleMoteInterfaces.add(interfaceVisualizer); + } + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + } + for (int i=0; i < mote.getInterfaces().getAllPassiveInterfaces().size(); i++) { + smallPane = new JPanel(); + smallPane.setLayout(new BorderLayout()); + + MoteInterface moteInterface = mote.getInterfaces().getAllPassiveInterfaces().get(i); + String interfaceDescription = GUI.getDescriptionOf(moteInterface); + + JPanel interfaceVisualizer = moteInterface.getInterfaceVisualizer(); + label = new JLabel(interfaceDescription); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + smallPane.add(BorderLayout.NORTH, label); + + if (interfaceVisualizer != null) { + interfaceVisualizer.setBorder(BorderFactory.createEtchedBorder()); + smallPane.add(BorderLayout.CENTER, interfaceVisualizer); + + // Tag each visualized interface to easier release them later + interfaceVisualizer.putClientProperty("my_interface", moteInterface); + visibleMoteInterfaces.add(interfaceVisualizer); + } + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + } + + + this.setContentPane(new JScrollPane(mainPane, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + pack(); + setPreferredSize(new Dimension(350,500)); + setSize(new Dimension(350,500)); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + // Register as state observer to detect if mote changes state + mote.addStateObserver(stateObserver = new Observer() { + public void update(Observable obs, Object obj) { + if (mote.getState() == Mote.STATE_ACTIVE) + stateLabel.setText("active"); + else if (mote.getState() == Mote.STATE_LPM) + stateLabel.setText("low power mode"); + else + stateLabel.setText("dead"); + } + }); + } + + public void closePlugin() { + // Remove state observer + mote.deleteStateObserver(stateObserver); + + // Release all interface visualizations + for (JPanel interfaceVisualization: visibleMoteInterfaces) { + MoteInterface moteInterface = (MoteInterface) interfaceVisualization.getClientProperty("my_interface"); + if (moteInterface != null && interfaceVisualization != null) + moteInterface.releaseInterfaceVisualizer(interfaceVisualization); + else + logger.warn("Could not release panel"); + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/MoteInterfaceViewer.java b/tools/cooja/java/se/sics/cooja/plugins/MoteInterfaceViewer.java new file mode 100644 index 000000000..68d10bb06 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/MoteInterfaceViewer.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2006, 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: MoteInterfaceViewer.java,v 1.1 2006/08/21 12:13:09 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +import se.sics.cooja.*; + +/** + * MoteInterfaceViewer allows a user to select and view information about a node's interfaces. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Mote Interface Viewer") +@VisPluginType(VisPluginType.MOTE_PLUGIN) +public class MoteInterfaceViewer extends VisPlugin { + private static final long serialVersionUID = 1L; + + private Mote mote; + private MoteInterface selectedMoteInterface = null; + private JPanel currentInterfaceVisualizer = null; + + /** + * Create a new mote interface viewer. + * + * @param moteToView Mote to view + */ + public MoteInterfaceViewer(Mote moteToView) { + super("Mote Interface Viewer (" + moteToView + ")"); + mote = moteToView; + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPane.setLayout(new BorderLayout()); + JPanel smallPane; + + // Select interface combo box + smallPane = new JPanel(new BorderLayout()); + + label = new JLabel("Select interface:"); + + final JComboBox selectInterfaceComboBox = new JComboBox(); + final JPanel interfacePanel = new JPanel(); + + for (int i=0; i < mote.getInterfaces().getAllActiveInterfaces().size(); i++) { + selectInterfaceComboBox.addItem(GUI.getDescriptionOf(mote.getInterfaces().getAllActiveInterfaces().get(i))); + } + for (int i=0; i < mote.getInterfaces().getAllPassiveInterfaces().size(); i++) { + selectInterfaceComboBox.addItem(GUI.getDescriptionOf(mote.getInterfaces().getAllPassiveInterfaces().get(i))); + } + + selectInterfaceComboBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + + // Release old interface visualizer if any + if (selectedMoteInterface != null && currentInterfaceVisualizer != null) + selectedMoteInterface.releaseInterfaceVisualizer(currentInterfaceVisualizer); + + // View selected interface if any + interfacePanel.removeAll(); + String interfaceDescription = (String) selectInterfaceComboBox.getSelectedItem(); + selectedMoteInterface = null; + for (int i=0; i < mote.getInterfaces().getAllActiveInterfaces().size(); i++) { + if (GUI.getDescriptionOf(mote.getInterfaces().getAllActiveInterfaces().get(i)).equals(interfaceDescription)) + selectedMoteInterface = mote.getInterfaces().getAllActiveInterfaces().get(i); + } + for (int i=0; i < mote.getInterfaces().getAllPassiveInterfaces().size(); i++) { + if (GUI.getDescriptionOf(mote.getInterfaces().getAllPassiveInterfaces().get(i)).equals(interfaceDescription)) + selectedMoteInterface = mote.getInterfaces().getAllPassiveInterfaces().get(i); + } + currentInterfaceVisualizer = selectedMoteInterface.getInterfaceVisualizer(); + if (currentInterfaceVisualizer != null) { + currentInterfaceVisualizer.setBorder(BorderFactory.createEtchedBorder()); + interfacePanel.add(BorderLayout.CENTER, currentInterfaceVisualizer); + currentInterfaceVisualizer.setVisible(true); + } else { + interfacePanel.add(new JLabel("No interface visualizer exists!")); + currentInterfaceVisualizer = null; + } + setSize(getSize()); + } + }); + selectInterfaceComboBox.setSelectedIndex(0); + + smallPane.add(BorderLayout.WEST, label); + smallPane.add(BorderLayout.EAST, selectInterfaceComboBox); + mainPane.add(BorderLayout.NORTH, smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,10))); + + // Add selected interface + interfacePanel.setLayout(new BorderLayout()); + if (selectInterfaceComboBox.getItemCount() > 0) { + selectInterfaceComboBox.setSelectedIndex(0); + selectInterfaceComboBox.dispatchEvent(new ActionEvent(selectInterfaceComboBox, ActionEvent.ACTION_PERFORMED, "")); + } + + mainPane.add(BorderLayout.CENTER, interfacePanel); + + this.setContentPane(new JScrollPane(mainPane, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + pack(); + setPreferredSize(new Dimension(350,300)); + setSize(new Dimension(350,300)); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + public void closePlugin() { + // Release old interface visualizer if any + if (selectedMoteInterface != null && currentInterfaceVisualizer != null) + selectedMoteInterface.releaseInterfaceVisualizer(currentInterfaceVisualizer); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/MoteTypeInformation.java b/tools/cooja/java/se/sics/cooja/plugins/MoteTypeInformation.java new file mode 100644 index 000000000..160e59e4e --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/MoteTypeInformation.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2006, 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: MoteTypeInformation.java,v 1.1 2006/08/21 12:13:08 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * Shows a summary of all created mote types. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Mote Type Information") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class MoteTypeInformation extends VisPlugin { + private static Logger logger = Logger.getLogger(MoteTypeInformation.class); + + private static final long serialVersionUID = 1L; + + private Simulation mySimulation; + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + /** + * Create a new mote type information window. + * + * @param simulation Simulation + */ + public MoteTypeInformation(Simulation simulation) { + super("Mote Type Information *frozen*"); + + mySimulation = simulation; + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + + // Visualize mote types + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("-- MOTE TYPES AT TIME " + simulation.getSimulationTime() + " --"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.NORTH, label); + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,10))); + + for (MoteType moteType: mySimulation.getMoteTypes()) { + smallPane = new JPanel(); + smallPane.setLayout(new BorderLayout()); + + label = new JLabel(GUI.getDescriptionOf(moteType) +": " + + "ID=" + moteType.getIdentifier() + + ", \"" + moteType.getDescription() + "\""); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + smallPane.add(BorderLayout.NORTH, label); + + JPanel moteTypeVisualizer = moteType.getTypeVisualizer(); + if (moteTypeVisualizer != null) { + moteTypeVisualizer.setBorder(BorderFactory.createEtchedBorder()); + smallPane.add(BorderLayout.CENTER, moteTypeVisualizer); + } else + smallPane.add(BorderLayout.CENTER, Box.createVerticalStrut(25)); + + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + } + + + this.setContentPane(new JScrollPane(mainPane, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + pack(); + setPreferredSize(new Dimension(350,500)); + setSize(new Dimension(350,500)); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + public void closePlugin() { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/SimControl.java b/tools/cooja/java/se/sics/cooja/plugins/SimControl.java new file mode 100644 index 000000000..be670179e --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/SimControl.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2006, 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: SimControl.java,v 1.1 2006/08/21 12:13:08 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.awt.event.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.NumberFormat; +import java.util.*; +import javax.swing.*; +import javax.swing.event.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * The Control Panel is a simple control panel for simulations. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Control Panel") +@VisPluginType(VisPluginType.SIM_STANDARD_PLUGIN) +public class SimControl extends VisPlugin { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(SimControl.class); + + private static final int MIN_DELAY_TIME = 0; + private static final int MAX_DELAY_TIME = 100; + + private Simulation simulation; + + private JSlider sliderDelay; + private JLabel simulationTime; + private JButton startButton, stopButton; + private JFormattedTextField stopTimeTextField; + private int simulationStopTime = -1; + + private Observer simObserver; + private Observer tickObserver; + + private long lastTextUpdateTime = -1; + + /** + * Create a new simulation control panel. + * + * @param simulationToControl Simulation to control + */ + public SimControl(Simulation simulationToControl) { + super("Control Panel - " + simulationToControl.getTitle()); + + simulation = simulationToControl; + + JButton button; + JPanel smallPanel; + + // Register as tickobserver + simulation.addTickObserver(tickObserver = new Observer() { + public void update(Observable obs, Object obj) { + // During simulation running, only update text 10 times each second + if (lastTextUpdateTime < System.currentTimeMillis() - 100) { + lastTextUpdateTime = System.currentTimeMillis(); + simulationTime.setText("Current simulation time: " + simulation.getSimulationTime()); + } + + if (simulationStopTime > 0 && simulationStopTime <= simulation.getSimulationTime() && simulation.isRunning()) { + // Time to stop simulation now + simulation.stopSimulation(); + simulationStopTime = -1; + } + } + }); + + // Register as simulation observer + simulation.addObserver(simObserver = new Observer() { + public void update(Observable obs, Object obj) { + if (simulation.isRunning()) { + startButton.setEnabled(false); + stopButton.setEnabled(true); + } else { + startButton.setEnabled(true); + stopButton.setEnabled(false); + simulationStopTime = -1; + } + sliderDelay.setValue((int) simulation.getDelayTime()); + simulationTime.setText("Current simulation time: " + simulation.getSimulationTime()); + } + }); + + + // Main panel + JPanel controlPanel = new JPanel(); + controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS)); + + setContentPane(controlPanel); + + // Add control buttons + smallPanel = new JPanel(); + smallPanel.setLayout(new BoxLayout(smallPanel, BoxLayout.X_AXIS)); + smallPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5)); + + button = new JButton("Start"); + button.setActionCommand("start"); + button.addActionListener(myEventHandler); + startButton = button; + smallPanel.add(button); + + button = new JButton("Stop"); + button.setActionCommand("stop"); + button.addActionListener(myEventHandler); + stopButton = button; + smallPanel.add(button); + + button = new JButton("Tick all motes once"); + button.setActionCommand("tickall"); + button.addActionListener(myEventHandler); + smallPanel.add(button); + + smallPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + controlPanel.add(smallPanel); + + smallPanel = new JPanel(); + smallPanel.setLayout(new BoxLayout(smallPanel, BoxLayout.X_AXIS)); + smallPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 10, 5)); + + button = new JButton("Run until"); + button.setActionCommand("rununtil"); + button.addActionListener(myEventHandler); + smallPanel.add(button); + + smallPanel.add(Box.createHorizontalStrut(10)); + + NumberFormat integerFormat = NumberFormat.getIntegerInstance(); + stopTimeTextField = new JFormattedTextField(integerFormat); + stopTimeTextField.setValue(simulation.getSimulationTime()); + stopTimeTextField.addPropertyChangeListener("value", new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + JFormattedTextField numberTextField = (JFormattedTextField) e.getSource(); + int untilTime = ((Number) numberTextField.getValue()).intValue(); + if (untilTime < simulation.getSimulationTime()) { + numberTextField.setValue(new Integer(simulation.getSimulationTime() + simulation.getTickTime())); + } + } + }); + smallPanel.add(stopTimeTextField); + + smallPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + controlPanel.add(smallPanel); + + + // Add delay slider + smallPanel = new JPanel(); + smallPanel.setLayout(new BoxLayout(smallPanel, BoxLayout.Y_AXIS)); + smallPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + simulationTime = new JLabel(); + simulationTime.setText("Current simulation time: " + simulation.getSimulationTime()); + + smallPanel.add(simulationTime); + smallPanel.add(Box.createRigidArea(new Dimension(0, 10))); + + smallPanel.add(new JLabel("Delay (ms) between each tick")); + + JSlider slider; + if (simulation.getDelayTime() > MAX_DELAY_TIME) + slider = new JSlider(JSlider.HORIZONTAL, MIN_DELAY_TIME, simulation.getDelayTime(), simulation.getDelayTime()); + else + slider = new JSlider(JSlider.HORIZONTAL, MIN_DELAY_TIME, MAX_DELAY_TIME, simulation.getDelayTime()); + + slider.addChangeListener(myEventHandler); + slider.setMajorTickSpacing(20); + slider.setPaintTicks(true); + + slider.setPaintLabels(true); + + sliderDelay = slider; + smallPanel.add(slider); + + controlPanel.add(smallPanel); + + pack(); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + private class MyEventHandler implements ActionListener, ChangeListener { + public void stateChanged(ChangeEvent e) { + if (e.getSource() == sliderDelay) { + simulation.setDelayTime(sliderDelay.getValue()); + } else + logger.debug("Unhandled state change: " + e); + } + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("start")) { + simulationStopTime = -1; // Reset until time + simulation.startSimulation(); + } else if (e.getActionCommand().equals("stop")) { + simulationStopTime = -1; // Reset until time + if (simulation.isRunning()) + simulation.stopSimulation(); + } else if (e.getActionCommand().equals("tickall")) { + simulationStopTime = -1; // Reset until time + simulation.tickSimulation(); + } else if (e.getActionCommand().equals("rununtil")) { + // Set new stop time + simulationStopTime = ((Number) stopTimeTextField.getValue()).intValue(); + if (simulationStopTime > simulation.getSimulationTime() && !simulation.isRunning()) { + simulation.startSimulation(); + } else { + if (simulation.isRunning()) + simulation.stopSimulation(); + simulationStopTime = -1; + } + } else + logger.debug("Unhandled action: " + e.getActionCommand()); + } + } MyEventHandler myEventHandler = new MyEventHandler(); + + public void closePlugin() { + // Remove log observer from all log interfaces + if (simObserver != null) + simulation.deleteObserver(simObserver); + + if (tickObserver != null) + simulation.deleteTickObserver(tickObserver); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/SimInformation.java b/tools/cooja/java/se/sics/cooja/plugins/SimInformation.java new file mode 100644 index 000000000..fe35be0ca --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/SimInformation.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2006, 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: SimInformation.java,v 1.1 2006/08/21 12:13:07 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.util.*; +import javax.swing.*; + +import se.sics.cooja.*; + +/** + * SimInformation is a simple information window for simulations. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Simulation Information") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class SimInformation extends VisPlugin { + private static final long serialVersionUID = 1L; + private Simulation simulation; + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + private JLabel labelStatus; + private JLabel labelSimTime; + private JLabel labelNrMotes; + private JLabel labelNrMoteTypes; + + private Observer simObserver; + private Observer tickObserver; + + /** + * Create a new simulation information window. + * + * @param simulationToView Simulation to view + */ + public SimInformation(Simulation simulationToView) { + super("Simulation Information"); + + simulation = simulationToView; + + // Register as simulation observer + simulation.addObserver(simObserver = new Observer() { + public void update(Observable obs, Object obj) { + if (simulation.isRunning()) { + labelStatus.setText("RUNNING"); + } else { + labelStatus.setText("STOPPED"); + } + labelNrMotes.setText("" + simulation.getMotesCount()); + labelNrMoteTypes.setText("" + simulation.getMoteTypes().size()); + + } + }); + + // Register as tick observer + simulation.addTickObserver(tickObserver = new Observer() { + public void update(Observable obs, Object obj) { + labelSimTime.setText("" + simulation.getSimulationTime()); + } + }); + + JLabel label; + JPanel mainPane = new JPanel(); + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + + // Status information + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Status"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(label); + + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + + label = new JLabel(); + if (simulation.isRunning()) + label.setText("RUNNING"); + else + label.setText("STOPPED"); + + labelStatus = label; + smallPane.add(label); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + // Current simulation time + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Simulation time"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(label); + + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + + label = new JLabel(); + label.setText("" + simulation.getSimulationTime()); + + labelSimTime = label; + smallPane.add(label); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + // Number of motes + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Number of motes"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(label); + + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + + label = new JLabel(); + label.setText("" + simulation.getMotesCount()); + + labelNrMotes = label; + smallPane.add(label); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + + // Number of mote types + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Number of mote types"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(label); + + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + + label = new JLabel(); + label.setText("" + simulation.getMoteTypes().size()); + + labelNrMoteTypes = label; + smallPane.add(label); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + + + // Radio Medium type + smallPane = new JPanel(); + smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); + smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); + label = new JLabel("Radio medium"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(label); + + smallPane.add(Box.createHorizontalStrut(10)); + smallPane.add(Box.createHorizontalGlue()); + + Class radioMediumClass = simulation.getRadioMedium().getClass(); + String description = GUI.getDescriptionOf(radioMediumClass); + label = new JLabel(description); + + smallPane.add(label); + + mainPane.add(smallPane); + + mainPane.add(Box.createRigidArea(new Dimension(0,5))); + + + this.setContentPane(mainPane); + pack(); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + public void closePlugin() { + // Remove log observer from all log interfaces + if (simObserver != null) + simulation.deleteObserver(simObserver); + + if (tickObserver != null) + simulation.deleteTickObserver(tickObserver); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/VariableWatcher.java b/tools/cooja/java/se/sics/cooja/plugins/VariableWatcher.java new file mode 100644 index 000000000..5d1c78f2b --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/VariableWatcher.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2006, 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: VariableWatcher.java,v 1.1 2006/08/21 12:13:07 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; +import java.text.NumberFormat; +import javax.swing.*; + +import se.sics.cooja.*; + +/** + * Variable Watcher enables a user to watch mote variables during a simulation. + * Variables can be read or written either as bytes, integers (4 bytes) or byte arrays. + * + * User can also see which variables seems to be available on the selected node. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Variable Watcher") +@VisPluginType(VisPluginType.MOTE_PLUGIN) +public class VariableWatcher extends VisPlugin { + private static final long serialVersionUID = 1L; + + private SectionMoteMemory moteMemory; + + private final static int LABEL_WIDTH = 170; + private final static int LABEL_HEIGHT = 15; + + private final static int BYTE_INDEX = 0; + private final static int INT_INDEX = 1; + private final static int ARRAY_INDEX = 2; + + private JPanel lengthPane; + private JPanel valuePane; + private JComboBox varName; + private JFormattedTextField[] varValues; + private JFormattedTextField varLength; + private JButton writeButton; + + private NumberFormat integerFormat; + + /** + * Create a variable watcher window. + * + * @param moteToView Mote to view + */ + public VariableWatcher(Mote moteToView) { + super("Variable Watcher (" + moteToView + ")"); + + moteMemory = (SectionMoteMemory) moteToView.getMemory(); + + JLabel label; + integerFormat = NumberFormat.getIntegerInstance(); + JPanel mainPane = new JPanel(); + mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); + JPanel smallPane; + + // Variable name + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Variable name"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.WEST, label); + + varName = new JComboBox(); + varName.setEditable(true); + varName.setSelectedItem("[enter or pick name]"); + + String[] allPotentialVarNames = moteMemory.getVariableNames(); + for (String aVarName: allPotentialVarNames) + varName.addItem(aVarName); + + varName.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + writeButton.setEnabled(false); + } + public void keyTyped(KeyEvent e) { + writeButton.setEnabled(false); + } + public void keyReleased(KeyEvent e) { + writeButton.setEnabled(false); + } + }); + + smallPane.add(BorderLayout.EAST, varName); + mainPane.add(smallPane); + + // Variable type + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Variable type"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + smallPane.add(BorderLayout.WEST, label); + + final JComboBox varType = new JComboBox(); + varType.addItem("Byte (1 byte)"); // BYTE_INDEX = 0 + varType.addItem("Integer (4 bytes)"); // INT_INDEX = 1 + varType.addItem("Byte array (x bytes)"); // ARRAY_INDEX = 2 + + varType.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (varType.getSelectedIndex() == ARRAY_INDEX) { + lengthPane.setVisible(true); + setNumberOfValues(((Number) varLength.getValue()).intValue()); + } else { + lengthPane.setVisible(false); + setNumberOfValues(1); + } + pack(); + } + }); + + smallPane.add(BorderLayout.EAST, varType); + mainPane.add(smallPane); + + // Variable length + lengthPane = new JPanel(new BorderLayout()); + label = new JLabel("Variable length"); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + lengthPane.add(BorderLayout.WEST, label); + + varLength = new JFormattedTextField(integerFormat); + varLength.setValue(new Integer(1)); + varLength.setColumns(4); + varLength.addPropertyChangeListener("value", new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + setNumberOfValues(((Number) varLength.getValue()).intValue()); + } + }); + + lengthPane.add(BorderLayout.EAST, varLength); + mainPane.add(lengthPane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + + lengthPane.setVisible(false); + + // Variable value label + label = new JLabel("Variable value"); + label.setAlignmentX(JLabel.CENTER_ALIGNMENT); + label.setPreferredSize(new Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + mainPane.add(label); + + // Variable value(s) + valuePane = new JPanel(); + valuePane.setLayout(new BoxLayout(valuePane, BoxLayout.X_AXIS)); + + varValues = new JFormattedTextField[1]; + varValues[0] = new JFormattedTextField(integerFormat); + varValues[0].setValue(new Integer(0)); + varValues[0].setColumns(3); + varValues[0].setText("?"); + + for (JFormattedTextField varValue: varValues) { + valuePane.add(varValue); + + } + + mainPane.add(valuePane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + + // Read/write buttons + smallPane = new JPanel(new BorderLayout()); + JButton button = new JButton("Read"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (varType.getSelectedIndex() == BYTE_INDEX) { + try { + byte val = moteMemory.getByteValueOf((String) varName.getSelectedItem()); + varValues[0].setValue(new Integer(val)); + varName.setBackground(Color.WHITE); + writeButton.setEnabled(true); + } catch (Exception ex) { + varName.setBackground(Color.RED); + writeButton.setEnabled(false); + } + } else if (varType.getSelectedIndex() == INT_INDEX) { + try { + int val = moteMemory.getIntValueOf((String) varName.getSelectedItem()); + varValues[0].setValue(new Integer(val)); + varName.setBackground(Color.WHITE); + writeButton.setEnabled(true); + } catch (Exception ex) { + varName.setBackground(Color.RED); + writeButton.setEnabled(false); + } + } else if (varType.getSelectedIndex() == ARRAY_INDEX) { + try { + int length = ((Number) varLength.getValue()).intValue(); + byte[] vals = moteMemory.getByteArray((String) varName.getSelectedItem(), length); + for (int i=0; i < length; i++) + varValues[i].setValue(new Integer(vals[i])); + varName.setBackground(Color.WHITE); + writeButton.setEnabled(true); + } catch (Exception ex) { + varName.setBackground(Color.RED); + writeButton.setEnabled(false); + } + } + } + }); + smallPane.add(BorderLayout.WEST, button); + + button = new JButton("Write"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (varType.getSelectedIndex() == BYTE_INDEX) { + try { + byte val = (byte) ((Number) varValues[0].getValue()).intValue(); + moteMemory.setByteValueOf((String) varName.getSelectedItem(), val); + varName.setBackground(Color.WHITE); + } catch (Exception ex) { + varName.setBackground(Color.RED); + } + } else if (varType.getSelectedIndex() == INT_INDEX) { + try { + int val = ((Number) varValues[0].getValue()).intValue(); + moteMemory.setIntValueOf((String) varName.getSelectedItem(), val); + varName.setBackground(Color.WHITE); + } catch (Exception ex) { + varName.setBackground(Color.RED); + } + } else if (varType.getSelectedIndex() == ARRAY_INDEX) { + try { + int length = ((Number) varLength.getValue()).intValue(); + byte[] vals = new byte[length]; + for (int i=0; i < length; i++) { + vals[i] = (byte) ((Number) varValues[i].getValue()).intValue(); + } + + moteMemory.setByteArray((String) varName.getSelectedItem(), vals); + varName.setBackground(Color.WHITE); + writeButton.setEnabled(true); + } catch (Exception ex) { + varName.setBackground(Color.RED); + writeButton.setEnabled(false); + } + } + } + }); + smallPane.add(BorderLayout.EAST, button); + button.setEnabled(false); + writeButton = button; + + + mainPane.add(smallPane); + mainPane.add(Box.createRigidArea(new Dimension(0,25))); + + this.setContentPane(new JScrollPane(mainPane, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + pack(); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + + } + + private void setNumberOfValues(int nr) { + valuePane.removeAll(); + + if (nr > 0) { + varValues = new JFormattedTextField[nr]; + for (int i=0; i < nr; i++) { + varValues[i] = new JFormattedTextField(integerFormat); + varValues[i] .setValue(new Integer(0)); + varValues[i] .setColumns(3); + varValues[i] .setText("?"); + valuePane.add(varValues[i]); + } + } + pack(); + } + + public void closePlugin() { + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/VisBattery.java b/tools/cooja/java/se/sics/cooja/plugins/VisBattery.java new file mode 100644 index 000000000..221c29a25 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/VisBattery.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006, 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: VisBattery.java,v 1.1 2006/08/21 12:13:08 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.util.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.Battery; + +/** + * A Battery Visualizer indicates mote energy levels by painting them in + * different colors. The mote is painted in a grayscale where white is max + * energy and black is no energy left. If a mote has no battery interface or + * infinite energy, it is painted blue. If a mote is dead it is painted red. + * + * A VisBattery observers both the simulation and all mote batteries. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Battery Visualizer") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class VisBattery extends Visualizer2D { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(VisBattery.class); + + private Simulation simulation; + + private Observer simObserver = null; // Watches simulation changes + private Observer batteryObserver = null; // Watches mote battery changes + + /** + * Creates a new battery visualizer. + * + * @param simulationToVisualize + * Simulation to visualize + */ + public VisBattery(Simulation simulationToVisualize) { + super(simulationToVisualize); + setTitle("Battery Visualizer"); + + simulation = simulationToVisualize; + + // Always observe all motes in simulation + batteryObserver = new Observer() { + public void update(Observable obs, Object obj) { + getCurrentCanvas().repaint(); + } + }; + simulation.addObserver(simObserver = new Observer() { + public void update(Observable obs, Object obj) { + // Register (or reregister) as observer on all motes + for (int i = 0; i < simulation.getMotesCount(); i++) { + Battery battery = simulation.getMote(i).getInterfaces().getBattery(); + if (battery != null) { + battery.addObserver(batteryObserver); + } + } + } + }); + simObserver.update(null, null); + + } + + public void postVisualizeSimulation(Graphics g) { + } + + public Color[] getColorOf(Mote mote) { + if (mote.getState() == Mote.STATE_DEAD) + return new Color[]{Color.RED}; + + Battery battery = mote.getInterfaces().getBattery(); + if (battery == null) { + return new Color[]{Color.BLUE}; + } + + if (battery.hasInfiniteEnergy()) { + return new Color[]{Color.BLUE}; + } + + double currentEnergy = battery.getCurrentEnergy(); + + if (currentEnergy < 0.0) { + return new Color[]{Color.RED}; + } + + int grayValue = (int) (255 * (currentEnergy / battery.getInitialEnergy())); + return new Color[]{new Color(grayValue, grayValue, grayValue)}; + } + + public void closePlugin() { + if (simObserver != null) { + simulation.deleteObserver(simObserver); + + // Delete all state observers + for (int i = 0; i < simulation.getMotesCount(); i++) { + Battery battery = simulation.getMote(i).getInterfaces().getBattery(); + if (battery != null) { + battery.deleteObserver(batteryObserver); + } + } + } + + super.closePlugin(); + } + + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/VisState.java b/tools/cooja/java/se/sics/cooja/plugins/VisState.java new file mode 100644 index 000000000..ec3bb33e7 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/VisState.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2006, 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: VisState.java,v 1.1 2006/08/21 12:13:07 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.util.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; + +/** + * A State Visualizer indicates mote states by painting them in different colors. + * Active motes are green, sleeping motes are gray and dead motes are read. + * + * The inner color indicates the mote type. + * + * A VisState observes both the simulation and all mote states. + * + * @author Fredrik Osterlind + */ +@ClassDescription("State Visualizer") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class VisState extends Visualizer2D { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(VisState.class); + + private Simulation simulation; + + private static final Color moteTypeColors[] = new Color[] { + Color.MAGENTA, + Color.CYAN, + Color.ORANGE, + Color.GREEN, + Color.BLUE, + Color.RED, + Color.YELLOW, + }; + + private Observer simObserver = null; // Watches simulation changes + private Observer stateObserver = null; // Watches mote state changes + + /** + * Creates a new state visualizer. + * + * @param simulationToVisualize Simulation to visualize + */ + public VisState(Simulation simulationToVisualize) { + super(simulationToVisualize); + setTitle("State Visualizer"); + + simulation = simulationToVisualize; + + // Always observe all motes in simulation + stateObserver = new Observer() { + public void update(Observable obs, Object obj) { + getCurrentCanvas().repaint(); + } + }; + simulation.addObserver(simObserver = new Observer() { + public void update(Observable obs, Object obj) { + // Register (or reregister) as observer on all motes + for (int i=0; i < simulation.getMotesCount(); i++) { + Mote mote = simulation.getMote(i); + if (mote != null) { + mote.addStateObserver(stateObserver); + } + } + } + }); + simObserver.update(null, null); + + } + + public void postVisualizeSimulation(Graphics g) { + } + + public Color[] getColorOf(Mote mote) { + Color[] returnColors = new Color[2]; + + // If mote is sleeping, make outer circle blue + if (mote.getState() == Mote.STATE_LPM) + returnColors[1] = Color.GRAY; + + // If mote is dead, make outer circle red + else if (mote.getState() == Mote.STATE_DEAD) + returnColors[1] = Color.RED; + + else + returnColors[1] = Color.GREEN; // make outer circle green + + + // Associate different colors with different mote types + Vector allTypes = simulation.getMoteTypes(); + int numberOfTypes = allTypes.size(); + + for (int colCounter=0; colCounter < numberOfTypes && colCounter < moteTypeColors.length; colCounter++) { + if (mote.getType() == allTypes.get(colCounter)) { + returnColors[0] = moteTypeColors[colCounter]; + return returnColors; + } + } + + returnColors[0] = Color.WHITE; + return returnColors; + } + + public void closePlugin() { + if (simObserver != null) { + simulation.deleteObserver(simObserver); + + // Delete all state observers + for (int i=0; i < simulation.getMotesCount(); i++) { + Mote mote = simulation.getMote(i); + if (mote != null) { + mote.deleteStateObserver(stateObserver); + } + } + } + + super.closePlugin(); + } +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java b/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java new file mode 100644 index 000000000..319f0fc65 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/VisTraffic.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2006, 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: VisTraffic.java,v 1.1 2006/08/21 12:13:07 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Observable; +import java.util.Observer; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.Position; + +/** + * A Traffic Visualizer visualizes radio traffic by painting lines between + * communicating motes. + * + * A VisTraffic observers the current simulation radio medium. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Traffic Visualizer") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public class VisTraffic extends Visualizer2D { + private static final long serialVersionUID = 1L; + private RadioMedium radioMedium; + + /** + * The image painted on screen at repaint(). + */ + public BufferedImage image; + + private Position oldSmallPosition = null; + private Position oldBigPosition = null; + private Simulation simulation; + private int oldNrMotes; + + private Observer radioObserver = null; + + /** + * Creates a new VisTraffic visualizer. + * + * @param simulationToVisualize + * Simulation to visualize + */ + public VisTraffic(Simulation simulationToVisualize) { + super(simulationToVisualize); + setTitle("Traffic Visualizer"); + simulation = simulationToVisualize; + oldNrMotes = simulation.getMotesCount(); + + radioMedium = simulationToVisualize.getRadioMedium(); + + // Repaint when radio medium has sent data + simulationToVisualize.getRadioMedium().addRadioMediumObserver(radioObserver = new Observer() { + public void update(Observable obs, Object obj) { + Graphics2D g2d = image.createGraphics(); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f)); + if (radioMedium != null && radioMedium.getLastTickConnections() != null) { + for (RadioConnection conn: radioMedium.getLastTickConnections()) { + paintConnection(conn, g2d); + } + } + getCurrentCanvas().repaint(); + } + }); + + } + + /** + * Paints given connection on given graphics. + * + * @param connection Connection + * @param g2d Graphics to paint on + */ + protected void paintConnection(RadioConnection connection, Graphics g2d) { + Point sourcePixelPosition = transformPositionToPixel(connection.getSourcePosition()); + for (Position destPosition: connection.getDestinationPositons()) { + Point destPixelPosition = transformPositionToPixel(destPosition); + g2d.setColor(getColorOf(connection)); + g2d.drawLine(sourcePixelPosition.x, sourcePixelPosition.y, + destPixelPosition.x, destPixelPosition.y); + + } + } + + /** + * Returns color a specific connection should be painted in. + * + * @param connection Connection + */ + protected Color getColorOf(RadioConnection connection) { + return Color.BLACK; + } + + protected void calculateTransformations() { + super.calculateTransformations(); + Dimension imageDimension = getCurrentCanvas().getPreferredSize(); + if (imageDimension.height <= 0 || imageDimension.width <= 0) + return; + + // Recreate image if .. + if ( + // .. it hasn't been painted before + oldSmallPosition == null || + oldBigPosition == null || + image == null || + simulation == null || + + // .. mote changes may have changed the transformation. + simulation.getMotesCount() != oldNrMotes || + + // .. visualization window has changed the transformation. + imageDimension.height != image.getHeight() || + imageDimension.width != image.getWidth() + ) { + if (simulation != null) + oldNrMotes = simulation.getMotesCount(); + + BufferedImage oldImage = image; + image = new BufferedImage(imageDimension.width, imageDimension.height, BufferedImage.TYPE_4BYTE_ABGR); + image.createGraphics().setColor(Color.WHITE); + image.createGraphics().fillRect(0, 0, imageDimension.width, imageDimension.height); + + // If old data exists, keep it + if (oldSmallPosition != null && oldBigPosition != null) { + Point oldSmallPixelPos = transformPositionToPixel(oldSmallPosition); + Point oldBigPixelPos = transformPositionToPixel(oldBigPosition); + image.createGraphics().drawImage(oldImage, + oldSmallPixelPos.x, + oldSmallPixelPos.y, + oldBigPixelPos.x-oldSmallPixelPos.x, + oldBigPixelPos.y-oldSmallPixelPos.y, + null); + } + + oldSmallPosition = transformPixelToPositon(new Point(0,0)); + oldBigPosition = transformPixelToPositon(new Point(imageDimension.width, imageDimension.height)); + } + } + + public void closePlugin() { + super.closePlugin(); + + // Remove radio observer + radioMedium.deleteRadioMediumObserver(radioObserver); + } + + public Color[] getColorOf(Mote m) { + return null; + } + + protected void visualizeSimulation(Graphics g) { + g.drawImage(image, 0, 0, null); + } + +} diff --git a/tools/cooja/java/se/sics/cooja/plugins/Visualizer2D.java b/tools/cooja/java/se/sics/cooja/plugins/Visualizer2D.java new file mode 100644 index 000000000..1b3d6f664 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/plugins/Visualizer2D.java @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2006, 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: Visualizer2D.java,v 1.1 2006/08/21 12:13:08 fros4943 Exp $ + */ + +package se.sics.cooja.plugins; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.*; + +/** + * Visualizer2D is an abstract mote visualizer for simulations. All motes are + * painted in the XY-plane, as seen from positive Z axis. + * + * An implementation of this class must colorize the different motes, each mote + * has two different colors; inner and outer. + * + * By right-clicking the mouse on a mote a popup menu will be displayed. From + * this menu mote plugins can be started. or the mote can be moved. Each + * implementation may also register its own actions to be accessed from this + * menu. + * + * A Visualizer2D observers both the simulation and all mote positions. + * + * @author Fredrik Osterlind + */ +@ClassDescription("2D Mote Visualizer") +@VisPluginType(VisPluginType.SIM_PLUGIN) +public abstract class Visualizer2D extends VisPlugin { + private static final long serialVersionUID = 1L; + private static Logger logger = Logger.getLogger(Visualizer2D.class); + + private double factorXCoordToPixel; + private double factorYCoordToPixel; + private double smallestXCoord; + private double smallestYCoord; + + private Simulation simulation = null; + private final JPanel canvas; + private Visualizer2D myPlugin; + + private static final int CANVAS_BORDER_WIDTH = 25; + private static final int MOTE_RADIUS = 8; + + private boolean moteIsBeingMoved = false; + private Mote moteToMove = null; + + private Observer simObserver = null; // Watches simulation changes + private Observer posObserver = null; // Watches position changes + + public interface MoteMenuAction { + public boolean isEnabled(Mote mote); + public String getDescription(Mote mote); + public void doAction(Mote mote); + } + + private class MoveMoteMenuAction implements MoteMenuAction { + public boolean isEnabled(Mote mote) { + return true; + } + public String getDescription(Mote mote) { + return "Move " + mote; + } + public void doAction(Mote mote) { + beginMoveRequest(mote); + } + }; + + private Vector menuActions = new Vector(); + + /** + * Registers as an simulation observer and initializes the canvas. + * + * @param simulationToVisualize + * Simulation to visualize + */ + public Visualizer2D(Simulation simulationToVisualize) { + super("Visualizer2D"); + + myPlugin = this; + + // Set initial bounds of frame + this.setBounds(150, 150, 300, 300); + setVisible(true); + + simulation = simulationToVisualize; + + // Create "canvas" to paint on + canvas = new JPanel() { + private static final long serialVersionUID = 1L; + public void paintComponent(Graphics g) { + super.paintComponent(g); + visualizeSimulation(g); + } + }; + canvas.setPreferredSize(new Dimension(getSize().width - 16, + getSize().height - 38)); + canvas.setBorder(BorderFactory.createLineBorder(Color.GREEN, 2)); + canvas.setBackground(Color.WHITE); + calculateTransformations(); + + this.setContentPane(canvas); + + // Detect general simulation changes + posObserver = new Observer() { + public void update(Observable obs, Object obj) { + calculateTransformations(); + canvas.repaint(); + } + }; + simulation.addObserver(simObserver = new Observer() { + public void update(Observable obs, Object obj) { + canvas.setPreferredSize(new Dimension(getSize().width - 16, + getSize().height - 38)); + + // Register (or reregister) as observer on all mote positions + for (int i = 0; i < simulation.getMotesCount(); i++) { + Position posIntf = simulation.getMote(i).getInterfaces() + .getPosition(); + if (posIntf != null) { + posIntf.addObserver(posObserver); + } + } + + calculateTransformations(); + canvas.repaint(); + } + }); + simObserver.update(null, null); + + canvas.addMouseMotionListener(new MouseMotionListener() { + public void mouseMoved(MouseEvent e) { + myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, false); + } + public void mouseDragged(MouseEvent e) { + myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, false); + } + }); + + // Detect mouse events + canvas.addMouseListener(new MouseListener() { + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) + myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y); + else { + myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, false); + } + } + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) + myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y); + else { + myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, true); + } + } + public void mouseEntered(MouseEvent e) { + if (e.isPopupTrigger()) + myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y); + } + public void mouseExited(MouseEvent e) { + if (e.isPopupTrigger()) + myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y); + } + public void mouseClicked(MouseEvent e) { + if (e.isPopupTrigger()) + myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y); + } + }); + + // Detect component events + addComponentListener(new ComponentListener() { + public void componentMoved(ComponentEvent ce) { + // NOP + } + public void componentShown(ComponentEvent ce) { + // NOP + } + public void componentHidden(ComponentEvent ce) { + // NOP + } + public void componentResized(ComponentEvent ce) { + canvas.setPreferredSize(new Dimension(getSize().width - 16, + getSize().height - 38)); + calculateTransformations(); + canvas.repaint(); + } + }); + + // Add menu action for moving motes + addMoteMenuAction(new MoveMoteMenuAction()); + + try { + setSelected(true); + } catch (java.beans.PropertyVetoException e) { + // Could not select + } + } + + /** + * Add new mote menu action. + * + * @see MoteMenuAction + * @param menuAction Menu action + */ + public void addMoteMenuAction(MoteMenuAction menuAction) { + menuActions.add(menuAction); + } + + private void handlePopupRequest(final int x, final int y) { + final Vector foundMotes = findMotesAtPosition(x, y); + if (foundMotes == null || foundMotes.size() == 0) + return; + + JPopupMenu pickMoteMenu = new JPopupMenu(); + pickMoteMenu.add(new JLabel("Select action:")); + pickMoteMenu.add(new JSeparator()); + + // Add 'show mote plugins'-actions + for (final Mote mote : foundMotes) { + final Point pos = new Point(canvas.getLocationOnScreen().x + x, canvas + .getLocationOnScreen().y + + y); + + JMenuItem menuItem = new JMenuItem("Open mote plugin for " + mote); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + GUI.currentGUI.showMotePluginsMenu(canvas, mote, pos); + } + }); + pickMoteMenu.add(menuItem); + } + + // Add the rest of the actions + for (final MoteMenuAction menuAction : menuActions) { + for (final Mote mote : foundMotes) { + if (menuAction.isEnabled(mote)) { + JMenuItem menuItem = new JMenuItem(menuAction.getDescription(mote)); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + menuAction.doAction(mote); + } + }); + pickMoteMenu.add(menuItem); + } + } + } + + // Show menu + Point pos = new Point(canvas.getLocationOnScreen().x + x, canvas + .getLocationOnScreen().y + + y); + pickMoteMenu.setLocation(pos.x, pos.y); + pickMoteMenu.setInvoker(canvas); + pickMoteMenu.setVisible(true); + } + + private void beginMoveRequest(Mote moteToMove) { + moteIsBeingMoved = true; + this.moteToMove = moteToMove; + } + + private void handleMoveRequest(final int x, final int y, + boolean wasJustReleased) { + if (!moteIsBeingMoved) { + return; + } + + if (!wasJustReleased) { + visualizeSimulation(canvas.getGraphics()); + canvas.paintImmediately(x - 40, y - 40, 80, 80); + canvas.getGraphics().setColor(Color.GRAY); + canvas.getGraphics().drawOval(x - MOTE_RADIUS, y - MOTE_RADIUS, + 2 * MOTE_RADIUS, 2 * MOTE_RADIUS); + } + + if (wasJustReleased) { + moteIsBeingMoved = false; + + Position newXYValues = transformPixelToPositon(new Point(x, y)); + int returnValue = JOptionPane.showConfirmDialog(myPlugin, "Mote mote to" + + "\nX=" + newXYValues.getXCoordinate() + "\nY=" + + newXYValues.getYCoordinate() + "\nZ=" + + moteToMove.getInterfaces().getPosition().getZCoordinate()); + + if (returnValue == JOptionPane.OK_OPTION) { + moteToMove.getInterfaces().getPosition().setCoordinates( + newXYValues.getXCoordinate(), newXYValues.getYCoordinate(), + moteToMove.getInterfaces().getPosition().getZCoordinate()); + repaint(); + } + } + + } + + /** + * Returns all motes at given position. + * + * @param clickedX + * X coordinate + * @param clickedY + * Y coordinate + * @return All motes at given position + */ + protected Vector findMotesAtPosition(int clickedX, int clickedY) { + double xCoord = factorXPixelToCoord(clickedX); + double yCoord = factorYPixelToCoord(clickedY); + + Vector motesFound = new Vector(); + + // Calculate painted mote radius in coordinates + double paintedMoteWidth = factorXPixelToCoord(MOTE_RADIUS) + - factorXPixelToCoord(0); + double paintedMoteHeight = factorYPixelToCoord(MOTE_RADIUS) + - factorYPixelToCoord(0); + + for (int i = 0; i < simulation.getMotesCount(); i++) { + Position pos = simulation.getMote(i).getInterfaces().getPosition(); + + // Transform to unit circle before checking if mouse hit this mote + double distanceX = Math.abs(xCoord - pos.getXCoordinate()) + / paintedMoteWidth; + double distanceY = Math.abs(yCoord - pos.getYCoordinate()) + / paintedMoteHeight; + + if (distanceX * distanceX + distanceY * distanceY <= 1) { + motesFound.add(simulation.getMote(i)); + } + } + if (motesFound.size() == 0) + return null; + + return motesFound; + } + + /** + * Get colors a certain mote should be painted with. May be overridden to get + * a different color scheme. + * + * Normally this method returns an array of two colors, one for the state + * (outer circle), the other for the type (inner circle). + * + * If this method only returns one color, the entire mote will be painted + * using that. + * + * @param mote + * Mote to paint + * @return Color[] { Inner color, Outer color } + */ + abstract public Color[] getColorOf(Mote mote); + + protected void visualizeSimulation(Graphics g) { + for (int i = 0; i < simulation.getMotesCount(); i++) { + Mote mote = simulation.getMote(i); + Color moteColors[] = getColorOf(mote); + Position motePos = mote.getInterfaces().getPosition(); + + Point pixelCoord = transformPositionToPixel(motePos); + int x = pixelCoord.x; + int y = pixelCoord.y; + + if (moteColors.length >= 1) { + g.setColor(moteColors[0]); + g.fillOval(x - MOTE_RADIUS, y - MOTE_RADIUS, 2 * MOTE_RADIUS, + 2 * MOTE_RADIUS); + } + + if (moteColors.length >= 2) { + g.setColor(moteColors[1]); + g.fillOval(x - MOTE_RADIUS / 2, y - MOTE_RADIUS / 2, MOTE_RADIUS, + MOTE_RADIUS); + } + + g.setColor(Color.BLACK); + g.drawOval(x - MOTE_RADIUS, y - MOTE_RADIUS, 2 * MOTE_RADIUS, + 2 * MOTE_RADIUS); + + } + } + + /** + * Recalculate size of canvas and factors for transforming between real and + * pixel coordinates. This method is called every time this frame is resized + * or created. + */ + protected void calculateTransformations() { + if (simulation.getMotesCount() == 0) { + smallestXCoord = 0; + smallestYCoord = 0; + factorXCoordToPixel = 1; + factorYCoordToPixel = 1; + return; + } + + double biggestXCoord, biggestYCoord; + + Position motePos = simulation.getMote(0).getInterfaces().getPosition(); + smallestXCoord = biggestXCoord = motePos.getXCoordinate(); + smallestYCoord = biggestYCoord = motePos.getYCoordinate(); + + // Get extreme coordinates + for (int i = 0; i < simulation.getMotesCount(); i++) { + motePos = simulation.getMote(i).getInterfaces().getPosition(); + + if (motePos.getXCoordinate() < smallestXCoord) + smallestXCoord = motePos.getXCoordinate(); + + if (motePos.getXCoordinate() > biggestXCoord) + biggestXCoord = motePos.getXCoordinate(); + + if (motePos.getYCoordinate() < smallestYCoord) + smallestYCoord = motePos.getYCoordinate(); + + if (motePos.getYCoordinate() > biggestYCoord) + biggestYCoord = motePos.getYCoordinate(); + + } + + if ((biggestXCoord - smallestXCoord) == 0) { + factorXCoordToPixel = 1; + } else + factorXCoordToPixel = ((double) canvas.getPreferredSize().width - 2 * CANVAS_BORDER_WIDTH) + / (biggestXCoord - smallestXCoord); + + if ((biggestYCoord - smallestYCoord) == 0) { + factorYCoordToPixel = 1; + } else + factorYCoordToPixel = ((double) canvas.getPreferredSize().height - 2 * CANVAS_BORDER_WIDTH) + / (biggestYCoord - smallestYCoord); + } + + /** + * Transforms a real-world position to a pixel which can be painted onto the + * current sized canvas. + * + * @param pos + * Real-world position + * @return Pixel coordinates + */ + public Point transformPositionToPixel(Position pos) { + return new Point(factorXCoordToPixel(pos.getXCoordinate()), + factorYCoordToPixel(pos.getYCoordinate())); + } + + /** + * Transforms real-world coordinates to a pixel which can be painted onto the + * current sized canvas. + * + * @param x Real world X + * @param y Real world Y + * @param z Real world Z (ignored) + * @return Pixel coordinates + */ + public Point transformPositionToPixel(double x, double y, double z) { + return new Point(factorXCoordToPixel(x), factorYCoordToPixel(y)); + } + + /** + * Transforms a pixel coordinate to a real-world. Z-value will always be 0. + * + * @param pixelPos + * On-screen pixel coordinate + * @return Real world coordinate (z=0). + */ + public Position transformPixelToPositon(Point pixelPos) { + Position dummyPosition = new Position(null); + dummyPosition.setCoordinates(factorXPixelToCoord(pixelPos.x), + factorYPixelToCoord(pixelPos.y), 0.0); + return dummyPosition; + } + + /** + * @return The current canvas to paint on + */ + public JPanel getCurrentCanvas() { + return canvas; + } + + private int factorXCoordToPixel(double xCoordinate) { + return (int) ((xCoordinate - smallestXCoord) * factorXCoordToPixel + CANVAS_BORDER_WIDTH); + } + private int factorYCoordToPixel(double yCoordinate) { + return (int) ((yCoordinate - smallestYCoord) * factorYCoordToPixel) + + CANVAS_BORDER_WIDTH; + } + private double factorXPixelToCoord(int xPixel) { + return ((double) (xPixel - CANVAS_BORDER_WIDTH) / factorXCoordToPixel) + + smallestXCoord; + } + private double factorYPixelToCoord(int yPixel) { + return ((double) (yPixel - CANVAS_BORDER_WIDTH) / factorYCoordToPixel) + + smallestYCoord; + } + + public void closePlugin() { + if (simObserver != null) { + simulation.deleteObserver(simObserver); + + for (int i = 0; i < simulation.getMotesCount(); i++) { + Position posIntf = simulation.getMote(i).getInterfaces().getPosition(); + if (posIntf != null) { + posIntf.deleteObserver(posObserver); + } + } + } + } + +} diff --git a/tools/cooja/java/se/sics/cooja/positioners/EllipsePositioner.java b/tools/cooja/java/se/sics/cooja/positioners/EllipsePositioner.java new file mode 100644 index 000000000..8b7ebbaf4 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/positioners/EllipsePositioner.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006, 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: EllipsePositioner.java,v 1.1 2006/08/21 12:13:11 fros4943 Exp $ + */ + +package se.sics.cooja.positioners; +import se.sics.cooja.*; + +/** + * Generates positions in a ellipse in the XY plane. + * (z position will always be start value of interval) + * + * @author Fredrik Osterlind + */ +@ClassDescription("Ellipse positioning") +public class EllipsePositioner extends Positioner { + + private double xRadius, yRadius, xMiddle, yMiddle; + private double zValue, deltaAngle, currentAngle; + + /** + * Creates a circle positioner. + * @param totalNumberOfMotes Total number of motes + * @param startX X interval start + * @param endX X interval end + * @param startY Y interval start + * @param endY Y interval end + * @param startZ Z interval start + * @param endZ Z interval end + */ + public EllipsePositioner(int totalNumberOfMotes, + double startX, double endX, + double startY, double endY, + double startZ, double endZ) { + xRadius = (endX - startX) / 2.0; + yRadius = (endY - startY) / 2.0; + xMiddle = startX + xRadius; + yMiddle = startY + yRadius; + zValue = startZ; + deltaAngle = 2*Math.PI / (double) totalNumberOfMotes; + currentAngle = 0; + } + + public double[] getNextPosition() { + currentAngle += deltaAngle; + return new double[] { + xMiddle + xRadius * Math.cos(currentAngle), + yMiddle + yRadius * Math.sin(currentAngle), + zValue}; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/positioners/LinearPositioner.java b/tools/cooja/java/se/sics/cooja/positioners/LinearPositioner.java new file mode 100644 index 000000000..e8dc7de74 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/positioners/LinearPositioner.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006, 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: LinearPositioner.java,v 1.1 2006/08/21 12:13:11 fros4943 Exp $ + */ + +package se.sics.cooja.positioners; +import se.sics.cooja.*; + +/** + * Generates positions linearly distributed in a given interval. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Linear positioning") +public class LinearPositioner extends Positioner { + + private double startX, startY, startZ; + private int addedInX, addedInY, addedInZ; + private int numberInX, numberInY, numberInZ; + private double xInterval, yInterval, zInterval; + + /** + * Creates a linear positioner. + * + * @param totalNumberOfMotes Total number of motes + * @param startX X interval start + * @param endX X interval end + * @param startY Y interval start + * @param endY Y interval end + * @param startZ Z interval start + * @param endZ Z interval end + */ + public LinearPositioner(int totalNumberOfMotes, + double startX, double endX, + double startY, double endY, + double startZ, double endZ) { + + this.startX = startX; + this.startY = startY; + this.startZ = startZ; + + double widthX = endX - startX; + double widthY = endY - startY; + double widthZ = endZ - startZ; + + if (widthX == 0) { + widthX = -1; + } + if (widthY == 0) { + widthY = -1; + } + if (widthZ == 0) { + widthZ = -1; + } + + double totalSpace = Math.abs(widthX * widthY * widthZ); + double spaceOfEachMote = totalSpace / (double) totalNumberOfMotes; + + int noDimensions = 0; + if (widthX > 0) + noDimensions++; + if (widthY > 0) + noDimensions++; + if (widthZ > 0) + noDimensions++; + + double sideLengthOfEachMote = Math.pow(spaceOfEachMote, 1.0/(double) noDimensions); + + this.numberInX = 0; + this.numberInY = 0; + this.numberInZ = 0; + + if (widthX > 0) + numberInX = (int) (widthX / sideLengthOfEachMote); + + if (widthY > 0) + numberInY = (int) (widthY / sideLengthOfEachMote); + + if (widthZ > 0) + numberInZ = (int) (widthZ / sideLengthOfEachMote); + + this.xInterval = widthX / numberInX; + this.yInterval = widthY / numberInY; + this.zInterval = widthZ / numberInZ; + + if (numberInX == 0) + xInterval = 0.0; + + if (numberInY == 0) + yInterval = 0.0; + + if (numberInZ == 0) + zInterval = 0.0; + + this.addedInX = 0; + this.addedInY = 0; + this.addedInZ = 0; + } + + public double[] getNextPosition() { + double[] newPosition = new double[] { + startX + addedInX*xInterval, + startY + addedInY*yInterval, + startZ + addedInZ*zInterval + }; + + addedInZ++; + + if (addedInZ >= numberInZ) { + addedInY++; + addedInZ = 0; + } + + if (addedInY >= numberInY) { + addedInX++; + addedInY = 0; + } + + return newPosition; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/positioners/RandomPositioner.java b/tools/cooja/java/se/sics/cooja/positioners/RandomPositioner.java new file mode 100644 index 000000000..f40403e5e --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/positioners/RandomPositioner.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006, 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: RandomPositioner.java,v 1.1 2006/08/21 12:13:11 fros4943 Exp $ + */ + +package se.sics.cooja.positioners; +import se.sics.cooja.*; + +/** + * Generates positions randomly distributed in a given interval. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Random positioning") +public class RandomPositioner extends Positioner { + double startX, endX, startY, endY, startZ, endZ; + + /** + * Creates a random positioner. + * @param totalNumberOfMotes Total number of motes + * @param startX X interval start + * @param endX X interval end + * @param startY Y interval start + * @param endY Y interval end + * @param startZ Z interval start + * @param endZ Z interval end + */ + public RandomPositioner(int totalNumberOfMotes, + double startX, double endX, + double startY, double endY, + double startZ, double endZ) { + this.startX = startX; + this.endX = endX; + this.startY = startY; + this.endY = endY; + this.startZ = startZ; + this.endZ = endZ; + } + + public double[] getNextPosition() { + return new double[] { + startX + Math.random()*(endX - startX), + startY + Math.random()*(endY - startY), + startZ + Math.random()*(endZ - startZ) + }; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java new file mode 100644 index 000000000..a4b6f577d --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/radiomediums/SilentRadioMedium.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2006, 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: SilentRadioMedium.java,v 1.1 2006/08/21 12:13:14 fros4943 Exp $ + */ + +package se.sics.cooja.radiomediums; +import java.util.Collection; +import java.util.Observer; + +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.*; + +/** + * Silent radio. No data is ever transferred through this medium. + * + * @author Fredrik Osterlind + */ +@ClassDescription("Silent Radio") +public class SilentRadioMedium extends RadioMedium { + + public void registerMote(Mote mote, Simulation sim) { + // Do nothing + } + + public void unregisterMote(Mote mote, Simulation sim) { + // Do nothing + } + + public void registerRadioInterface(Radio radio, Position position, Simulation sim) { + // Do nothing + } + + public void unregisterRadioInterface(Radio radio, Simulation sim) { + // Do nothing + } + + public void addRadioMediumObserver(Observer observer) { + // Do nothing + } + + public void deleteRadioMediumObserver(Observer observer) { + // Do nothing + } + + public RadioConnection[] getLastTickConnections() { + return null; + } + + public void setConnectionLogger(ConnectionLogger connection) { + // Do nothing + } + + public Collection getConfigXML() { + return null; + } + + public boolean setConfigXML(Collection configXML) { + return true; + } + +} diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/StandardRadioMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/StandardRadioMedium.java new file mode 100644 index 000000000..3d142efb3 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/radiomediums/StandardRadioMedium.java @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2006, 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: StandardRadioMedium.java,v 1.1 2006/08/21 12:13:13 fros4943 Exp $ + */ + +package se.sics.cooja.radiomediums; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.event.*; +import org.jdom.Element; +import org.apache.log4j.Logger; + +import se.sics.cooja.*; +import se.sics.cooja.interfaces.*; +import se.sics.cooja.plugins.Visualizer2D; + +/** + * Standard radio medium has two different range parameters; one for + * transmitting and one for interfering other transmissions. + * + * Radio data are analysed when all registered motes have ticked once (this + * medium is registered as a tick observer). For every mote in transmission + * range of a sending mote, current listen status is changed from hearing + * nothing to hearing packet, or hearing packet to hearing noise. This way, if a + * mote hears two packets during one tick loop, it will receive none (noise). If + * a mote is in the interference range, the current listen status will be set to + * hears noise immediately. + * + * This radio medium registers a dynamic visual plugin: Radio Medium - Standard. + * Via this plugin ranges can be viewed and changed. Active connection may also + * be viewed. + * + * + * @author Fredrik Osterlind + */ +@ClassDescription("Standard Radio") +public class StandardRadioMedium extends RadioMedium { + private static Logger logger = Logger.getLogger(StandardRadioMedium.class); + + private Vector registeredPositions = new Vector(); + private Vector registeredRadios = new Vector(); + + private Vector sendingPositions = new Vector(); + private Vector sendingRadios = new Vector(); + + private static RadioMedium myRadioMedium; + + /** + * Visualizes radio traffic in the current radio medium. Allows a user to + * change transmission ranges. + * + * Sending motes are blue, receiving motes are green and motes that hear noise + * are painted red. Motes without radios are painted gray, and the rest are + * white. + * + * @author Fredrik Osterlind + */ + @ClassDescription("Radio Medium - Standard") + @VisPluginType(VisPluginType.SIM_PLUGIN) + public static class RadioMediumSimPlugin extends Visualizer2D { + private Mote selectedMote = null; + + private JSpinner transmissionSpinner = null; + private JSpinner interferenceSpinner = null; + + private Observer radioMediumObserver; + + private class ChangeRangesMenuAction implements MoteMenuAction { + public boolean isEnabled(Mote mote) { + return true; + } + public String getDescription(Mote mote) { + return "Change transmission ranges"; + } + public void doAction(Mote mote) { + transmissionSpinner.setVisible(true); + interferenceSpinner.setVisible(true); + repaint(); + } + }; + + public RadioMediumSimPlugin(Simulation sim) { + super(sim); + setTitle("Radio Medium - Standard"); + + // Create spinners for changing ranges + SpinnerNumberModel transmissionModel = new SpinnerNumberModel(); + transmissionModel.setValue(new Double(TRANSMITTING_RANGE)); + transmissionModel.setStepSize(new Double(1.0)); // 1m + transmissionModel.setMinimum(new Double(0.0)); + + SpinnerNumberModel interferenceModel = new SpinnerNumberModel(); + interferenceModel.setValue(new Double(INTERFERENCE_RANGE)); + interferenceModel.setStepSize(new Double(1.0)); // 1m + interferenceModel.setMinimum(new Double(0.0)); + + transmissionSpinner = new JSpinner(transmissionModel); + interferenceSpinner = new JSpinner(interferenceModel); + + ((JSpinner.DefaultEditor) transmissionSpinner.getEditor()).getTextField() + .setColumns(5); + ((JSpinner.DefaultEditor) interferenceSpinner.getEditor()).getTextField() + .setColumns(5); + transmissionSpinner.setToolTipText("Transmitting range"); + interferenceSpinner.setToolTipText("Interference range"); + + transmissionSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + TRANSMITTING_RANGE = ((SpinnerNumberModel) transmissionSpinner + .getModel()).getNumber().doubleValue(); + repaint(); + } + }); + + interferenceSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + INTERFERENCE_RANGE = ((SpinnerNumberModel) interferenceSpinner + .getModel()).getNumber().doubleValue(); + repaint(); + } + }); + + getCurrentCanvas().add(transmissionSpinner); + getCurrentCanvas().add(interferenceSpinner); + transmissionSpinner.setVisible(false); + interferenceSpinner.setVisible(false); + + // Add mouse listener for selecting motes + getCurrentCanvas().addMouseListener(new MouseListener() { + public void mouseExited(MouseEvent e) { + // Do nothing + } + public void mouseEntered(MouseEvent e) { + // Do nothing + } + public void mouseReleased(MouseEvent e) { + // Do nothing + } + public void mousePressed(MouseEvent e) { + Vector clickedMotes = findMotesAtPosition(e.getX(), e.getY()); + if (clickedMotes == null || clickedMotes.size() == 0) { + selectedMote = null; + transmissionSpinner.setVisible(false); + interferenceSpinner.setVisible(false); + repaint(); + return; + } + + // Select one of the clicked motes + if (clickedMotes.contains(selectedMote)) { + int pos = clickedMotes.indexOf(selectedMote); + if (pos < clickedMotes.size() - 1) + selectedMote = clickedMotes.get(pos + 1); + else + selectedMote = clickedMotes.firstElement(); + } else { + selectedMote = clickedMotes.firstElement(); + } + repaint(); + } + public void mouseClicked(MouseEvent e) { + } + }); + + // Register change ranges action + addMoteMenuAction(new ChangeRangesMenuAction()); + + // Observe our own radio medium + myRadioMedium + .addRadioMediumObserver(radioMediumObserver = new Observer() { + public void update(Observable obs, Object obj) { + getCurrentCanvas().repaint(); + } + }); + + } + + public void closePlugin() { + super.closePlugin(); + + myRadioMedium.deleteRadioMediumObserver(radioMediumObserver); + } + + public Color[] getColorOf(Mote mote) { + Radio moteRadio = mote.getInterfaces().getRadio(); + if (moteRadio == null) + return new Color[]{Color.GRAY}; + + if (selectedMote != null && mote == selectedMote) + return new Color[]{Color.CYAN}; + + if (moteRadio.getSendState() == Radio.SENT_SOMETHING) + return new Color[]{Color.BLUE}; + + if (moteRadio.getListenState() == Radio.HEARS_PACKET) + return new Color[]{Color.GREEN}; + + if (moteRadio.getListenState() == Radio.HEARS_NOISE) + return new Color[]{Color.RED}; + + return new Color[]{Color.WHITE}; + } + + public void visualizeSimulation(Graphics g) { + + // Paint transmission+interference areas for selected mote (if any) + if (selectedMote != null) { + Position motePos = selectedMote.getInterfaces().getPosition(); + + Point pixelCoord = transformPositionToPixel(motePos); + int x = pixelCoord.x; + int y = pixelCoord.y; + + Point translatedZero = transformPositionToPixel(0.0, 0.0, 0.0); + Point translatedInterference = transformPositionToPixel( + INTERFERENCE_RANGE, INTERFERENCE_RANGE, 0.0); + Point translatedTransmission = transformPositionToPixel( + TRANSMITTING_RANGE, TRANSMITTING_RANGE, 0.0); + + translatedInterference.x = Math.abs(translatedInterference.x + - translatedZero.x); + translatedInterference.y = Math.abs(translatedInterference.y + - translatedZero.y); + translatedTransmission.x = Math.abs(translatedTransmission.x + - translatedZero.x); + translatedTransmission.y = Math.abs(translatedTransmission.y + - translatedZero.y); + + // Interference + g.setColor(Color.DARK_GRAY); + g.fillOval(x - translatedInterference.x, y - translatedInterference.y, + 2 * translatedInterference.x, 2 * translatedInterference.y); + + // Transmission + g.setColor(Color.GREEN); + g.fillOval(x - translatedTransmission.x, y - translatedTransmission.y, + 2 * translatedTransmission.x, 2 * translatedTransmission.y); + + } + + // Let parent paint motes + super.visualizeSimulation(g); + + // Paint last tick connections + if (myRadioMedium != null + && myRadioMedium.getLastTickConnections() != null) { + for (RadioConnection conn : myRadioMedium.getLastTickConnections()) { + if (conn != null) { + Point sourcePoint = transformPositionToPixel(conn + .getSourcePosition()); + + // Paint destinations + for (Position destPos : conn.getDestinationPositons()) { + Point destPoint = transformPositionToPixel(destPos); + + g.setColor(Color.BLACK); + g + .drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, + destPoint.y); + + } + } + } + } + } + } + + public StandardRadioMedium() { + // Register this radio medium's plugins + GUI.currentGUI.registerTemporaryPlugin(RadioMediumSimPlugin.class); + myRadioMedium = this; + } + + private boolean isTickObserver = false; + + private static double TRANSMITTING_RANGE = 20; // 20m + private static double INTERFERENCE_RANGE = 40; // 40m + + private static boolean RECEIVE_MY_OWN_PACKETS = false; + private static boolean DETECT_MY_OWN_PACKETS = true; + + private class RadioMediumObservable extends Observable { + private void transferredData() { + setChanged(); + notifyObservers(); + } + } + private RadioMediumObservable radioMediumObservable = new RadioMediumObservable(); + + private RadioConnection[] lastTickConnections = null; + + private ConnectionLogger myLogger = null; + + private Observer radioDataObserver = new Observer() { + public void update(Observable radio, Object obj) { + if (((Radio) radio).getSendState() == Radio.SENT_SOMETHING) { + if (!sendingPositions.contains((Position) obj)) { + sendingPositions.add((Position) obj); + sendingRadios.add((Radio) radio); + } + } + } + }; + + private Observer tickObserver = new Observer() { + public void update(Observable obs, Object obj) { + RadioConnection[] oldTickConnections = lastTickConnections; + lastTickConnections = null; + if (sendingPositions.size() > 0) { + final int numberSending = sendingPositions.size(); + lastTickConnections = new RadioConnection[numberSending]; + + // Loop through all sending radios + for (int sendNr = 0; sendNr < numberSending; sendNr++) { + Radio sendingRadio = sendingRadios.get(sendNr); + byte[] dataToSend = sendingRadio.getLastPacketSent(); + + lastTickConnections[sendNr] = new RadioConnection(); + lastTickConnections[sendNr].setSource(sendingRadios.get(sendNr), + sendingPositions.get(sendNr), dataToSend); + + // Set sending radio unable to receive any more data + if (RECEIVE_MY_OWN_PACKETS) { + sendingRadio.receivePacket(dataToSend); + sendingRadio.advanceListenState(); + } else if (DETECT_MY_OWN_PACKETS) { + sendingRadio.setListenState(Radio.HEARS_NOISE); + } + + // Loop through all radios that are listening + for (int listenNr = 0; listenNr < registeredPositions.size(); listenNr++) { + + // If not the sending radio.. + if (sendingRadios.get(sendNr) != registeredRadios.get(listenNr)) { + Radio listeningRadio = registeredRadios.get(listenNr); + + double distance = sendingPositions.get(sendNr).getDistanceTo( + registeredPositions.get(listenNr)); + + if (distance <= TRANSMITTING_RANGE) { + lastTickConnections[sendNr].addDestination(registeredRadios + .get(listenNr), registeredPositions.get(listenNr), + dataToSend); + + // If close enough to transmit ok.. + if (listeningRadio.getListenState() == Radio.HEARS_PACKET) { + // .. but listening radio already received a packet + listeningRadio.advanceListenState(); + } else if (listeningRadio.getListenState() == Radio.HEARS_NOISE) { + // .. but listening radio heard interference + listeningRadio.advanceListenState(); + } else { + // .. send packet + listeningRadio.receivePacket(dataToSend); + listeningRadio.setListenState(Radio.HEARS_PACKET); + } + } else if (distance <= INTERFERENCE_RANGE) { + // If close enough to sabotage other transmissions.. + if (listeningRadio.getListenState() == Radio.HEARS_PACKET) { + // .. and listening radio already received a packet + listeningRadio.advanceListenState(); + } else { + // .. and listening radio has done nothing sofar + listeningRadio.setListenState(Radio.HEARS_NOISE); + } + } + // else too far away + } + } + } + sendingPositions.clear(); + sendingRadios.clear(); + + if (myLogger != null) { + for (RadioConnection conn : lastTickConnections) + myLogger.logConnection(conn); + } + + } + if (lastTickConnections != oldTickConnections) + radioMediumObservable.transferredData(); + } + }; + + public void registerMote(Mote mote, Simulation sim) { + registerRadioInterface(mote.getInterfaces().getRadio(), mote + .getInterfaces().getPosition(), sim); + } + + public void unregisterMote(Mote mote, Simulation sim) { + unregisterRadioInterface(mote.getInterfaces().getRadio(), sim); + } + + public void registerRadioInterface(Radio radio, Position position, + Simulation sim) { + if (radio != null && position != null) { + if (!isTickObserver) { + sim.addTickObserver(tickObserver); + isTickObserver = true; + } + + registeredPositions.add(position); + registeredRadios.add(radio); + radio.addObserver(radioDataObserver); + } // else logger.warn("Standard Radio Medium not registering mote"); + } + + public void unregisterRadioInterface(Radio radio, Simulation sim) { + for (int i = 0; i < registeredRadios.size(); i++) { + if (registeredRadios.get(i).equals(radio)) { + registeredRadios.remove(i); + registeredPositions.remove(i); + radio.deleteObserver(radioDataObserver); + return; + } + } + logger.warn("Could not find radio: " + radio + " to unregister"); + } + + public void addRadioMediumObserver(Observer observer) { + radioMediumObservable.addObserver(observer); + } + + public void deleteRadioMediumObserver(Observer observer) { + radioMediumObservable.deleteObserver(observer); + } + + public RadioConnection[] getLastTickConnections() { + return lastTickConnections; + } + + public void setConnectionLogger(ConnectionLogger connection) { + myLogger = connection; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + Element element; + + // Transmitting range + element = new Element("transmitting_range"); + element.setText(Double.toString(TRANSMITTING_RANGE)); + config.add(element); + + // Interference range + element = new Element("interference_range"); + element.setText(Double.toString(INTERFERENCE_RANGE)); + config.add(element); + + return config; + } + + public boolean setConfigXML(Collection configXML) { + for (Element element : configXML) { + if (element.getName().equals("transmitting_range")) { + TRANSMITTING_RANGE = Double.parseDouble(element.getText()); + } + + if (element.getName().equals("interference_range")) { + INTERFERENCE_RANGE = Double.parseDouble(element.getText()); + } + } + return true; + } + +} diff --git a/tools/cooja/lib/jdom.jar b/tools/cooja/lib/jdom.jar new file mode 100644 index 000000000..c95de9206 Binary files /dev/null and b/tools/cooja/lib/jdom.jar differ diff --git a/tools/cooja/lib/log4j.jar b/tools/cooja/lib/log4j.jar new file mode 100644 index 000000000..1595a56ef Binary files /dev/null and b/tools/cooja/lib/log4j.jar differ