From 660167b39baed9b71a5f45b96aec5547fed20966 Mon Sep 17 00:00:00 2001 From: fros4943 Date: Fri, 20 Feb 2009 16:50:16 +0000 Subject: [PATCH] added configuration wizard to replace the jni_tests --- tools/cooja/java/se/sics/cooja/GUI.java | 14 +- .../cooja/dialogs/ConfigurationWizard.java | 1009 +++++++++++++++++ 2 files changed, 1022 insertions(+), 1 deletion(-) create mode 100644 tools/cooja/java/se/sics/cooja/dialogs/ConfigurationWizard.java diff --git a/tools/cooja/java/se/sics/cooja/GUI.java b/tools/cooja/java/se/sics/cooja/GUI.java index 87d152eb5..c0d2afa5a 100644 --- a/tools/cooja/java/se/sics/cooja/GUI.java +++ b/tools/cooja/java/se/sics/cooja/GUI.java @@ -24,7 +24,7 @@ * (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.105 2009/02/18 17:25:14 fros4943 Exp $ + * $Id: GUI.java,v 1.106 2009/02/20 16:50:16 fros4943 Exp $ */ package se.sics.cooja; @@ -118,6 +118,7 @@ import se.sics.cooja.contikimote.ContikiMoteType; import se.sics.cooja.contikimote.ContikiMoteTypeDialog; import se.sics.cooja.contikimote.ContikiProcess; import se.sics.cooja.dialogs.AddMoteDialog; +import se.sics.cooja.dialogs.ConfigurationWizard; import se.sics.cooja.dialogs.CreateSimDialog; import se.sics.cooja.dialogs.ExternalToolsDialog; import se.sics.cooja.dialogs.MessageList; @@ -839,6 +840,15 @@ public class GUI extends Observable { menuItem.setToolTipText("Not available in applet version"); } + menuItem = new JMenuItem("Compiler configuration wizard"); + menuItem.setActionCommand("configuration wizard"); + menuItem.addActionListener(guiEventHandler); + menu.add(menuItem); + if (isVisualizedInApplet()) { + menuItem.setEnabled(false); + menuItem.setToolTipText("Not available in applet version"); + } + menu.addSeparator(); menuItem = new JMenuItem("Java version: " @@ -2956,6 +2966,8 @@ public class GUI extends Observable { return; } } + } else if (e.getActionCommand().equals("configuration wizard")) { + ConfigurationWizard.startWizard(GUI.getTopParentContainer(), GUI.this); } else if (e.getActionCommand().equals("start plugin")) { Class pluginClass = (Class) ((JMenuItem) e.getSource()).getClientProperty("class"); diff --git a/tools/cooja/java/se/sics/cooja/dialogs/ConfigurationWizard.java b/tools/cooja/java/se/sics/cooja/dialogs/ConfigurationWizard.java new file mode 100644 index 000000000..0032e90ba --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/ConfigurationWizard.java @@ -0,0 +1,1009 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: ConfigurationWizard.java,v 1.1 2009/02/20 16:51:25 fros4943 Exp $ + */ + +package se.sics.cooja.dialogs; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.util.Properties; +import java.util.Vector; +import javax.swing.*; +import se.sics.cooja.CoreComm; +import se.sics.cooja.GUI; +import se.sics.cooja.SectionMoteMemory; +import se.sics.cooja.MoteType.MoteTypeCreationException; +import se.sics.cooja.contikimote.ContikiMoteType; +import se.sics.cooja.contikimote.ContikiMoteTypeDialog; + +public class ConfigurationWizard extends JDialog { + private static final long serialVersionUID = 1L; + + private static final String COMPILER_ARGS_suggestions[] = new String[] { + "-mno-cygwin -Wall -I'$(JAVA_HOME)/include' -I'$(JAVA_HOME)/include/win32' -fno-builtin-printf", + "-mno-cygwin -Wall -I'$(JAVA_HOME)/include' -I'$(JAVA_HOME)/include/win32'", + "-Wall -D_JNI_IMPLEMENTATION_ -I'$(JAVA_HOME)/include' -I'$(JAVA_HOME)/include/win32'", + "-mno-cygwin -I'$(JAVA_HOME)/include' -I'$(JAVA_HOME)/include/win32'", + "-I'$(JAVA_HOME)/include' -I'$(JAVA_HOME)/include/linux' -fno-builtin-printf -fPIC", + "", + "-Wall -I/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Headers -dynamiclib -fno-common" + }; + + private static final String LINK_COMMAND_1_suggestions[] = new String[] { + "gcc -mno-cygwin -shared -Wl,-Map=$(MAPFILE) -Wl,--add-stdcall-alias -o $(LIBFILE)", + "gcc -shared -Wl,-Map=$(MAPFILE) -o $(LIBFILE)", + "gcc -I'$(JAVA_HOME)/include' -I'$(JAVA_HOME)/include/linux' -shared -Wl,-Map=$(MAPFILE) -o $(LIBFILE)", + "ld -Map=$(MAPFILE) -shared --add-stdcall-alias /usr/lib/mingw/dllcrt2.o -o $(LIBFILE)", + "gcc -shared -Wl,-Map=$(MAPFILE) -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -o $(LIBFILE)", + "gcc -dynamiclib -fno-common -o $(LIBFILE)" + }; + + private static final String LINK_COMMAND_2_suggestions[] = new String[] { + "", + "-L/usr/lib/mingw -lmsvcrt", + "-L/usr/lib/mingw -lmingw32 -lmingwex -lmsvcrt", + "-framework JavaVM" + }; + + private static final String PARSE_WITH_COMMAND_suggestions[] = new String[] { + "true", + "false" + }; + + private static final String AR_COMMAND_1_suggestions[] = new String[] { + "ar rcf $(ARFILE)", + "ar rc $(ARFILE)" + }; + + private static final String PARSE_COMMAND_suggestions[] = new String[] { + "nm -C $(LIBFILE)", + "nm -a $(LIBFILE)", + "nmandsize $(LIBFILE)" + }; + + private static final String OPTION_RUN_TEST = "Run test"; + private static final String OPTION_NEXT_TEST = "Next test"; + private static final String OPTION_CLOSE_WIZARD = "Close Wizard"; + + private static final String testTemplate = "test_template.c"; + + private static int testCounter = 0; + + private static String cLibraryName; + private static File cLibrarySourceFile; + private static File cLibraryFile; + private static String javaLibraryName; + private static CoreComm javaLibrary; + private static Properties addresses; + private static int relDataSectionAddr; + private static int dataSectionSize; + private static int relBssSectionAddr; + private static int bssSectionSize; + + private static MessageList output; + private static JDialog progressDialog; + private static JButton button; + private static JProgressBar progressBar; + + public static boolean startWizard(Container parentContainer, GUI gui) { + if (GUI.isVisualizedInApplet()) { + return false; + } + + /* Initial info message */ + if (!showWizardInfo(parentContainer, gui)) { + return false; + } + + /* Test 1 - Compile and link C source */ + if (!doCompileCTest((JFrame)parentContainer, gui)) { + return false; + } + + /* Test 2 - Load Java library */ + if (!doLoadLibraryTest((JFrame)parentContainer, gui)) { + return false; + } + + /* Test 3 - Address parsing */ + if (!doAddressParsingTest((JFrame)parentContainer, gui)) { + return false; + } + + /* Test 4 - Memory replacement */ + if (!doMemoryReplacementTest((JFrame)parentContainer, gui)) { + return false; + } + + return true; + } + + public static boolean showWizardInfo(Container parent, GUI gui) { + String options[] = {"Start tests", OPTION_CLOSE_WIZARD}; + int value = JOptionPane.showOptionDialog(parent, + "This wizard configures and tests your toolchain for simulating Contiki motes in COOJA.\n" + + "Throughout the wizard, Contiki libraries are compiled and loaded while allowing you to \n" + + "alter external tools settings such as compiler arguments.\n" + + "\n" + + "Changes made in this wizard are reflected in menu Settings, External tools paths.\n", + "Configuration Wizard", + JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, + null, options, options[0]); + + if (value != JOptionPane.YES_OPTION) { + return false; + } + + return true; + } + + public static boolean doCompileCTest(JFrame parent, GUI gui) { + final String testDescription = "Step 1/4 - Compile and link Contiki library"; + String value = OPTION_RUN_TEST; + while (value.equals(OPTION_RUN_TEST)) { + value = showStepDialog( + parent, + "Generates, compiles and links a COOJA/Contiki stub.\n", + testDescription, + new String[] { + "COMPILER_ARGS", "LINK_COMMAND_1", "LINK_COMMAND_2", "AR_COMMAND_1", "AR_COMMAND_2" + }, + true + ); + + if (value == null) { + return false; + } + + if (value.equals(OPTION_NEXT_TEST)) { + return true; + } + + if (!value.equals(OPTION_RUN_TEST)) { + return false; + } + + prepareShowTestProgress(parent, testDescription); + + /* Start test */ + new Thread(new Runnable() { + public void run() { + testCounter++; + PrintStream normalStream = new PrintStream(output.getInputStream(MessageList.NORMAL)); + PrintStream errorStream = new PrintStream(output.getInputStream(MessageList.ERROR)); + boolean success = performCompileCTest(output, normalStream, errorStream); + normalStream.close(); + errorStream.close(); + + if (success) { + output.addMessage("### Test OK", MessageList.NORMAL); + } else { + output.addMessage("### Test failed", MessageList.ERROR); + } + button.setEnabled(true); + progressBar.setIndeterminate(false); + } + }).start(); + + showTestProgress(parent); + } + + return false; + } + + public static boolean doLoadLibraryTest(JFrame parent, GUI gui) { + final String testDescription = "Step 2/4 - Load Contiki library in Java"; + String value = OPTION_RUN_TEST; + while (value.equals(OPTION_RUN_TEST)) { + value = showStepDialog( + parent, + "Generates, compiles and loads a CoreComm Java class.\n" + + "A CoreComm instance loads the Contiki library created in step 2.\n", + testDescription, + new String[] { + "PATH_JAVAC" + }, + true + ); + + if (value == null) { + return false; + } + + if (value.equals(OPTION_NEXT_TEST)) { + return true; + } + + if (!value.equals(OPTION_RUN_TEST)) { + return false; + } + + prepareShowTestProgress(parent, testDescription); + + /* Start test */ + new Thread(new Runnable() { + public void run() { + testCounter++; + PrintStream normalStream = new PrintStream(output.getInputStream(MessageList.NORMAL)); + PrintStream errorStream = new PrintStream(output.getInputStream(MessageList.ERROR)); + boolean success = performLoadTest(output, normalStream, errorStream); + normalStream.close(); + errorStream.close(); + + if (success) { + output.addMessage("### Test OK", MessageList.NORMAL); + } else { + output.addMessage("### Test failed", MessageList.ERROR); + } + button.setEnabled(true); + progressBar.setIndeterminate(false); + } + }).start(); + + showTestProgress(parent); + } + + return false; + } + + public static boolean doAddressParsingTest(JFrame parent, GUI gui) { + final String testDescription = "Step 3/4 - Library memory addresses"; + String value = OPTION_RUN_TEST; + while (value.equals(OPTION_RUN_TEST)) { + value = showStepDialog( + parent, + "Tests parsing memory addresses of a loaded Contiki library.\n" + + "Addresses can be parsed using either a map file, or with the nm tool.\n" + + "Both approaches are tested.\n", + testDescription, + new String[] { + "PARSE_WITH_COMMAND", "PARSE_COMMAND" + }, + true + ); + + if (value == null) { + return false; + } + + if (value.equals(OPTION_NEXT_TEST)) { + return true; + } + + if (!value.equals(OPTION_RUN_TEST)) { + return false; + } + + prepareShowTestProgress(parent, testDescription); + + /* Start test */ + new Thread(new Runnable() { + public void run() { + testCounter++; + PrintStream normalStream = new PrintStream(output.getInputStream(MessageList.NORMAL)); + PrintStream errorStream = new PrintStream(output.getInputStream(MessageList.ERROR)); + boolean success = performAddressTest(output, normalStream, errorStream); + normalStream.close(); + errorStream.close(); + + if (success) { + output.addMessage("### Test OK", MessageList.NORMAL); + } else { + output.addMessage("### Test failed", MessageList.ERROR); + } + button.setEnabled(true); + progressBar.setIndeterminate(false); + } + }).start(); + + showTestProgress(parent); + } + + return false; + } + + public static boolean doMemoryReplacementTest(JFrame parent, GUI gui) { + final String testDescription = "Step 4/4 - Memory replacement test"; + String value = OPTION_RUN_TEST; + while (value.equals(OPTION_RUN_TEST)) { + value = showStepDialog( + parent, + "Tests copying memory sections between Contiki and COOJA.\n" + + "Variable values are both altered in Contiki and in COOJA.\n" + + "\n" + + "This is the final test!\n", + testDescription, + null, + false + ); + + if (value == null) { + return false; + } + + if (value.equals(OPTION_NEXT_TEST)) { + return true; + } + + if (!value.equals(OPTION_RUN_TEST)) { + return false; + } + + prepareShowTestProgress(parent, testDescription); + + /* Start test */ + new Thread(new Runnable() { + public void run() { + testCounter++; + PrintStream normalStream = new PrintStream(output.getInputStream(MessageList.NORMAL)); + PrintStream errorStream = new PrintStream(output.getInputStream(MessageList.ERROR)); + boolean success = performMemoryReplacementTest(output, normalStream, errorStream); + normalStream.close(); + errorStream.close(); + + if (success) { + output.addMessage("### Test OK", MessageList.NORMAL); + } else { + output.addMessage("### Test failed", MessageList.ERROR); + } + button.setEnabled(true); + progressBar.setIndeterminate(false); + } + }).start(); + + showTestProgress(parent); + } + + return false; + } + + private static void prepareShowTestProgress(JFrame parent, String desc) { + output = new MessageList(); + progressDialog = new JDialog(parent, desc); + button = new JButton("Close"); + progressBar = new JProgressBar(0, 100); + } + + private static void showTestProgress(JFrame parent) { + progressBar.setValue(0); + progressBar.setStringPainted(false); + progressBar.setIndeterminate(true); + JPanel progressPanel = new JPanel(new BorderLayout()); + button.setEnabled(false); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (progressDialog.isDisplayable()) { + progressDialog.dispose(); + } + } + }); + progressPanel.add(BorderLayout.CENTER, new JScrollPane(output)); + progressPanel.add(BorderLayout.NORTH, progressBar); + progressPanel.add(BorderLayout.SOUTH, button); + progressDialog.getContentPane().add(progressPanel); + progressDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + progressDialog.setSize(700, 500); + progressDialog.setModal(true); + progressDialog.setLocationRelativeTo(parent); + progressDialog.getRootPane().setDefaultButton(button); + progressDialog.setVisible(true); + } + + private static JPanel createConfigureComboBox(final String name) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + JComboBox combo = new JComboBox(new Object[] { GUI.getExternalToolsSetting(name, "") }); + + JLabel label = new JLabel(name); + label.setToolTipText(name); + label.setPreferredSize(new Dimension(120, label.getPreferredSize().height)); + + /* Suggest external tools settings */ + String[] suggestions = null; + if (name.equals("COMPILER_ARGS")) { + suggestions = COMPILER_ARGS_suggestions; + } else if (name.equals("LINK_COMMAND_1")) { + suggestions = LINK_COMMAND_1_suggestions; + } else if (name.equals("LINK_COMMAND_2")) { + suggestions = LINK_COMMAND_2_suggestions; + } else if (name.equals("PARSE_WITH_COMMAN")) { + suggestions = PARSE_WITH_COMMAND_suggestions; + } else if (name.equals("AR_COMMAND_1")) { + suggestions = AR_COMMAND_1_suggestions; + } else if (name.equals("PARSE_COMMAND")) { + suggestions = PARSE_COMMAND_suggestions; + } + if (suggestions != null) { + for (String suggestion: suggestions) { + combo.addItem(suggestion); + } + } + combo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + GUI.setExternalToolsSetting(name, (String) e.getItem()); + } + }); + combo.setEditable(true); + combo.setPreferredSize(new Dimension(300, combo.getPreferredSize().height)); + + panel.add(label); + panel.add(Box.createHorizontalStrut(10)); + panel.add(combo); + return panel; + } + + private static String showStepDialog(JFrame parent, String desc, String title, String[] settings, boolean hasNext) { + + /* Create configurable settings panels (label+combobox) */ + JPanel settingsPanels[] = null; + if (settings != null && settings.length > 0) { + settingsPanels = new JPanel[settings.length]; + for (int i=0; i < settings.length; i++) { + settingsPanels[i] = createConfigureComboBox(settings[i]); + } + } + + /* Create dialog message */ + Object descAndSettings[] = { + desc + "\n", + settingsPanels + }; + JOptionPane optionPane = new JOptionPane(); + optionPane.setMessage(descAndSettings); + optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + + /* Create dialog options */ + String options[]; + if (hasNext) { + options = new String[] {OPTION_RUN_TEST, OPTION_NEXT_TEST, OPTION_CLOSE_WIZARD}; + } else { + options = new String[] {OPTION_RUN_TEST, OPTION_CLOSE_WIZARD}; + } + optionPane.setOptions(options); + optionPane.setInitialValue(options[0]); + + /* Show dialog */ + JDialog dialog = optionPane.createDialog(parent, title); + dialog.setVisible(true); + return (String) optionPane.getValue(); + } + + public static boolean performCompileCTest(MessageList testOutput, PrintStream normalStream, PrintStream errorStream) { + javaLibraryName = "LibTest" + testCounter; + cLibraryName = "libtest" + testCounter; + cLibrarySourceFile = new File(ContikiMoteType.tempOutputDirectory, cLibraryName + ".c"); + cLibraryFile = new File(ContikiMoteType.tempOutputDirectory, cLibraryName + ".library"); + + testOutput.addMessage("### Reading C library template source: " + testTemplate, MessageList.NORMAL); + BufferedReader templateReader = null; + try { + if ((new File(testTemplate)).exists()) { + templateReader = new BufferedReader(new FileReader(testTemplate)); + } else { + InputStream input = ContikiMoteTypeDialog.class.getResourceAsStream('/' + testTemplate); + if (input == null) { + throw new FileNotFoundException("File not found: " + testTemplate); + } + templateReader = new BufferedReader(new InputStreamReader(input)); + } + } catch (FileNotFoundException e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Generating C library source: " + cLibrarySourceFile.getName()); + if (!ContikiMoteType.tempOutputDirectory.exists()) { + ContikiMoteType.tempOutputDirectory.mkdir(); + } + if (cLibrarySourceFile.exists()) { + cLibrarySourceFile.delete(); + } + try { + cLibrarySourceFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + BufferedWriter cLibraryWriter = null; + try { + cLibraryWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(cLibrarySourceFile))); + String line; + while ((line = templateReader.readLine()) != null) { + line = line.replaceFirst("\\[CLASS_NAME\\]", javaLibraryName); + cLibraryWriter.write(line + "\n"); + } + cLibraryWriter.close(); + templateReader.close(); + } catch (IOException e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Compiling C library source: " + cLibrarySourceFile.getName()); + boolean compileOK = ContikiMoteTypeDialog.compileLibrary( + cLibraryName, + new File(GUI.getExternalToolsSetting("PATH_CONTIKI")), + new Vector(), + false, + ContikiMoteType.CommunicationStack.RIME, + normalStream, + errorStream + ); + if (!compileOK) { + testOutput.addMessage("### Error: Compilation failed", MessageList.ERROR); + return false; + } + + return true; + } + + public static boolean performLoadTest(MessageList testOutput, PrintStream normalStream, PrintStream errorStream) { + MessageList dummy = new MessageList(); + PrintStream dummyStream = dummy.getInputStream(MessageList.NORMAL); + if (!performCompileCTest(dummy, dummyStream, errorStream)) { + return false; + } + dummyStream.close(); + + testOutput.addMessage("### Generating Java library source: se/sics/cooja/corecomm/" + javaLibraryName + ".java"); + try { + CoreComm.generateLibSourceFile(javaLibraryName); + } catch (MoteTypeCreationException e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Compiling Java library source: se/sics/cooja/corecomm/" + javaLibraryName + ".java"); + try { + CoreComm.compileSourceFile(javaLibraryName); + } catch (MoteTypeCreationException e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Loading Java library class: se/sics/cooja/corecomm/" + javaLibraryName); + Class javaLibraryClass = null; + try { + javaLibraryClass = CoreComm.loadClassFile(javaLibraryName); + } catch (MoteTypeCreationException e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Creating Java library: se/sics/cooja/corecomm/" + javaLibraryName + " with argument: " + cLibraryFile); + javaLibrary = null; + try { + Constructor constr = javaLibraryClass.getConstructor(new Class[] { File.class }); + javaLibrary = constr.newInstance(new Object[] { cLibraryFile }); + } catch (Exception e) { + e.printStackTrace(errorStream); + testOutput.addMessage("### Error: " + e.getMessage(), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Calling native Contiki stub functions"); + javaLibrary.setReferenceAddress(0); + javaLibrary.getMemory(0, 0, new byte[]{}); + javaLibrary.setMemory(0, 0, new byte[]{}); + return true; + } + + public static boolean performAddressTest(MessageList testOutput, PrintStream normalStream, PrintStream errorStream) { + MessageList dummy = new MessageList(); + PrintStream dummyStream = dummy.getInputStream(MessageList.NORMAL); + if (!performCompileCTest(dummy, dummyStream, errorStream)) { + return false; + } + if (!performLoadTest(dummy, dummyStream, errorStream)) { + return false; + } + dummyStream.close(); + + boolean successMap = false; + boolean successCommand = false; + + successMap = performMapAddressTest(testOutput, normalStream, errorStream); + testOutput.addMessage(""); + successCommand = performCommandAddressTest(testOutput, normalStream, errorStream); + + boolean parseWithCommand = Boolean.parseBoolean(GUI.getExternalToolsSetting("PARSE_WITH_COMMAND", "false")); + + if (successMap && successCommand) { + testOutput.addMessage("### Both map file and command based address parsing succeeded"); + return true; + } + if (parseWithCommand) { + if (successCommand) { + testOutput.addMessage("### Command based address parsing succeeded"); + return true; + } + if (successMap) { + testOutput.addMessage("Map file based parsing succeded: use PARSE_WITH_COMMAND=false", MessageList.ERROR); + return false; + } + } + if (!parseWithCommand) { + if (successMap) { + testOutput.addMessage("### Map file based address parsing succeeded"); + return true; + } + if (successMap) { + testOutput.addMessage("Command based parsing succeded: use PARSE_WITH_COMMAND=true", MessageList.ERROR); + return false; + } + } + return false; + } + + private static boolean performMapAddressTest(MessageList testOutput, PrintStream normalStream, PrintStream errorStream) { + testOutput.addMessage("### Testing map file based address parsing"); + + File mapFile = new File(ContikiMoteType.tempOutputDirectory, cLibraryName + ContikiMoteType.mapSuffix); + + testOutput.addMessage("### Reading map file: " + mapFile); + if (!mapFile.exists()) { + testOutput.addMessage("### Error: Map file not found", MessageList.ERROR); + return false; + } + Vector mapData = ContikiMoteType.loadMapFile(mapFile); + if (mapData == null) { + testOutput.addMessage("### Error: Map file could not be read", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Parsing map file data for addresses"); + addresses = new Properties(); + boolean parseOK = ContikiMoteType.parseMapFileData(mapData, addresses); + if (!parseOK) { + testOutput.addMessage("### Error: Failed parsing map file data", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Validating section addresses"); + relDataSectionAddr = ContikiMoteType.loadRelDataSectionAddr(mapData); + dataSectionSize = ContikiMoteType.loadDataSectionSize(mapData); + relBssSectionAddr = ContikiMoteType.loadRelBssSectionAddr(mapData); + bssSectionSize = ContikiMoteType.loadBssSectionSize(mapData); + testOutput.addMessage("Data section address: 0x" + Integer.toHexString(relDataSectionAddr)); + testOutput.addMessage("Data section size: 0x" + Integer.toHexString(dataSectionSize)); + testOutput.addMessage("BSS section address: 0x" + Integer.toHexString(relBssSectionAddr)); + testOutput.addMessage("BSS section size: 0x" + Integer.toHexString(bssSectionSize)); + if (relDataSectionAddr < 0) { + testOutput.addMessage("Data section address < 0: 0x" + Integer.toHexString(relDataSectionAddr), MessageList.ERROR); + return false; + } + if (relBssSectionAddr < 0) { + testOutput.addMessage("BSS section address < 0: 0x" + Integer.toHexString(relBssSectionAddr), MessageList.ERROR); + return false; + } + if (dataSectionSize <= 0) { + testOutput.addMessage("Data section size <= 0: 0x" + Integer.toHexString(dataSectionSize), MessageList.ERROR); + return false; + } + if (bssSectionSize <= 0) { + testOutput.addMessage("BSS section size <= 0: 0x" + Integer.toHexString(bssSectionSize), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Looking for known Contiki variables"); + String varName; + varName = "var1"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "var2"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "arr1"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "arr2"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "uvar1"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "uvar2"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + + return true; + } + + private static boolean performCommandAddressTest(MessageList testOutput, PrintStream normalStream, PrintStream errorStream) { + testOutput.addMessage("### Testing command based address parsing"); + + testOutput.addMessage("### Executing command"); + Vector commandData = ContikiMoteType.loadCommandData(cLibraryFile); + if (commandData == null) { + testOutput.addMessage("### Error: Could not execute command", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Parsing command output for addresses"); + addresses = new Properties(); + boolean parseOK = ContikiMoteType.parseCommandData(commandData, addresses); + if (!parseOK) { + testOutput.addMessage("### Error: Failed parsing command output", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Validating section addresses"); + relDataSectionAddr = ContikiMoteType.loadCommandRelDataSectionAddr(commandData); + dataSectionSize = ContikiMoteType.loadCommandDataSectionSize(commandData); + relBssSectionAddr = ContikiMoteType.loadCommandRelBssSectionAddr(commandData); + bssSectionSize = ContikiMoteType.loadCommandBssSectionSize(commandData); + testOutput.addMessage("Data section address: 0x" + Integer.toHexString(relDataSectionAddr)); + testOutput.addMessage("Data section size: 0x" + Integer.toHexString(dataSectionSize)); + testOutput.addMessage("BSS section address: 0x" + Integer.toHexString(relBssSectionAddr)); + testOutput.addMessage("BSS section size: 0x" + Integer.toHexString(bssSectionSize)); + if (relDataSectionAddr < 0) { + testOutput.addMessage("Data section address < 0: 0x" + Integer.toHexString(relDataSectionAddr), MessageList.ERROR); + return false; + } + if (relBssSectionAddr < 0) { + testOutput.addMessage("BSS section address < 0: 0x" + Integer.toHexString(relBssSectionAddr), MessageList.ERROR); + return false; + } + if (dataSectionSize <= 0) { + testOutput.addMessage("Data section size <= 0: 0x" + Integer.toHexString(dataSectionSize), MessageList.ERROR); + return false; + } + if (bssSectionSize <= 0) { + testOutput.addMessage("BSS section size <= 0: 0x" + Integer.toHexString(bssSectionSize), MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Looking for known Contiki variables"); + String varName; + varName = "var1"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "var2"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "arr1"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "arr2"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "uvar1"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + varName = "uvar2"; + if (!addresses.containsKey(varName)) { + testOutput.addMessage("Could not find address of: " + varName, MessageList.ERROR); + return false; + } + + return true; + } + + + public static boolean performMemoryReplacementTest(MessageList testOutput, PrintStream normalStream, PrintStream errorStream) { + MessageList dummy = new MessageList(); + PrintStream dummyStream = dummy.getInputStream(MessageList.NORMAL); + if (!performCompileCTest(dummy, dummyStream, errorStream)) { + return false; + } + if (!performLoadTest(dummy, dummyStream, errorStream)) { + return false; + } + boolean parseWithCommand = Boolean.parseBoolean(GUI.getExternalToolsSetting("PARSE_WITH_COMMAND", "false")); + if (parseWithCommand) { + if (!performCommandAddressTest(dummy, dummyStream, errorStream)) { + return false; + } + } else { + if (!performMapAddressTest(dummy, dummyStream, errorStream)) { + return false; + } + } + dummyStream.close(); + + testOutput.addMessage("### Testing Contiki library memory replacement"); + + testOutput.addMessage("### Configuring Contiki using parsed reference address"); + int relRefAddress = (Integer) addresses.get("ref_var"); + if (!addresses.containsKey("ref_var")) { + testOutput.addMessage("Could not find address of ref_var", MessageList.ERROR); + return false; + } + javaLibrary.setReferenceAddress(relRefAddress); + + testOutput.addMessage("### Creating data and BSS memory sections"); + byte[] initialDataSection = new byte[dataSectionSize]; + byte[] initialBssSection = new byte[bssSectionSize]; + javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, initialDataSection); + javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); + SectionMoteMemory memory = new SectionMoteMemory(addresses); + memory.setMemorySegment(relDataSectionAddr, initialDataSection); + memory.setMemorySegment(relBssSectionAddr, initialBssSection); + + int contikiDataCounter, contikiBSSCounter; + + testOutput.addMessage("### Checking initial variable values: 1,0"); + contikiDataCounter = memory.getIntValueOf("var1"); + contikiBSSCounter = memory.getIntValueOf("uvar1"); + int javaDataCounter = 1; + int javaBSSCounter = 0; + if (contikiDataCounter != javaDataCounter) { + testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); + return false; + } + if (contikiBSSCounter != javaBSSCounter) { + testOutput.addMessage("### BSS section mismatch (" + contikiBSSCounter + " != " + javaBSSCounter + ")", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Increasing data and BSS counters 5 times: 6,5"); + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + + testOutput.addMessage("### Fetching memory, comparing counters"); + javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, initialDataSection); + javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); + memory.setMemorySegment(relDataSectionAddr, initialDataSection); + memory.setMemorySegment(relBssSectionAddr, initialBssSection); + contikiDataCounter = memory.getIntValueOf("var1"); + contikiBSSCounter = memory.getIntValueOf("uvar1"); + if (contikiDataCounter != javaDataCounter) { + testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); + return false; + } + if (contikiBSSCounter != javaBSSCounter) { + testOutput.addMessage("### BSS section mismatch (" + contikiBSSCounter + " != " + javaBSSCounter + ")", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Backup memory sections: 6,5"); + byte[] savedDataSection = new byte[dataSectionSize]; + byte[] savedBssSection = new byte[bssSectionSize]; + int backupDataCounter = contikiDataCounter; + int backupBssCounter = contikiBSSCounter; + javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, savedDataSection); + javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, savedBssSection); + + testOutput.addMessage("### Increasing data and BSS counters 3 times: 9,8"); + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + + testOutput.addMessage("### Fetching memory, comparing counters"); + javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, initialDataSection); + javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); + memory.setMemorySegment(relDataSectionAddr, initialDataSection); + memory.setMemorySegment(relBssSectionAddr, initialBssSection); + contikiDataCounter = memory.getIntValueOf("var1"); + contikiBSSCounter = memory.getIntValueOf("uvar1"); + if (contikiDataCounter != javaDataCounter) { + testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); + return false; + } + if (contikiBSSCounter != javaBSSCounter) { + testOutput.addMessage("### BSS section mismatch (" + contikiBSSCounter + " != " + javaBSSCounter + ")", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Restoring backup data section: 6,8"); + javaLibrary.setMemory(relDataSectionAddr, dataSectionSize, savedDataSection); + javaDataCounter = backupDataCounter; + + testOutput.addMessage("### Increasing data and BSS counters 3 times: 9,11"); + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + javaLibrary.tick(); javaDataCounter++; javaBSSCounter++; + + testOutput.addMessage("### Fetching memory, comparing counters"); + javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, initialDataSection); + javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); + memory.setMemorySegment(relDataSectionAddr, initialDataSection); + memory.setMemorySegment(relBssSectionAddr, initialBssSection); + contikiDataCounter = memory.getIntValueOf("var1"); + contikiBSSCounter = memory.getIntValueOf("uvar1"); + if (contikiDataCounter != javaDataCounter) { + testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); + return false; + } + if (contikiBSSCounter != javaBSSCounter) { + testOutput.addMessage("### BSS section mismatch (" + contikiBSSCounter + " != " + javaBSSCounter + ")", MessageList.ERROR); + return false; + } + + testOutput.addMessage("### Restoring backup BSS section: 9,5"); + javaLibrary.setMemory(relBssSectionAddr, bssSectionSize, savedBssSection); + javaBSSCounter = backupBssCounter; + + testOutput.addMessage("### Fetching memory, comparing counters"); + javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, initialDataSection); + javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); + memory.setMemorySegment(relDataSectionAddr, initialDataSection); + memory.setMemorySegment(relBssSectionAddr, initialBssSection); + contikiDataCounter = memory.getIntValueOf("var1"); + contikiBSSCounter = memory.getIntValueOf("uvar1"); + if (contikiDataCounter != javaDataCounter) { + testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); + return false; + } + if (contikiBSSCounter != javaBSSCounter) { + testOutput.addMessage("### BSS section mismatch (" + contikiBSSCounter + " != " + javaBSSCounter + ")", MessageList.ERROR); + return false; + } + + return true; + } + +}