📄 contikimotetype.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: ContikiMoteType.java,v 1.27 2008/05/02 05:47:22 fros4943 Exp $ */package se.sics.cooja.contikimote;import java.awt.BorderLayout;import java.awt.Container;import java.awt.Dimension;import java.io.*;import java.security.*;import java.util.*;import java.util.regex.*;import javax.swing.*;import org.apache.log4j.Logger;import org.jdom.Element;import se.sics.cooja.*;import se.sics.cooja.dialogs.MessageList;/** * 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. * <p> * 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. * <p> * All core communication with the Contiki mote should be via this class. When a * mote type is created it allocates a CoreComm to be used with this type, and * loads the variable and segments addresses. * <p> * When a new mote type is created an initialization function is run on the * Contiki system in order to create the initial memory. When a new mote is * created the createInitialMemory() method should be called to get this initial * memory for the mote. * * @author Fredrik Osterlind */@ClassDescription("Contiki Mote Type")@AbstractionLevelDescription("OS level")public class ContikiMoteType implements MoteType { private static Logger logger = Logger.getLogger(ContikiMoteType.class); /** * Map file suffix */ final static public String mapSuffix = ".map"; /** * Library file suffix */ final static public String librarySuffix = ".library"; /** * Make dependency file suffix */ final static public String dependSuffix = ".a"; /** * Temporary output directory */ final static public File tempOutputDirectory = new File("obj_cooja"); /** * Communication stacks in Contiki. */ public enum CommunicationStack { RIME, UIP, UIP_UAODV; public String toString() { if (this == UIP) { return "uIP"; } if (this == UIP_UAODV) { return "uIP over uAODV"; } if (this == RIME) { return "Rime"; } return "[unknown]"; } public String getSourceFilenamesString() { if (this == UIP) { return " cooja-radio.c radio-uip.c init-net-uip.c"; } if (this == UIP_UAODV) { return " uaodv.c cooja-radio.c radio-uip-uaodv.c init-net-uip-uaodv.c crc16.c"; } if (this == RIME) { return " cooja-radio.c init-net-rime.c"; } return " "; } public static CommunicationStack parse(String name) { if (name.equals("uIP") || name.equals("UIP")) { return UIP; } if (name.equals("uIP over uAODV") || name.equals("UIP_UAODV")) { return UIP_UAODV; } if (name.equals("Rime") || name.equals("RIME")) { return RIME; } logger.warn("Can't parse communication stack name: " + name); return UIP; } } // Mote type specific data private String identifier = null; private String description = null; private String contikiBaseDir = null; private String contikiCoreDir = null; private Vector<File> projectDirs = null; private Vector<File> compilationFiles = null; private Vector<String> processes = null; private Vector<String> sensors = null; private Vector<String> coreInterfaces = null; private Vector<Class<? extends MoteInterface>> moteInterfaces = null; private boolean hasSystemSymbols = false; private CommunicationStack commStack = CommunicationStack.RIME; // Simulation holding this mote type private Simulation mySimulation = null; // Type specific class configuration private ProjectConfig myConfig = null; // Core communication variables private String libraryClassName = null; private int offsetRelToAbs = 0; private CoreComm myCoreComm = null; // Variable name to address mappings private Properties varAddresses = new Properties(); // Initial memory for all motes of this type private SectionMoteMemory initialMemory = null; /** * Creates a new uninitialized Contiki mote type. This mote type needs to load * a library file and parse a map file before it can be used. */ public ContikiMoteType() { } /** * Creates a new Contiki mote type. * * @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 { if (visAvailable) { return ContikiMoteTypeDialog.showDialog(parentContainer, simulation, this); } else { // 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); } // 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); } // Generate Contiki main source file try { ContikiMoteTypeDialog.generateSourceFile(identifier, sensors, coreInterfaces, processes); } catch (Exception e) { throw (MoteTypeCreationException) new MoteTypeCreationException( "Error during main source file generation: " + e.getMessage()) .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; } if (!depFile.exists()) { MoteTypeCreationException ex = new MoteTypeCreationException( "Compilation error: " + depFile.getPath() + " does not exist"); ex.setCompilationOutput(taskOutput); throw ex; } if (!compilationSucceded) { MoteTypeCreationException ex = new MoteTypeCreationException( "Compilation error: Unknown error"); ex.setCompilationOutput(taskOutput); throw ex; } // Load compiled library doInit(identifier); return true; } } /** * This is an mote type initialization method and should normally never be * called by any other part than the mote type constructor. It is called from * the constructor with an identifier argument. but not from the standard * constructor. This method may be called from the simulator when loading * configuration files, and the libraries must be recompiled. * * This method allocates a core communicator, loads the Contiki library file, * loads and parses library addresses, creates a variable name to address * mapping of the Contiki system and finally creates the Contiki mote initial * memory. * * @param identifier * Mote type identifier */ protected void doInit(String identifier) throws MoteTypeCreationException { this.identifier = identifier; if (myCoreComm != null) { 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); // Check that library file exists if (!libFile.exists()) { throw new MoteTypeCreationException("Library file could not be found: " + libFile); } // Allocate core communicator class libraryClassName = CoreComm.getAvailableClassName(); myCoreComm = CoreComm.createCoreComm(libraryClassName, libFile); // Should we parse addresses using map file or command? boolean useCommand = Boolean.parseBoolean(GUI.getExternalToolsSetting("PARSE_WITH_COMMAND", "false")); int relDataSectionAddr = -1; int dataSectionSize = -1; int relBssSectionAddr = -1; int bssSectionSize = -1; if (useCommand) { // Parse command output Vector<String> commandData = loadCommandData(libFile); if (commandData == null) { logger.fatal("No parse command output could be loaded"); throw new MoteTypeCreationException("No parse command output be loaded"); } boolean parseOK = parseCommandData(commandData, varAddresses); if (!parseOK) { logger.fatal("Command output parsing failed"); throw new MoteTypeCreationException("Command output parsing failed"); } relDataSectionAddr = loadCommandRelDataSectionAddr(commandData); dataSectionSize = loadCommandDataSectionSize(commandData); relBssSectionAddr = loadCommandRelBssSectionAddr(commandData); bssSectionSize = loadCommandBssSectionSize(commandData); } else { // Parse map file if (!mapFile.exists()) { logger.fatal("Map file " + mapFile.getAbsolutePath() + " could not be found!"); throw new MoteTypeCreationException("Map file " + mapFile.getAbsolutePath() + " could not be found!"); } Vector<String> mapData = loadMapFile(mapFile); if (mapData == null) { logger.fatal("No map data could be loaded"); throw new MoteTypeCreationException("No map data could be loaded"); } boolean parseOK = parseMapFileData(mapData, varAddresses); if (!parseOK) { logger.fatal("Map data parsing failed"); throw new MoteTypeCreationException("Map data parsing failed"); } relDataSectionAddr = loadRelDataSectionAddr(mapData); dataSectionSize = loadDataSectionSize(mapData); relBssSectionAddr = loadRelBssSectionAddr(mapData); bssSectionSize = loadBssSectionSize(mapData); } // Create variable names to addresses mappings if (varAddresses.size() == 0) { throw new MoteTypeCreationException( "Variable name to addresses mappings could not be created"); } try { // Get offset between relative and absolute addresses offsetRelToAbs = getReferenceAbsAddr() - (Integer) varAddresses.get("referenceVar"); } catch (Exception e) { throw (MoteTypeCreationException) new MoteTypeCreationException( "JNI call error: " + e.getMessage()).initCause(e); } if (relDataSectionAddr <= 0 || dataSectionSize <= 0 || relBssSectionAddr <= 0 || bssSectionSize <= 0) { throw new MoteTypeCreationException( "Could not parse section addresses correctly"); } // Create initial memory byte[] initialDataSection = new byte[dataSectionSize]; getCoreMemory(relDataSectionAddr + offsetRelToAbs, dataSectionSize, initialDataSection); byte[] initialBssSection = new byte[bssSectionSize]; getCoreMemory(relBssSectionAddr + offsetRelToAbs, bssSectionSize, initialBssSection); initialMemory = new SectionMoteMemory(varAddresses); initialMemory.setMemorySegment(relDataSectionAddr, initialDataSection); initialMemory.setMemorySegment(relBssSectionAddr, initialBssSection); } /** * Ticks the currently loaded mote. This should not be used directly, but * rather via ContikiMote.tick(). */ public void tick() { myCoreComm.tick(); } /** * Creates and returns a copy of this mote type's initial memory (just after * the init function has been run). When a new mote is created it should get * it's memory from here. * * @return Initial memory of a mote type */ public SectionMoteMemory createInitialMemory() { return initialMemory.clone(); } /** * Copy given memory to the Contiki system. This should not be used directly, * but instead via ContikiMote.setMemory(). * * @param mem * New memory */ public void setCoreMemory(SectionMoteMemory mem) { for (int i = 0; i < mem.getNumberOfSections(); i++) { setCoreMemory(mem.getStartAddrOfSection(i) + offsetRelToAbs, mem .getSizeOfSection(i), mem.getDataOfSection(i)); } } /** * Parses specified map file data for variable name to addresses mappings. The * mappings are added to the given properties object. * * @param mapFileData * Contents of entire map file * @param varAddresses * Properties that should contain the name to addresses mappings. */ public static boolean parseMapFileData(Vector<String> mapFileData, Properties varAddresses) { Vector<String> varNames = getMapFileVarNames(mapFileData); if (varNames == null || varNames.size() == 0) { return false; } for (String varName : varNames) { int varAddress = getMapFileVarAddress(mapFileData, varName, varAddresses); if (varAddress > 0) { varAddresses.put(varName, new Integer(varAddress)); } else { logger.warn("Parsed Contiki variable '" + varName + "' but could not find address"); } } return true; } /** * Parses specified parse command output for variable * name to addresses mappings. The mappings are added * to the given properties object. * * @param commandData * Output from parse command on object file * @param varAddresses * Properties that should contain the name to addresses mappings. */ public static boolean parseCommandData(Vector<String> commandData, Properties varAddresses) { int nrNew = 0, nrOld = 0, nrMismatch = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -