From: Fredrik Ãs. <fro...@us...> - 2006-11-09 19:31:19
|
Update of /cvsroot/contiki/contiki-2.x/tools/cooja/java/se/sics/cooja/mantismote In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv2171/tools/cooja/java/se/sics/cooja/mantismote Added Files: MantisMoteTypeDialog.java MantisMote.java MantisMoteType.java Log Message: added test files for future support of mantis os. not working yet due to threading vs jni problems --- NEW FILE: MantisMoteTypeDialog.java --- /* * 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: MantisMoteTypeDialog.java,v 1.1 2006/11/09 19:31:14 fros4943 Exp $ */ package se.sics.cooja.mantismote; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; import org.apache.log4j.Logger; import se.sics.cooja.*; import se.sics.cooja.dialogs.MessageList; /** * A dialog for configuring Mantis mote types and compiling KMantis mote type * libraries. * * The dialog takes a Mantis 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 MantisMoteTypeDialog extends JDialog { private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(MantisMoteTypeDialog.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 MantisMoteType myMoteType = null; private JTextField textID, textOutputFiles, textDescription, textMantisBinary; private JButton createButton, compileButton; private File objFile = null; private File workingDir = null; private File libFile = null; private File srcFile = null; private Vector<Class<? extends MoteInterface>> moteInterfaceClasses = null; 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 Vector<MoteType> allOtherTypes = null; // Used to check for conflicting parameters private MantisMoteTypeDialog myDialog; /** * Shows a dialog for configuring a Mantis mote type. * * @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 mote type configuration succeded and library is ready to be loaded */ public static boolean showDialog(Frame parentFrame, Simulation simulation, MantisMoteType moteTypeToConfigure) { final MantisMoteTypeDialog myDialog = new MantisMoteTypeDialog( 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; } } } myDialog.textID.setText(testIdentifier); } // Set preset description of mote type if (moteTypeToConfigure.getDescription() != null) { myDialog.textDescription.setText(moteTypeToConfigure.getDescription()); } else { myDialog.textDescription.setText("mantis type, id=" + myDialog.textID.getText()); } // Set preset object file of mote type if (moteTypeToConfigure.getObjectFilename() != null) { myDialog.textMantisBinary.setText(moteTypeToConfigure.getObjectFilename()); } // Load all mote interface classes String[] moteInterfaces = GUI.currentGUI.getPlatformConfig().getStringArrayValue(MantisMoteType.class, "MOTE_INTERFACES"); myDialog.moteInterfaceClasses = new Vector<Class<? extends MoteInterface>>(); for (String moteInterface : moteInterfaces) { try { Class<? extends MoteInterface> newMoteInterfaceClass = GUI.currentGUI.tryLoadClass(GUI.currentGUI, MoteInterface.class, moteInterface); myDialog.moteInterfaceClasses.add(newMoteInterfaceClass); /*logger.info("Loaded Mantis mote interface: " + newMoteInterfaceClass);*/ } catch (Exception e) { logger.fatal("Failed to load mote interface, aborting: " + moteInterface + ", " + e.getMessage()); return false; } } // Set position and focus of dialog myDialog.pack(); myDialog.setLocationRelativeTo(parentFrame); myDialog.textDescription.requestFocus(); myDialog.textDescription.select(0, myDialog.textDescription.getText().length()); myDialog.pathsWereUpdated(); myDialog.setVisible(true); if (myDialog.myMoteType != null) { // Library was compiled and loaded return true; } return false; } private MantisMoteTypeDialog(Frame frame) { super(frame, "Configure Mantis Mote Type", true); myDialog = this; 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("Compile"); button.setActionCommand("compile"); button.addActionListener(myEventHandler); compileButton = button; this.getRootPane().setDefaultButton(button); buttonPane.add(button); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); buttonPane.add(Box.createHorizontalGlue()); button = new JButton("Clean"); 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(""); 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(""); 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))); // Mantis binary smallPane = new JPanel(); smallPane.setAlignmentX(Component.LEFT_ALIGNMENT); smallPane.setLayout(new BoxLayout(smallPane, BoxLayout.X_AXIS)); label = new JLabel("Mantis x86 object"); label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); textField = new JTextField(); textField.setText(""); textField.getDocument().addDocumentListener(myEventHandler); textMantisBinary = textField; label.setLabelFor(textField); button = new JButton("Browse"); button.setActionCommand("browsemantis"); 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))); mainPane.add(Box.createVerticalGlue()); // Add everything! mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); Container contentPane = getContentPane(); contentPane.add(mainPane, BorderLayout.NORTH); contentPane.add(buttonPane, BorderLayout.SOUTH); } /** * Tries to compile library using current settings. */ public void doCompileCurrentSettings() { 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.getRootPane().setDefaultButton(button); progressDialog.setVisible(true); // Generate main mantis source file try { // Remove old file is existing if (srcFile.exists()) { srcFile.delete(); } if (srcFile.exists()) { throw new Exception("could not remove old source file"); } generateSourceFile(srcFile); if (!srcFile.exists()) { throw new Exception("source file not created"); } } catch (Exception e) { libraryCreatedOK = false; progressBar.setBackground(Color.ORANGE); if (e.getMessage() != null) progressBar.setString("source file generation failed: " + e.getMessage()); else progressBar.setString("source file generation failed"); progressBar.setIndeterminate(false); progressBar.setValue(0); createButton.setEnabled(libraryCreatedOK); return; } // Test compile shared library progressBar.setString("..compiling.."); if (libFile.exists()) { libFile.delete(); } compilationThread = new Thread(new Runnable() { public void run() { compilationSucceded = MantisMoteTypeDialog.compileLibrary( libFile, objFile, srcFile, workingDir, taskOutput.getInputStream(MessageList.NORMAL), taskOutput.getInputStream(MessageList.ERROR)); } }, "compilation thread"); compilationThread.start(); while (compilationThread.isAlive()) { try { Thread.sleep(100); } catch (InterruptedException e) { // NOP } } if (!compilationSucceded) { if (libFile.exists()) { libFile.delete(); } libraryCreatedOK = false; } else { libraryCreatedOK = true; if (!libFile.exists()) libraryCreatedOK = false; } if (libraryCreatedOK) { progressBar.setBackground(Color.GREEN); progressBar.setString("compilation succeded"); button.grabFocus(); myDialog.getRootPane().setDefaultButton(createButton); } else { progressBar.setBackground(Color.ORANGE); progressBar.setString("compilation failed"); myDialog.getRootPane().setDefaultButton(compileButton); } progressBar.setIndeterminate(false); progressBar.setValue(0); createButton.setEnabled(libraryCreatedOK); } /** * Generates new source file by reading default source template and replacing * certain field in order to be loadable from given Java class. * * @param outputFile Source file to create * @throws Exception */ public static void generateSourceFile(File outputFile) throws Exception { // CHECK JNI CLASS AVAILABILITY String libString = CoreComm.getAvailableClassName(); if (libString == null) { logger.fatal("No more libraries can be loaded!"); throw new Exception("Maximum number of mote types already exist"); } // GENERATE NEW FILE BufferedWriter destFile = null; BufferedReader sourceFile = null; try { Reader reader; String mainTemplate = GUI .getExternalToolsSetting("MANTIS_MAIN_TEMPLATE_FILENAME"); if ((new File(mainTemplate)).exists()) { reader = new FileReader(mainTemplate); } else { InputStream input = MantisMoteTypeDialog.class .getResourceAsStream('/' + mainTemplate); if (input == null) { throw new FileNotFoundException(mainTemplate + " not found"); } reader = new InputStreamReader(input); } sourceFile = new BufferedReader(reader); destFile = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(outputFile))); // Replace fields in template String line; while ((line = sourceFile.readLine()) != null) { line = line.replaceFirst("\\[CLASS_NAME\\]", libString); destFile.write(line + "\n"); } destFile.close(); sourceFile.close(); } catch (Exception e) { try { if (destFile != null) destFile.close(); if (sourceFile != null) sourceFile.close(); } catch (Exception e2) { } // Forward exception throw e; } } /** * Compiles a mote type shared library using the standard Mantis makefile. * * @param libFile Library file to create * @param binFile Binary file to link against * @param sourceFile Source file to compile * @param workingDir Working directory * @param outputStream * Output stream from compilation (optional) * @param errorStream * Error stream from compilation (optional) * @return True if compilation succeeded, false otherwise */ public static boolean compileLibrary(File libFile, File binFile, File sourceFile, File workingDir, final PrintStream outputStream, final PrintStream errorStream) { // Check needed files if (!workingDir.exists()) { if (errorStream != null) errorStream.println("Bad paths"); logger.fatal("Working directory does not exist"); return false; } if (!workingDir.isDirectory()) { if (errorStream != null) errorStream.println("Bad paths"); logger.fatal("Working directory is not a directory"); return false; } if (libFile.exists()) { if (errorStream != null) errorStream.println("Bad output filenames"); logger.fatal("Library already exists"); return false; } if (!sourceFile.exists()) { if (errorStream != null) errorStream.println("Bad dependency files"); logger.fatal("Source file not found"); return false; } if (!binFile.exists()) { if (errorStream != null) errorStream.println("Bad dependency files"); logger.fatal("Link object file not found"); return false; } if (CoreComm.hasLibraryFileBeenLoaded(libFile)) { if (errorStream != null) errorStream.println("Bad output filenames"); logger.fatal("A library has already been loaded with the same name before"); return false; } try { // Call make file String[] cmd = new String[]{ GUI.getExternalToolsSetting("PATH_MAKE"), libFile.getName()}; String[] env = new String[]{ "COOJA_LINKFILE=" + binFile.getName(), "COOJA_SOURCE=" + sourceFile.getName(), "PATH=" + System.getenv("PATH")}; Process p = Runtime.getRuntime().exec(cmd, env, workingDir); 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 (outputStream != null && readLine != null) outputStream.println(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 (errorStream != null && readLine != null) errorStream.println(readLine); } } 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) { logger.fatal("Make file returned error: " + p.exitValue()); return false; } } catch (Exception e) { logger.fatal("Error while compiling library: " + e); return false; } return true; } private void pathsWereUpdated() { updateVisualFields(); } 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; } } // Check that binary exists textMantisBinary.setBackground(Color.WHITE); textMantisBinary.setToolTipText(null); objFile = new File(textMantisBinary.getText()); workingDir = objFile.getParentFile(); libFile = new File(workingDir, textID.getText() + ".library"); srcFile = new File(workingDir, textID.getText() + ".c"); // TODO Check that file is correct type (.o or something) if (objFile == null || !objFile.exists()) { textMantisBinary.setBackground(Color.RED); textMantisBinary.setToolTipText("Incorrect object file"); objFile = null; libFile = null; srcFile = null; workingDir = null; settingsOK = false; } // Update output text field if (settingsOK) { textOutputFiles.setText(libFile.getName() + ", " + srcFile.getName() + ", " + textID.getText() + ".o"); } else { textOutputFiles.setText(""); } createButton.setEnabled(libraryCreatedOK = false); compileButton.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 // TODO Not implemented logger.fatal("Clean functionality not implemented"); } else if (e.getActionCommand().equals("create")) { // Create mote type and set related fields boolean ret = myMoteType.doInit(libFile, objFile, moteInterfaceClasses); myMoteType.setDescription(textDescription.getText()); myMoteType.setIdentifier(textID.getText()); if (ret) { dispose(); } else { logger.fatal("Mote type creation failed."); } } else if (e.getActionCommand().equals("compile")) { compileButton.requestFocus(); Thread testSettingsThread = new Thread(new Runnable() { public void run() { doCompileCurrentSettings(); } }, "test settings thread"); testSettingsThread.start(); } else if (e.getActionCommand().equals("browsemantis")) { JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new java.io.File(".")); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setDialogTitle("Mantis binary to link against"); if (fc.showOpenDialog(myDialog) == JFileChooser.APPROVE_OPTION) { textMantisBinary.setText(fc.getSelectedFile().getPath()); } createButton.setEnabled(libraryCreatedOK = false); pathsWereUpdated(); } else logger.warn("Unhandled action: " + e.getActionCommand()); createButton.setEnabled(libraryCreatedOK = false); } } } --- NEW FILE: MantisMote.java --- /* * 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: MantisMote.java,v 1.1 2006/11/09 19:31:15 fros4943 Exp $ */ package se.sics.cooja.mantismote; import java.util.*; import org.apache.log4j.Logger; import org.jdom.Element; import se.sics.cooja.*; /** * A Mantis mote simulation works the same way as the native Contiki mote. The * Mantis OS is compiled and linked together with a JNI-enabled object file * generated from COOJA. * * Each tick the all interfaces are polled, the memory is copied and the tick is * forwarded to the core Mantis system. * * A Mantis mote is always active. * * @author Fredrik Osterlind */ public class MantisMote implements Mote { private static Logger logger = Logger.getLogger(MantisMote.class); private MantisMoteType myType = null; private SectionMoteMemory myMemory = null; private MoteInterfaceHandler myInterfaceHandler = null; private Simulation mySimulation = null; /** * Creates a new uninitialized Mantis mote. * * This mote needs at least a type, a memory, a mote interface handler and to * be connected to a simulation. */ public MantisMote() { } /** * 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 MantisMote(MantisMoteType moteType, Simulation sim) { this.mySimulation = sim; this.myType = moteType; this.myMemory = moteType.createInitialMemory(); this.myInterfaceHandler = new MoteInterfaceHandler((Mote) this, moteType .getMoteInterfaces()); } public void setState(State newState) { logger.fatal("Mantis motes can't change state"); } public State getState() { return 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 = (MantisMoteType) type; } public Simulation getSimulation() { return mySimulation; } public void setSimulation(Simulation simulation) { mySimulation = simulation; } public void tick(int simTime) { // Poll all interfaces before tick myInterfaceHandler.doActiveActionsBeforeTick(); myInterfaceHandler.doPassiveActionsBeforeTick(); // Copy memory to core myType.setCoreMemory(myMemory); // Tick node myType.tick(); // Fetch new updated memory from core myType.getCoreMemory(myMemory); // Poll all interfaces after tick myInterfaceHandler.doActiveActionsBeforeTick(); myInterfaceHandler.doPassiveActionsBeforeTick(); } public Collection<Element> getConfigXML() { Vector<Element> config = new Vector<Element>(); 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<Element> configXML) { mySimulation = simulation; for (Element element : configXML) { String name = element.getName(); if (name.equals("motetype_identifier")) { myType = (MantisMoteType) simulation.getMoteType(element.getText()); myMemory = myType.createInitialMemory(); myInterfaceHandler = new MoteInterfaceHandler((Mote) this, myType .getMoteInterfaces()); } else if (name.equals("interface_config")) { Class<? extends MoteInterface> 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); if (moteInterface != null) moteInterface.setConfigXML(element.getChildren()); else logger .warn("Can't restore configuration for non-existing interface: " + moteInterfaceClass.getName()); } } return true; } public String toString() { if (getInterfaces().getMoteID() != null) { return "Mantis Mote, ID=" + getInterfaces().getMoteID().getMoteID(); } else return "Mantis Mote, ID=null"; } } --- NEW FILE: MantisMoteType.java --- /* * 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: MantisMoteType.java,v 1.1 2006/11/09 19:31:15 fros4943 Exp $ */ package se.sics.cooja.mantismote; import java.awt.BorderLayout; import java.awt.Dimension; import java.io.File; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import org.apache.log4j.Logger; import org.jdom.Element; import se.sics.cooja.*; import se.sics.cooja.contikimote.ContikiMoteType; /** * The Mantis mote type holds the native library used to communicate with an * underlying Mantis system. All communication with that system should always * pass through this mote type. * <p> * All core communication with the Mantis mote should be via this class. When a * mote type is created it allocates a CoreComm to be used with this type. * <p> * When a new mote type is created an initialization function is run on the * Mantis 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("Mantis Mote Type") public class MantisMoteType implements MoteType { private static Logger logger = Logger.getLogger(MantisMoteType.class); private Simulation mySimulation = null; // Mote type specific information private String myIdentifier = null; private String myDescription = null; private String myObjectFilename = null; private SectionMoteMemory myInitialMemory = null; private Vector<Class<? extends MoteInterface>> moteInterfaceClasses = 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(); /** * Creates a new uninitialized Mantis mote type. This mote type's doInit * method must be called and succeed before it can be used. */ public MantisMoteType() { } /** * Creates a new initialized Mantis mote type. The given library file is * loaded by the first available CoreComm. Each mote generated from this mote * type will have the interfaces specified in the given mote interface class * list. * * @param libFile * Library file to load * @param objFile * Object file * @param moteInterfaceClasses * List of mote interfaces */ public MantisMoteType(File libFile, File objFile, Vector<Class<? extends MoteInterface>> moteInterfaceClasses) { if (!doInit(libFile, objFile, moteInterfaceClasses)) logger.fatal("Mantis mote type creation failed!"); } /** * 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 Mantis library file, * creates variable name to address mappings and finally creates the Mantis * mote initial memory. * * @param libFile Library file * @param objFile Object file * @param moteInterfaceClasses Mote interface classes * @return True if initialization ok, false otherwise */ protected boolean doInit(File libFile, File objFile, Vector<Class<? extends MoteInterface>> moteInterfaceClasses) { myObjectFilename = objFile.getAbsolutePath(); myIdentifier = libFile.getName(); myDescription = libFile.getAbsolutePath(); // Allocate core communicator class libraryClassName = CoreComm.getAvailableClassName(); myCoreComm = CoreComm.createCoreComm(libraryClassName, libFile); // Parse variable name to addresses mappings using nm varAddresses.clear(); Vector<String> nmData = ContikiMoteType.loadNmData(libFile); if (nmData == null || !ContikiMoteType.parseNmData(nmData, varAddresses)) { logger.fatal("Nm response parsing failed"); return false; } // TODO Bug. Both sections sizes must be > 0! // Parse section offsets and sizes using objdump Vector<String> objdumpData = ContikiMoteType.loadObjdumpData(libFile); int relDataSectionAddr = -1; int dataSectionSize = -1; int relBssSectionAddr = -1; int bssSectionSize = -1; String dataRegExp = "^[ \t]*[0-9]*[ \t]*.data[ \t]*([0-9A-Fa-f]*)[ \t]*[0-9A-Fa-f]*[ \t]*([0-9A-Fa-f]*)[ \t]*[0-9A-Fa-f]*[ \t]*"; String bssRegExp = "^[ \t]*[0-9]*[ \t]*.bss[ \t]*([0-9A-Fa-f]*)[ \t]*[0-9A-Fa-f]*[ \t]*([0-9A-Fa-f]*)[ \t]*[0-9A-Fa-f]*[ \t]*"; Pattern dataPattern = Pattern.compile(dataRegExp); Pattern bssPattern = Pattern.compile(bssRegExp); Matcher matcher; for (String objdumpLine: objdumpData) { matcher = dataPattern.matcher(objdumpLine); if (matcher.find()) { String size = matcher.group(1); String offset = matcher.group(2); dataSectionSize = Integer.parseInt(size, 16); relDataSectionAddr = Integer.parseInt(offset, 16); } matcher = bssPattern.matcher(objdumpLine); if (matcher.find()) { String size = matcher.group(1); String offset = matcher.group(2); bssSectionSize = Integer.parseInt(size, 16); relBssSectionAddr = Integer.parseInt(offset, 16); } } if (relDataSectionAddr == -1) { logger.fatal("Data section address parsing failed"); return false; } if (dataSectionSize == -1) { logger.fatal("Data section size parsing failed"); return false; } if (relBssSectionAddr == -1) { logger.fatal("BSS section address parsing failed"); return false; } if (bssSectionSize == -1) { logger.fatal("BSS section size parsing failed"); return false; } // Get offset between relative and absolute addresses offsetRelToAbs = myCoreComm.getReferenceAbsAddr() - (Integer) varAddresses.get("referenceVar"); // Read initial memory from Mantis system byte[] initialDataSection = new byte[dataSectionSize]; myCoreComm.getMemory(relDataSectionAddr + offsetRelToAbs, dataSectionSize, initialDataSection); byte[] initialBssSection = new byte[bssSectionSize]; myCoreComm.getMemory(relBssSectionAddr + offsetRelToAbs, bssSectionSize, initialBssSection); // Store initial memory for later use myInitialMemory = new SectionMoteMemory(varAddresses); myInitialMemory.setMemorySegment(relDataSectionAddr, initialDataSection); myInitialMemory.setMemorySegment(relBssSectionAddr, initialBssSection); this.moteInterfaceClasses = moteInterfaceClasses; return true; } /** * 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 myInitialMemory.clone(); } /** * Ticks the currently loaded mote. This should not be used directly, but * rather via MantisMote.tick(). */ public void tick() { myCoreComm.tick(); } /** * Copy core memory to given memory. This should not be used directly, but * instead via MantisMote.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); byte[] data = mem.getDataOfSection(i); getCoreMemory(startAddr + offsetRelToAbs, size, data); } } /** * Copy given memory to the Mantis system. This should not be used directly, * but instead via MantisMote.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)); } } private void getCoreMemory(int start, int length, byte[] data) { myCoreComm.getMemory(start, length, data); } private void setCoreMemory(int start, int length, byte[] mem) { myCoreComm.setMemory(start, length, mem); } /** * Returns all mote interfaces of this mote type * * @return All mote interfaces */ public Vector<Class<? extends MoteInterface>> getMoteInterfaces() { return moteInterfaceClasses; } public String getDescription() { return myDescription; } public void setDescription(String description) { myDescription = description; } public String getIdentifier() { return myIdentifier; } public void setIdentifier(String identifier) { myIdentifier = identifier; } public String getObjectFilename() { return myObjectFilename; } public void setObjectFilename(String objectFilename) { myObjectFilename = objectFilename; } 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(myIdentifier); 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(myDescription); smallPane.add(BorderLayout.EAST, label); panel.add(smallPane); // Object file smallPane = new JPanel(new BorderLayout()); label = new JLabel("Object file"); smallPane.add(BorderLayout.WEST, label); label = new JLabel(myObjectFilename); 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); panel.add(Box.createRigidArea(new Dimension(0, 5))); return panel; } public PlatformConfig getConfig() { logger.debug("MantisMoteType::getConfig"); return null; } public Mote generateMote(Simulation simulation) { return new MantisMote(this, mySimulation); } public boolean configureAndInit(JFrame parentFrame, Simulation simulation) { return MantisMoteTypeDialog.showDialog(parentFrame, simulation, this); } public Collection<Element> getConfigXML() { Vector<Element> config = new Vector<Element>(); Element element; // Identifier element = new Element("identifier"); element.setText(getIdentifier()); config.add(element); // Description element = new Element("description"); element.setText(getDescription()); config.add(element); // Object file element = new Element("objectfile"); element.setText(getObjectFilename()); config.add(element); return config; } public boolean setConfigXML(Simulation simulation, Collection<Element> configXML) { mySimulation = simulation; for (Element element : configXML) { String name = element.getName(); if (name.equals("identifier")) { myIdentifier = element.getText(); } else if (name.equals("description")) { myDescription = element.getText(); } else if (name.equals("objectfile")) { myObjectFilename = element.getText(); } else { logger.fatal("Unrecognized entry in loaded configuration: " + name); } } boolean createdOK = configureAndInit(GUI.frame, simulation); return createdOK; } } |