From c0bdeed635bc4dbddf75db8797eb1e7084336c17 Mon Sep 17 00:00:00 2001 From: fros4943 Date: Tue, 10 Mar 2009 21:10:06 +0000 Subject: [PATCH] rewrote contiki mote type to be more integrated with the contiki build system. example: instead of selecting and scanning for contiki processes, autostart processes are determined as on other platforms: via AUTOSTART() macro in the main contiki application not all functionality has been reimplemented yet --- .../cooja/contikimote/ContikiMoteType.java | 761 ++++++++---------- 1 file changed, 329 insertions(+), 432 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java index 6a3763dc3..6f5c40e64 100644 --- a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java +++ b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMoteType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Swedish Institute of Computer Science. + * Copyright (c) 2009, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ContikiMoteType.java,v 1.29 2009/03/03 13:45:32 fros4943 Exp $ + * $Id: ContikiMoteType.java,v 1.30 2009/03/10 21:10:06 fros4943 Exp $ */ package se.sics.cooja.contikimote; @@ -35,6 +35,7 @@ import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.io.*; +import java.lang.reflect.Method; import java.security.*; import java.util.*; import java.util.regex.*; @@ -43,16 +44,18 @@ import org.apache.log4j.Logger; import org.jdom.Element; import se.sics.cooja.*; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.ContikiMoteCompileDialog; import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; /** * 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 optional mote type specific project directories are located. + * This type also contains information about sensors and mote interfaces a mote + * of this type has. *

* 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 @@ -70,18 +73,20 @@ import se.sics.cooja.dialogs.MessageList; public class ContikiMoteType implements MoteType { private static Logger logger = Logger.getLogger(ContikiMoteType.class); + public static final String ID_PREFIX = "mtype"; + + /** + * Library file suffix + */ + final static public String librarySuffix = ".cooja"; + /** * Map file suffix */ final static public String mapSuffix = ".map"; /** - * Library file suffix - */ - final static public String librarySuffix = ".library"; - - /** - * Make dependency file suffix + * Make archive file suffix */ final static public String dependSuffix = ".a"; @@ -138,40 +143,35 @@ public class ContikiMoteType implements MoteType { } } - // Mote type specific data + private final String[] sensors = { "button_sensor", "pir_sensor", "radio_sensor", "vib_sensor" }; + private String identifier = null; - private String description = null; + private File fileSource = null; + private File fileFirmware = null; + private String compileCommands = null; - private String contikiBaseDir = null; + /* For internal use only: using during Contiki compilation. */ + private File contikiApp = null; /* Contiki application: hello-world.c */ + public File libSource = null; /* JNI library: obj_cooja/mtype1.c */ + public File libFile = null; /* JNI library: obj_cooja/mtype1.lib */ + public File archiveFile = null; /* Contiki archive: obj_cooja/mtype1.a */ + public File mapFile = null; /* Contiki map: obj_cooja/mtype1.map */ + public String javaClassName = null; /* Loading Java class name: Lib1 */ - private String contikiCoreDir = null; + private String[] coreInterfaces = null; - private Vector projectDirs = null; - - private Vector compilationFiles = null; - - private Vector processes = null; - - private Vector sensors = null; - - private Vector coreInterfaces = null; - - private Vector> moteInterfaces = null; + private ArrayList> moteInterfacesClasses = null; private boolean hasSystemSymbols = false; private CommunicationStack commStack = CommunicationStack.RIME; - // Simulation holding this mote type - private Simulation mySimulation = null; + private Simulation simulation = null; // Type specific class configuration private ProjectConfig myConfig = null; - // Core communication variables - private String libraryClassName = null; - private int relAddressOfRefenceVariable = 0; private CoreComm myCoreComm = null; @@ -189,147 +189,180 @@ public class ContikiMoteType implements MoteType { public ContikiMoteType() { } - /** - * Creates a new Contiki mote type. - * - * @param identifier - * Unique identifier for this mote type - */ - public ContikiMoteType(String identifier) throws MoteTypeCreationException { - doInit(identifier); - } - public Mote generateMote(Simulation simulation) { return new ContikiMote(this, simulation); } public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) throws MoteTypeCreationException { + myConfig = simulation.getGUI().getProjectConfig().clone(); + if (visAvailable) { - return ContikiMoteTypeDialog.showDialog(parentContainer, simulation, this); + + if (getDescription() == null) { + setDescription("Contiki Mote Type #" + (simulation.getMoteTypes().length+1)); + } + + /* Compile Contiki from dialog */ + boolean compileOK = + ContikiMoteCompileDialog.showDialog(parentContainer, simulation, this); + if (!compileOK) { + return false; + } + + /* Load compiled library */ + doInit(); + return true; + } else { - - /* Automatically clean if not visualized */ - if (!GUI.isVisualized()) { - ContikiMoteTypeDialog.cleanTempFiles(); + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier specified"); + } + if (getContikiSourceFile() == null) { + throw new MoteTypeCreationException("No Contiki application specified"); } - // Create temp output directory if not already exists - if (!ContikiMoteType.tempOutputDirectory.exists()) { - ContikiMoteType.tempOutputDirectory.mkdir(); - } - if (!ContikiMoteType.tempOutputDirectory.exists()) { - throw new MoteTypeCreationException( - "Could not create output directory: " - + ContikiMoteType.tempOutputDirectory); + /* Create variables used for compiling Contiki */ + contikiApp = getContikiSourceFile(); + libSource = new File( + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + ".c"); + libFile = new File( + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + librarySuffix); + archiveFile = new File( + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + dependSuffix); + mapFile = new File( + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + mapSuffix); + javaClassName = CoreComm.getAvailableClassName(); + + if (javaClassName == null) { + throw new MoteTypeCreationException("Could not allocate a core communicator!"); } - // Delete output files - File libFile = new File(ContikiMoteType.tempOutputDirectory, identifier - + ContikiMoteType.librarySuffix); - File mapFile = new File(ContikiMoteType.tempOutputDirectory, identifier - + ContikiMoteType.mapSuffix); - File depFile = new File(ContikiMoteType.tempOutputDirectory, identifier - + ContikiMoteType.dependSuffix); - if (libFile.exists()) { - libFile.delete(); - } - if (depFile.exists()) { - depFile.delete(); - } - if (mapFile.exists()) { - mapFile.delete(); - } - if (libFile.exists()) { - throw new MoteTypeCreationException("Could not delete output file: " - + libFile); - } - if (depFile.exists()) { - throw new MoteTypeCreationException("Could not delete output file: " - + depFile); - } + /* Delete output files */ + libSource.delete(); + libFile.delete(); + archiveFile.delete(); + mapFile.delete(); - // Generate Contiki main source file + /* Generate Contiki main source */ try { - ContikiMoteTypeDialog.generateSourceFile(identifier, sensors, - coreInterfaces, processes); + CompileContiki.generateSourceFile( + libSource, + javaClassName, + getSensors(), + getCoreInterfaces() + ); } catch (Exception e) { throw (MoteTypeCreationException) new MoteTypeCreationException( - "Error during main source file generation: " + e.getMessage()) - .initCause(e); + "Error when generating Contiki main source").initCause(e); } - // Compile library - MessageList taskOutput = new MessageList(); - boolean compilationSucceded = ContikiMoteTypeDialog.compileLibrary( - identifier, new File(contikiBaseDir), compilationFiles, - hasSystemSymbols, commStack, taskOutput - .getInputStream(MessageList.NORMAL), taskOutput - .getInputStream(MessageList.ERROR)); - if (!libFile.exists()) { - MoteTypeCreationException ex = new MoteTypeCreationException( - "Compilation error: " + libFile.getPath() + " does not exist"); - ex.setCompilationOutput(taskOutput); - throw ex; + /* Prepare compiler environment */ + String[][] env; + try { + env = CompileContiki.createCompilationEnvironment( + getIdentifier(), contikiApp, mapFile, libFile, archiveFile); + } catch (Exception e) { + throw (MoteTypeCreationException) new MoteTypeCreationException( + "Error when creating environment: " + e.getMessage()).initCause(e); } - if (!depFile.exists()) { - MoteTypeCreationException ex = new MoteTypeCreationException( - "Compilation error: " + depFile.getPath() + " does not exist"); - ex.setCompilationOutput(taskOutput); - throw ex; + String[] envOneDimension = new String[env.length]; + for (int i=0; i < env.length; i++) { + envOneDimension[i] = env[i][0] + "=" + env[i][1]; } - if (!compilationSucceded) { - MoteTypeCreationException ex = new MoteTypeCreationException( - "Compilation error: Unknown error"); - ex.setCompilationOutput(taskOutput); - throw ex; + /* Compile Contiki (may consist of several commands) */ + if (getCompileCommands() == null) { + throw new MoteTypeCreationException("No compile commands specified"); + } + final MessageList compilationOutput = new MessageList(); + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + envOneDimension, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } } - // Load compiled library - doInit(identifier); + /* Make sure compiled firmware exists */ + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + /* Load compiled library */ + doInit(); return true; } } + public static File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + librarySuffix); + } + /** - * 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. + * For internal use. * - * This method allocates a core communicator, loads the Contiki library file, - * loads and parses library addresses, creates a variable name to address - * mapping of the Contiki system and finally creates the Contiki mote initial - * memory. + * This method creates a core communicator linking a Contiki library and a Java class. + * It furthermore parses library Contiki memory addresses and creates the initial memory. * - * @param identifier - * Mote type identifier + * @throws MoteTypeCreationException */ - protected void doInit(String identifier) throws MoteTypeCreationException { - this.identifier = identifier; + public void doInit() throws MoteTypeCreationException { if (myCoreComm != null) { - throw new MoteTypeCreationException("Core communicator already used: " - + myCoreComm.getClass().getName()); + throw new MoteTypeCreationException( + "Core communicator already used: " + myCoreComm.getClass().getName()); } - File libFile = new File(ContikiMoteType.tempOutputDirectory, identifier - + librarySuffix); - File mapFile = new File(ContikiMoteType.tempOutputDirectory, identifier - + mapSuffix); + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Library file could not be found: " + getContikiFirmwareFile()); + } - // Check that library file exists - if (!libFile.exists()) { - throw new MoteTypeCreationException("Library file could not be found: " - + libFile); + if (this.javaClassName == null) { + throw new MoteTypeCreationException("Unknown Java class library: " + this.javaClassName); } // Allocate core communicator class - libraryClassName = CoreComm.getAvailableClassName(); - myCoreComm = CoreComm.createCoreComm(libraryClassName, libFile); + logger.info("Creating core communicator between Java class '" + javaClassName + "' and Contiki library '" + getContikiFirmwareFile().getName() + "'"); + myCoreComm = CoreComm.createCoreComm(this.javaClassName, getContikiFirmwareFile()); // Should we parse addresses using map file or command? boolean useCommand = Boolean.parseBoolean(GUI.getExternalToolsSetting("PARSE_WITH_COMMAND", "false")); @@ -341,10 +374,10 @@ public class ContikiMoteType implements MoteType { if (useCommand) { // Parse command output - Vector commandData = loadCommandData(libFile); + Vector commandData = loadCommandData(getContikiFirmwareFile()); if (commandData == null) { logger.fatal("No parse command output could be loaded"); - throw new MoteTypeCreationException("No parse command output be loaded"); + throw new MoteTypeCreationException("No parse command output loaded"); } boolean parseOK = parseCommandData(commandData, varAddresses); @@ -359,7 +392,8 @@ public class ContikiMoteType implements MoteType { bssSectionSize = loadCommandBssSectionSize(commandData); } else { // Parse map file - if (!mapFile.exists()) { + if (mapFile == null || + !mapFile.exists()) { logger.fatal("Map file " + mapFile.getAbsolutePath() + " could not be found!"); throw new MoteTypeCreationException("Map file " + mapFile.getAbsolutePath() + " could not be found!"); } @@ -385,7 +419,7 @@ public class ContikiMoteType implements MoteType { // Create variable names to addresses mappings if (varAddresses.size() == 0) { throw new MoteTypeCreationException( - "Variable name to addresses mappings could not be created"); + "Variable name to addresses mappings could not be created"); } try { @@ -399,7 +433,7 @@ public class ContikiMoteType implements MoteType { if (relDataSectionAddr <= 0 || dataSectionSize <= 0 || relBssSectionAddr <= 0 || bssSectionSize <= 0) { throw new MoteTypeCreationException( - "Could not parse section addresses correctly"); + "Could not parse section addresses correctly"); } myCoreComm.setReferenceAddress(relAddressOfRefenceVariable); @@ -519,14 +553,14 @@ public class ContikiMoteType implements MoteType { } } - if (nrMismatch > 0) { + /*if (nrMismatch > 0) { logger.debug("Command response parsing summary: Added " + nrNew + " variables. Found " + nrOld + " old variables. Mismatching addresses: " + nrMismatch); } else { logger.debug("Command response parsing summary: Added " + nrNew + " variables. Found " + nrOld + " old variables"); - } + }*/ return (nrNew + nrOld) > 0; } @@ -553,15 +587,38 @@ public class ContikiMoteType implements MoteType { } public void setIdentifier(String identifier) { - logger.warn("Contiki mote type is read-only"); + this.identifier = identifier; + } + + public File getContikiSourceFile() { + return fileSource; + } + + public void setContikiSourceFile(File file) { + fileSource = file; + } + + public File getContikiFirmwareFile() { + return fileFirmware; + } + + public void setContikiFirmwareFile(File file) { + fileFirmware = file; + } + + public String getCompileCommands() { + return compileCommands; + } + + public void setCompileCommands(String commands) { + this.compileCommands = commands; } /** - * @param using - * Core library has system symbols information + * @param symbols Core library has system symbols information */ - public void setHasSystemSymbols(boolean using) { - hasSystemSymbols = using; + public void setHasSystemSymbols(boolean symbols) { + hasSystemSymbols = symbols; } /** @@ -572,8 +629,7 @@ public class ContikiMoteType implements MoteType { } /** - * @param commStack - * Communication stack + * @param commStack Communication stack */ public void setCommunicationStack(CommunicationStack commStack) { this.commStack = commStack; @@ -586,13 +642,6 @@ public class ContikiMoteType implements MoteType { return commStack; } - /** - * @return Contiki mote type's library class name - */ - public String getLibraryClassName() { - return libraryClassName; - } - /** * Get relative address of variable with given name. * @@ -609,7 +658,7 @@ public class ContikiMoteType implements MoteType { } String regExp = GUI.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_1") - + varName + GUI.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); + + varName + GUI.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); String retString = getFirstMatchGroup(mapFileData, regExp, 1); if (retString != null) { @@ -633,7 +682,7 @@ public class ContikiMoteType implements MoteType { int groupNr) { Pattern pattern = Pattern.compile(regexp); for (int i = 0; i < lines.size(); i++) { - Matcher matcher = pattern.matcher(lines.elementAt(i)); + Matcher matcher = pattern.matcher(lines.get(i)); if (matcher.find()) { return matcher.group(groupNr); } @@ -656,7 +705,7 @@ public class ContikiMoteType implements MoteType { varNames.addAll(getAllVariableNames(mapFileData, loadRelBssSectionAddr(mapFileData), loadRelBssSectionAddr(mapFileData) - + loadBssSectionSize(mapFileData))); + + loadBssSectionSize(mapFileData))); return varNames; } @@ -668,7 +717,7 @@ public class ContikiMoteType implements MoteType { Pattern pattern = Pattern.compile(GUI .getExternalToolsSetting("MAPFILE_VAR_NAME")); for (int i = 0; i < lines.size(); i++) { - Matcher matcher = pattern.matcher(lines.elementAt(i)); + Matcher matcher = pattern.matcher(lines.get(i)); if (matcher.find()) { if (Integer.decode(matcher.group(1)).intValue() >= startAddress && Integer.decode(matcher.group(1)).intValue() <= endAddress) { @@ -684,7 +733,7 @@ public class ContikiMoteType implements MoteType { .getExternalToolsSetting("MAPFILE_VAR_SIZE_1") + varName + GUI.getExternalToolsSetting("MAPFILE_VAR_SIZE_2")); for (int i = 0; i < lines.size(); i++) { - Matcher matcher = pattern.matcher(lines.elementAt(i)); + Matcher matcher = pattern.matcher(lines.get(i)); if (matcher.find()) { return Integer.decode(matcher.group(1)); } @@ -806,7 +855,7 @@ public class ContikiMoteType implements MoteType { private static int getRelVarAddr(Vector mapFileData, String varName) { String regExp = GUI.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_1") - + varName + GUI.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); + + varName + GUI.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); String retString = getFirstMatchGroup(mapFileData, regExp, 1); if (retString != null) { @@ -855,12 +904,11 @@ public class ContikiMoteType implements MoteType { } // Prepare command - command = command.replace("$(LIBFILE)", libraryFile.getPath().replace(File.separatorChar, '/')); + command = command.replace("$(LIBFILE)", libraryFile.getName().replace(File.separatorChar, '/')); String line; - Process p = Runtime.getRuntime().exec(command.split(" ")); - BufferedReader input = new BufferedReader(new InputStreamReader(p - .getInputStream())); + Process p = Runtime.getRuntime().exec(command.split(" "), null, libraryFile.getParentFile()); + BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); p.getErrorStream().close(); // Ignore error stream while ((line = input.readLine()) != null) { commandData.add(line); @@ -905,7 +953,7 @@ public class ContikiMoteType implements MoteType { objdumpExecArray[0] = objdumpPath.trim(); objdumpExecArray[objdumpExecArray.length - 1] = libraryFile - .getAbsolutePath(); + .getAbsolutePath(); System.arraycopy(splittedObjdumpArgs, 0, objdumpExecArray, 1, splittedObjdumpArgs.length); } else { @@ -935,25 +983,6 @@ public class ContikiMoteType implements MoteType { return objdumpData; } - /** - * 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; } @@ -962,82 +991,6 @@ public class ContikiMoteType implements MoteType { 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 compilation files - * - * @return Compilation files - */ - public Vector getCompilationFiles() { - return compilationFiles; - } - - /** - * Sets compilation files. - * - * @param files - * New compilation files - */ - public void setCompilationFiles(Vector files) { - compilationFiles = files; - } - - /** - * Returns mote type specific project directories - * - * @return Project directories - */ - public Vector getProjectDirs() { - return projectDirs; - } - - /** - * Sets mote type specific project directories. - * - * @param dirs - * New project directories - */ - public void setProjectDirs(Vector dirs) { - projectDirs = dirs; - } - public ProjectConfig getConfig() { return myConfig; } @@ -1053,50 +1006,21 @@ public class ContikiMoteType implements MoteType { 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() { + public String[] 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() { + public String[] getCoreInterfaces() { return coreInterfaces; } @@ -1106,28 +1030,24 @@ public class ContikiMoteType implements MoteType { * @param coreInterfaces * New core interfaces */ - public void setCoreInterfaces(Vector coreInterfaces) { + public void setCoreInterfaces(String[] coreInterfaces) { this.coreInterfaces = coreInterfaces; } - /** - * Returns all mote interfaces of this mote type - * - * @return All mote interfaces - */ - public Vector> getMoteInterfaces() { - return moteInterfaces; + public Class[] getMoteInterfaceClasses() { + if (moteInterfacesClasses == null) { + return null; + } + Class[] arr = new Class[moteInterfacesClasses.size()]; + moteInterfacesClasses.toArray(arr); + return arr; } - /** - * Set mote interfaces of this mote type - * - * @param moteInterfaces - * New mote interfaces - */ - public void setMoteInterfaces( - Vector> moteInterfaces) { - this.moteInterfaces = moteInterfaces; + public void setMoteInterfaceClasses(Class[] moteInterfaces) { + this.moteInterfacesClasses = new ArrayList>(); + for (Class intf: moteInterfaces) { + this.moteInterfacesClasses.add(intf); + } } /** @@ -1169,14 +1089,14 @@ public class ContikiMoteType implements MoteType { * @param reservedIdentifiers Already reserved identifiers, may be null * @return Unique mote type ID. */ - public static String generateUniqueMoteTypeID(Collection existingTypes, Collection reservedIdentifiers) { + public static String generateUniqueMoteTypeID(MoteType[] existingTypes, Collection reservedIdentifiers) { int counter = 0; String testID = ""; boolean okID = false; while (!okID) { counter++; - testID = ContikiMoteTypeDialog.ID_PREFIX + counter; + testID = ID_PREFIX + counter; okID = true; // Check if identifier is reserved @@ -1203,7 +1123,9 @@ public class ContikiMoteType implements MoteType { } // Check if identifier library has been loaded - File libraryFile = new File(ContikiMoteType.tempOutputDirectory, testID + ContikiMoteType.librarySuffix); + File libraryFile = new File( + ContikiMoteType.tempOutputDirectory, + testID + ContikiMoteType.librarySuffix); if (CoreComm.hasLibraryFileBeenLoaded(libraryFile)) { okID = false; } @@ -1224,7 +1146,7 @@ public class ContikiMoteType implements MoteType { panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - // Identifier + /* Identifier */ smallPane = new JPanel(new BorderLayout()); label = new JLabel("Identifier"); smallPane.add(BorderLayout.WEST, label); @@ -1232,7 +1154,7 @@ public class ContikiMoteType implements MoteType { smallPane.add(BorderLayout.EAST, label); panel.add(smallPane); - // Description + /* Description */ smallPane = new JPanel(new BorderLayout()); label = new JLabel("Description"); smallPane.add(BorderLayout.WEST, label); @@ -1240,36 +1162,35 @@ public class ContikiMoteType implements MoteType { smallPane.add(BorderLayout.EAST, label); panel.add(smallPane); - // Contiki dir + /* Contiki application */ smallPane = new JPanel(new BorderLayout()); - label = new JLabel("Contiki path"); + label = new JLabel("Contiki application"); smallPane.add(BorderLayout.WEST, label); - label = new JLabel(contikiBaseDir); + label = new JLabel(getContikiSourceFile().getName()); + label.setToolTipText(getContikiSourceFile().getAbsolutePath()); smallPane.add(BorderLayout.EAST, label); panel.add(smallPane); - // Library class name + panel.add(Box.createVerticalStrut(15)); + + /* Contiki firmware */ smallPane = new JPanel(new BorderLayout()); - label = new JLabel("JNI Class"); + label = new JLabel("Contiki firmware"); smallPane.add(BorderLayout.WEST, label); - label = new JLabel(libraryClassName); + label = new JLabel(getContikiFirmwareFile().getName()); + label.setToolTipText(getContikiFirmwareFile().getAbsolutePath()); smallPane.add(BorderLayout.EAST, label); panel.add(smallPane); - // Processes + /* JNI Class */ smallPane = new JPanel(new BorderLayout()); - label = new JLabel("Processes"); + label = new JLabel("Java class (JNI)"); smallPane.add(BorderLayout.WEST, label); + label = new JLabel(this.javaClassName); + smallPane.add(BorderLayout.EAST, 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 + /* Sensors */ smallPane = new JPanel(new BorderLayout()); label = new JLabel("Sensors"); smallPane.add(BorderLayout.WEST, label); @@ -1282,28 +1203,28 @@ public class ContikiMoteType implements MoteType { 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 + /* Mote Interfaces */ smallPane = new JPanel(new BorderLayout()); label = new JLabel("Mote interfaces"); smallPane.add(BorderLayout.WEST, label); panel.add(smallPane); - for (Class moteInterface : moteInterfaces) { + for (Class intf : moteInterfacesClasses) { smallPane = new JPanel(new BorderLayout()); - label = new JLabel(moteInterface.getSimpleName()); + label = new JLabel(intf.getSimpleName()); + 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 intf : getCoreInterfaces()) { + smallPane = new JPanel(new BorderLayout()); + label = new JLabel(intf); smallPane.add(BorderLayout.EAST, label); panel.add(smallPane); } @@ -1314,79 +1235,36 @@ public class ContikiMoteType implements MoteType { 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()); + element = new Element("contikiapp"); + element.setText(getContikiSourceFile().getAbsolutePath()); /* TODO Fix Contiki-relative path */ config.add(element); - // Contiki core directory - element = new Element("contikicoredir"); - element.setText(getContikiCoreDir()); + element = new Element("commands"); + element.setText(compileCommands); config.add(element); - // User project directory - for (File projectDir : projectDirs) { - element = new Element("projectdir"); - element.setText(projectDir.getPath().replace('\\', '/')); - config.add(element); - } - - // Compilation files - for (File compileFile : compilationFiles) { - element = new Element("compilefile"); - element.setText(compileFile.getPath().replace('\\', '/')); - 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()) { + for (Class moteInterface : getMoteInterfaceClasses()) { 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); - } - - // Has system symbols element = new Element("symbols"); - element.setText(new Boolean(hasSystemSymbols).toString()); + element.setText(new Boolean(hasSystemSymbols()).toString()); config.add(element); - // Communication stack element = new Element("commstack"); - element.setText(commStack.toString()); + element.setText(getCommunicationStack().toString()); config.add(element); return config; @@ -1394,14 +1272,9 @@ public class ContikiMoteType implements MoteType { public boolean setConfigXML(Simulation simulation, Collection configXML, boolean visAvailable) - throws MoteTypeCreationException { - projectDirs = new Vector(); - compilationFiles = new Vector(); - processes = new Vector(); - sensors = new Vector(); - coreInterfaces = new Vector(); - moteInterfaces = new Vector>(); - mySimulation = simulation; + throws MoteTypeCreationException { + moteInterfacesClasses = new ArrayList>(); + this.simulation = simulation; for (Element element : configXML) { String name = element.getName(); @@ -1410,54 +1283,78 @@ public class ContikiMoteType implements MoteType { 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("projectdir")) { - projectDirs.add(new File(element.getText())); - } else if (name.equals("compilefile")) { - compilationFiles.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("contikiapp")) { + setContikiSourceFile(new File(element.getText())); /* TODO Fix Contiki-relative paths */ + + /* XXX Do not load the generated firmware. Instead, load the unique library file directly */ + File contikiFirmware = new File( + getContikiSourceFile().getParentFile(), + "obj_cooja/" + getIdentifier() + librarySuffix); + setContikiFirmwareFile(contikiFirmware); + + } else if (name.equals("commands")) { + compileCommands = element.getText(); } else if (name.equals("symbols")) { hasSystemSymbols = Boolean.parseBoolean(element.getText()); } else if (name.equals("commstack")) { commStack = CommunicationStack.parse(element.getText()); - } else if (name.equals("coreinterface")) { - coreInterfaces.add(element.getText()); } else if (name.equals("moteinterface")) { - Class moteInterfaceClass = simulation.getGUI() - .tryLoadClass(this, MoteInterface.class, element.getText().trim()); + Class moteInterfaceClass = + simulation.getGUI().tryLoadClass( + this, MoteInterface.class, element.getText().trim()); if (moteInterfaceClass == null) { logger.warn("Can't find mote interface class: " + element.getText()); } else { - moteInterfaces.add(moteInterfaceClass); + moteInterfacesClasses.add(moteInterfaceClass); } } else { logger.fatal("Unrecognized entry in loaded configuration: " + name); } } - // Create class specific configuration - myConfig = simulation.getGUI().getProjectConfig().clone(); + /* Create initial core interface dependencies */ + Class[] arr = + new Class[moteInterfacesClasses.size()]; + moteInterfacesClasses.toArray(arr); + setCoreInterfaces(ContikiMoteType.getRequiredCoreInterfaces(arr)); - // Merge with all project directory configs (if any) - for (File projectDir : projectDirs) { - try { - myConfig.appendProjectDir(projectDir); - } catch (Exception ex) { - logger.fatal("Error when parsing project directory config: " + ex); - return false; - } - } - - mySimulation = simulation; boolean createdOK = configureAndInit(GUI.getTopParentContainer(), simulation, visAvailable); return createdOK; } + public static String[] getRequiredCoreInterfaces( + Class[] moteInterfaces) { + /* Extract Contiki dependencies from currently selected mote interfaces */ + ArrayList coreInterfacesList = new ArrayList(); + for (Class intf: moteInterfaces) { + if (!ContikiMoteInterface.class.isAssignableFrom(intf)) { + continue; + } + + String[] deps; + try { + /* Call static method */ + Method m = intf.getDeclaredMethod("getCoreInterfaceDependencies", (Class[]) null); + deps = (String[]) m.invoke(null, (Object[]) null); + } catch (Exception e) { + logger.warn("Could not extract Contiki dependencies of mote interface: " + intf.getName()); + e.printStackTrace(); + continue; + } + + if (deps == null || deps.length == 0) { + continue; + } + + for (String dep: deps) { + coreInterfacesList.add(dep); + } + } + + String[] coreInterfaces = new String[coreInterfacesList.size()]; + coreInterfacesList.toArray(coreInterfaces); + return coreInterfaces; + } + }