From c18afffd366975901b12c187f7442e16fb0f7403 Mon Sep 17 00:00:00 2001 From: fros4943 Date: Thu, 7 Feb 2008 14:53:29 +0000 Subject: [PATCH] esb mote extends general msp mote --- .../src/se/sics/cooja/mspmote/ESBMote.java | 115 +++ .../se/sics/cooja/mspmote/ESBMoteType.java | 63 ++ .../src/se/sics/cooja/mspmote/MspMote.java | 354 +++++++ .../se/sics/cooja/mspmote/MspMoteMemory.java | 192 ++++ .../se/sics/cooja/mspmote/MspMoteType.java | 942 ++++++++++++++++++ 5 files changed, 1666 insertions(+) create mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java create mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java create mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java create mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteMemory.java create mode 100644 tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java new file mode 100644 index 000000000..6c3aebbc4 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2007, 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: ESBMote.java,v 1.1 2008/02/07 14:53:29 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote; + +import java.io.File; +import java.util.*; +import org.apache.log4j.Logger; +import se.sics.cooja.*; +import se.sics.cooja.interfaces.*; +import se.sics.cooja.mspmote.interfaces.*; +import se.sics.mspsim.platform.esb.ESBNode; + +/** + * @author Fredrik Osterlind + */ +public class ESBMote extends MspMote { + private static Logger logger = Logger.getLogger(ESBMote.class); + + public ESBNode esbNode = null; + + public ESBMote() { + super(); + } + + public ESBMote(MoteType moteType, Simulation sim) { + super((ESBMoteType) moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + try { + createCPUAndMemory(fileELF); + + esbNode = new ESBNode(getCPU()); + + } catch (Exception e) { + logger.fatal("Error when creating ESB mote: " + e); + return false; + } + return true; + } + + protected MoteInterfaceHandler createMoteInterfaceHandler() { + MoteInterfaceHandler moteInterfaceHandler = new MoteInterfaceHandler(); + // Add position interface + Position motePosition = new Position(this); + Random random = new Random(); + motePosition.setCoordinates(random.nextDouble()*100, random.nextDouble()*100, random.nextDouble()*100); + moteInterfaceHandler.addActiveInterface(motePosition); + + // Add log interface + Log moteLog = new ESBLog(this); + moteInterfaceHandler.addActiveInterface(moteLog); + + // Add time interface + Clock moteClock = new MspClock(this); + moteInterfaceHandler.addActiveInterface(moteClock); + + // Add led interface + LED moteLed = new ESBLED(this); + moteInterfaceHandler.addActiveInterface(moteLed); + + // Add button interface + Button moteButton = new ESBButton(this); + moteInterfaceHandler.addActiveInterface(moteButton); + + // Add ID interface + MoteID moteID = new MspMoteID(this); + moteInterfaceHandler.addActiveInterface(moteID); + + // Add radio interface + myRadio = new TR1001Radio(this); + moteInterfaceHandler.addActiveInterface(myRadio); + + return moteInterfaceHandler; + } + + public String toString() { + if (getInterfaces().getMoteID() != null) { + return "ESB Mote, ID=" + getInterfaces().getMoteID().getMoteID(); + } else { + return "ESB Mote, ID=null"; + } + } + +} + diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java new file mode 100644 index 000000000..d8fd902da --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 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: ESBMoteType.java,v 1.1 2008/02/07 14:53:29 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote; + +import javax.swing.*; +import org.apache.log4j.Logger; +import se.sics.cooja.*; + +@ClassDescription("ESB Mote Type") +@AbstractionLevelDescription("Emulated level") +public class ESBMoteType extends MspMoteType { + private static Logger logger = Logger.getLogger(ESBMoteType.class); + + public static final String target = "esb"; + public static final String targetNice = "ESB"; + + public ESBMoteType() { + } + + public ESBMoteType(String identifier) { + setIdentifier(identifier); + setDescription(targetNice + " Mote Type #" + identifier); + } + + public Mote generateMote(Simulation simulation) { + return new ESBMote(this, simulation); + } + + public boolean configureAndInit(JFrame parentFrame, Simulation simulation, + boolean visAvailable) throws MoteTypeCreationException { + return configureAndInitMspType(parentFrame, simulation, visAvailable, target, targetNice); + } + +} diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java new file mode 100644 index 000000000..8790cedfe --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2007, 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: MspMote.java,v 1.1 2008/02/07 14:53:29 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote; + +import java.io.*; +import java.util.*; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.mspmote.interfaces.TR1001Radio; +import se.sics.mspsim.core.MSP430; +import se.sics.mspsim.core.MapTable; +import se.sics.mspsim.util.ELF; + +/** + * @author Fredrik Osterlind + */ +public abstract class MspMote implements Mote { + private static Logger logger = Logger.getLogger(MspMote.class); + + /* 2.4 MHz */ + public static int NR_CYCLES_PER_MSEC = 2365; + + /* Cycle counter */ + public long cycleCounter = 0; + + private Simulation mySimulation = null; + private MSP430 myCpu = null; + private MspMoteType myMoteType = null; + private MspMoteMemory myMemory = null; + private MoteInterfaceHandler myMoteInterfaceHandler = null; + private ELF myELFModule = null; + + protected TR1001Radio myRadio = null; /* TODO Only used by ESB (TR1001) */ + + /* Stack monitoring variables */ + private boolean stopNextInstruction = false; + private boolean monitorStackUsage = false; + private int stackPointerLow = Integer.MAX_VALUE; + private int heapStartAddress; + private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable(); + + /** + * Abort current tick immediately. + * May for example be called by a breakpoint handler. + */ + public void stopNextInstruction() { + stopNextInstruction = true; + } + + public MspMote() { + myMoteType = null; + mySimulation = null; + myCpu = null; + myMemory = null; + myMoteInterfaceHandler = null; + } + + public MspMote(MspMoteType moteType, Simulation simulation) { + myMoteType = moteType; + mySimulation = simulation; + + initEmulator(myMoteType.getELFFile()); + + myMoteInterfaceHandler = createMoteInterfaceHandler(); + } + + /** + * @return MSP430 CPU + */ + public MSP430 getCPU() { + return myCpu; + } + + public MoteMemory getMemory() { + return myMemory; + } + + public void setMemory(MoteMemory memory) { + myMemory = (MspMoteMemory) memory; + } + + public Simulation getSimulation() { + return mySimulation; + } + + public void setSimulation(Simulation simulation) { + mySimulation = simulation; + } + + /* Stack monitoring variables */ + public class StackOverflowObservable extends Observable { + public void signalStackOverflow() { + setChanged(); + notifyObservers(); + } + } + + /** + * Enable/disable stack monitoring + * + * @param monitoring Monitoring enabled + */ + public void monitorStack(boolean monitoring) { + this.monitorStackUsage = monitoring; + resetLowestStackPointer(); + } + + /** + * @return Lowest SP since stack monitoring was enabled + */ + public int getLowestStackPointer() { + return stackPointerLow; + } + + /** + * Resets lowest stack pointer variable + */ + public void resetLowestStackPointer() { + stackPointerLow = Integer.MAX_VALUE; + } + + /** + * @return Stack overflow observable + */ + public StackOverflowObservable getStackOverflowObservable() { + return stackOverflowObservable; + } + + /** + * Creates MSP430 CPU object and address memory for current object. + * This method should normally not be called from outside constructor. + * + * @param fileELF ELF file + * @throws IOException File loading failed + */ + protected void createCPUAndMemory(File fileELF) throws IOException { + myCpu = new MSP430(0); + myCpu.setMonitorExec(true); + + int[] memory = myCpu.getMemory(); + + myELFModule = ELF.readELF(fileELF.getPath()); + myELFModule.loadPrograms(memory); + MapTable map = myELFModule.getMap(); + myCpu.getDisAsm().setMap(map); + myCpu.setMap(map); + + /* TODO Need new memory type including size and type as well */ + + /* Create mote address memory */ + Properties varAddresses = new Properties(); + for (int i=0; i < map.functionNames.length; i++) { + if (map.functionNames[i] != null) { + varAddresses.put(map.functionNames[i], new Integer(i)); + } + } + myMemory = new MspMoteMemory(varAddresses, myCpu); + + myCpu.reset(); + } + + public void setState(State newState) { + logger.warn("Msp motes can't change state"); + } + + public State getState() { + return Mote.State.ACTIVE; + } + + public MoteType getType() { + return myMoteType; + } + + public void setType(MoteType type) { + myMoteType = (MspMoteType) type; + } + + public void addStateObserver(Observer newObserver) { + } + + public void deleteStateObserver(Observer newObserver) { + } + + public MoteInterfaceHandler getInterfaces() { + return myMoteInterfaceHandler; + } + + public void setInterfaces(MoteInterfaceHandler moteInterfaceHandler) { + myMoteInterfaceHandler = moteInterfaceHandler; + } + + /** + * Creates an interface handler object and registers interfaces to it. + * + * @return Interface handler + */ + protected abstract MoteInterfaceHandler createMoteInterfaceHandler(); + + /** + * Initializes emulator by creating CPU, memory and node object. + * + * @param ELFFile ELF file + * @return True if successful + */ + protected abstract boolean initEmulator(File ELFFile); + + public void tick(int simTime) { + // Let all interfaces act + myMoteInterfaceHandler.doPassiveActionsBeforeTick(); + myMoteInterfaceHandler.doActiveActionsBeforeTick(); + + stopNextInstruction = false; + + // Leave control to emulated CPU + MSP430 cpu = getCPU(); + cycleCounter += NR_CYCLES_PER_MSEC; + + if (monitorStackUsage) { + // CPU loop with stack observer + int newStack; + while (!stopNextInstruction && cpu.step() < cycleCounter) { + /* Check if radio has pending incoming bytes */ + if (myRadio != null && myRadio.hasPendingBytes()) { + myRadio.tryDeliverNextByte(cpu.cycles); + } + + newStack = cpu.reg[MSP430.SP]; + if (newStack < stackPointerLow && newStack > 0) { + stackPointerLow = cpu.reg[MSP430.SP]; + + // Check if stack is writing in memory + if (stackPointerLow < heapStartAddress) { + stackOverflowObservable.signalStackOverflow(); + stopNextInstruction = true; + } + } + } + } else { /* Fast CPU loop */ + do { + /* Check if radio has pending incoming bytes */ + if (myRadio != null && myRadio.hasPendingBytes()) { + myRadio.tryDeliverNextByte(cpu.cycles); + } + } while (!stopNextInstruction && (cpu.step() < cycleCounter) ); + } + + // Reset abort flag + stopNextInstruction = false; + + // Let all interfaces act after tick + myMoteInterfaceHandler.doActiveActionsAfterTick(); + myMoteInterfaceHandler.doPassiveActionsAfterTick(); + } + + public boolean setConfigXML(Simulation simulation, Collection configXML, boolean visAvailable) { + for (Element element: configXML) { + String name = element.getName(); + + if (name.equals("motetype_identifier")) { + + setSimulation(simulation); + myMoteType = (MspMoteType) simulation.getMoteType(element.getText()); + getType().setIdentifier(element.getText()); + + initEmulator(myMoteType.getELFFile()); + myMoteInterfaceHandler = createMoteInterfaceHandler(); + + } else if (name.equals("interface_config")) { + Class moteInterfaceClass = simulation.getGUI().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 = getInterfaces().getInterfaceOfType(moteInterfaceClass); + moteInterface.setConfigXML(element.getChildren(), visAvailable); + } + } + + return true; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // Mote type identifier + element = new Element("motetype_identifier"); + element.setText(getType().getIdentifier()); + config.add(element); + + // Active interface configs (if any) + for (MoteInterface moteInterface: getInterfaces().getAllActiveInterfaces()) { + element = new Element("interface_config"); + element.setText(moteInterface.getClass().getName()); + + Collection interfaceXML = moteInterface.getConfigXML(); + if (interfaceXML != null) { + element.addContent(interfaceXML); + config.add(element); + } + } + + // Passive interface configs (if any) + for (MoteInterface moteInterface: getInterfaces().getAllPassiveInterfaces()) { + element = new Element("interface_config"); + element.setText(moteInterface.getClass().getName()); + + Collection interfaceXML = moteInterface.getConfigXML(); + if (interfaceXML != null) { + element.addContent(interfaceXML); + config.add(element); + } + } + + return config; + } + +} + diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteMemory.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteMemory.java new file mode 100644 index 000000000..1513fda3e --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteMemory.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2007, 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: MspMoteMemory.java,v 1.1 2008/02/07 14:53:29 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote; + +import java.util.*; +import org.apache.log4j.Logger; + +import se.sics.cooja.AddressMemory; +import se.sics.cooja.MoteMemory; +import se.sics.mspsim.core.MSP430; + +public class MspMoteMemory implements MoteMemory, AddressMemory { + private static Logger logger = Logger.getLogger(MspMoteMemory.class); + private final Properties variableAddresses; + + private int TEMP_MEM_START; + private MSP430 cpu; + + public MspMoteMemory(Properties variableAddresses, MSP430 cpu) { + this.variableAddresses = variableAddresses; + + this.cpu = cpu; + TEMP_MEM_START = 0; + } + + public String[] getVariableNames() { + String[] names = new String[variableAddresses.size()]; + Enumeration nameEnum = variableAddresses.keys(); + for (int i = 0; i < variableAddresses.size(); i++) { + names[i] = (String) nameEnum.nextElement(); + } + return names; + } + + public int getVariableAddress(String varName) { + if (!variableAddresses.containsKey(varName)) { + return -1; + } + return ((Integer) variableAddresses.get(varName)).intValue(); + } + + public void clearMemory() { + logger.fatal("clearMemory() not implemented"); + } + + public byte[] getMemorySegment(int address, int size) { + int[] ret = new int[size]; + + System.arraycopy(cpu.memory, address - TEMP_MEM_START, ret, 0, size); + + // TODO XXX Slow method + byte[] ret2 = new byte[size]; + for (int i=0; i < size; i++) { + ret2[i] = (byte) ret[i]; + } + + return ret2; + } + + public void setMemorySegment(int address, byte[] data) { + // TODO XXX Slow method + int[] intArr = new int[data.length]; + for (int i=0; i < data.length; i++) { + intArr[i] = data[i]; + } + + System.arraycopy(intArr, 0, cpu.memory, address - TEMP_MEM_START, data.length); + } + + public int getTotalSize() { + return cpu.memory.length; + } + + public boolean variableExists(String varName) { + return variableAddresses.containsKey(varName); + } + + public int getIntValueOf(String varName) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) { + return -1; + } + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + byte[] varData = getMemorySegment(varAddr, 2); + + int retVal = 0; + int pos = 0; + retVal += ((varData[pos++] & 0xFF)) << 8; + retVal += ((varData[pos++] & 0xFF)) << 0; + + return Integer.reverseBytes(retVal) >> 16; // Crop two bytes + } + + public void setIntValueOf(String varName, int newVal) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) { + return; + } + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + // TODO Check if small/big-endian when coming from JNI? + int newValToSet = Integer.reverseBytes(newVal); + + // Create byte array + int pos = 0; + + byte[] varData = new byte[4]; + varData[pos++] = (byte) ((newValToSet & 0xFF000000) >> 24); + varData[pos++] = (byte) ((newValToSet & 0xFF0000) >> 16); + varData[pos++] = (byte) ((newValToSet & 0xFF00) >> 8); + varData[pos++] = (byte) ((newValToSet & 0xFF) >> 0); + + setMemorySegment(varAddr, varData); + } + + public byte getByteValueOf(String varName) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) { + return -1; + } + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + byte[] varData = getMemorySegment(varAddr, 1); + + return varData[0]; + } + + public void setByteValueOf(String varName, byte newVal) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) { + return; + } + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + byte[] varData = new byte[1]; + + varData[0] = newVal; + + setMemorySegment(varAddr, varData); + } + + public byte[] getByteArray(String varName, int length) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) { + return null; + } + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + // TODO Check if small/big-endian when coming from JNI? + return getMemorySegment(varAddr, length); + } + + public void setByteArray(String varName, byte[] data) { + // Get start address of variable + if (!variableAddresses.containsKey(varName)) { + return; + } + int varAddr = ((Integer) variableAddresses.get(varName)).intValue(); + + // TODO Check if small/big-endian when coming from JNI? + setMemorySegment(varAddr, data); + } + +} diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java new file mode 100644 index 000000000..f8bab4b10 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java @@ -0,0 +1,942 @@ +/* + * Copyright (c) 2007, 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: MspMoteType.java,v 1.1 2008/02/07 14:53:29 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.util.*; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.filechooser.FileFilter; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.*; +import se.sics.cooja.dialogs.MessageList; + +@ClassDescription("Msp Mote Type") +public abstract class MspMoteType implements MoteType { + private static Logger logger = Logger.getLogger(MspMoteType.class); + + private static final String firmwareFileExtension = ".firmware"; + + /* Convenience: Preselecting last used directory */ + protected static File lastParentDirectory = null; + + private String identifier = null; + private String description = null; + + /* If source file is defined, (re)compilation is performed */ + private File fileELF = null; + private File fileSource = null; + private String compileCommand = null; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + /** + * Set ELF file. + * + * @param file + * ELF file + */ + public void setELFFile(File file) { + this.fileELF = file; + } + + /** + * Set compile command. + * + * @param command + * Compile command + */ + public void setCompileCommand(String command) { + this.compileCommand = command; + } + + /** + * @return ELF file + */ + public File getELFFile() { + return fileELF; + } + + /** + * @return Compile command + */ + public String getCompileCommand() { + return compileCommand; + } + + /** + * Set source file + * + * @param file Source file + */ + public void setSourceFile(File file) { + fileSource = file; + } + + /** + * @return Source file + */ + public File getSourceFile() { + return fileSource; + } + + /** + * Configures and initialized Msp mote types. + * + * @param parentFrame Graphical parent frame + * @param simulation Current simulation + * @param visAvailable Enable graphical interfaces and user input + * @param target Contiki target platform name + * @param targetNice Nicer representation of target + * @return True is successful + * @throws MoteTypeCreationException Mote type creation failed + */ + protected boolean configureAndInitMspType(JFrame parentFrame, Simulation simulation, + boolean visAvailable, String target, String targetNice) + throws MoteTypeCreationException { + boolean compileFromSource = false; + + if (getIdentifier() == null && !visAvailable) { + throw new MoteTypeCreationException("No identifier"); + } + + /* Generate unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + counter++; + setIdentifier(target + counter); + identifierOK = true; + + // Check if identifier is already used by some other type + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType != this + && existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + + if (getDescription() == null) { + setDescription(targetNice + " Mote Type #" + counter); + } + + /* Let user choose whether to compile or load existing binaries */ + Object[] options = { "Select", "Compile" }; + + String question = targetNice + " mote type depends on an ELF file.\n" + + "If you want to use an already existing file, click 'Select'.\n\n" + + "To compile this file from source, click 'Compile'"; + String title = "Select or compile " + targetNice + " firmware"; + int answer = JOptionPane.showOptionDialog(GUI.frame, + question, title, JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + + if (answer != JOptionPane.YES_OPTION && answer != JOptionPane.NO_OPTION) { + return false; + } + compileFromSource = answer != JOptionPane.YES_OPTION; + } + + /* Description */ + if (getDescription() == null) { + setDescription(targetNice + " Mote Type #" + getIdentifier()); + } + + if (getSourceFile() != null) { + compileFromSource = true; + } + + if (compileFromSource) { + MspELFCompiler compiler = new MspELFCompiler(target); + compiler.setCompileCommand(compileCommand); + + if (visAvailable) { + boolean success = compiler.showDialog(GUI.frame, this); + if (success) { + setSourceFile(compiler.getSourceFile()); + setELFFile(compiler.getOutputFile()); + setCompileCommand(compiler.getLastCompileCommand()); + return true; + } else { + return false; + } + } else { + MessageList compilationOutput = new MessageList(); + try { + compiler.compileFirmware(getSourceFile(), 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); + throw newException; + } + + /*File parentFile = getSourceFile().getParentFile();*/ + /*final String filenameNoExtension = getSourceFile().getName().substring(0, + getSourceFile().getName().length() - 2);*/ + /*setELFFile(new File(parentFile, filenameNoExtension + firmwareFileExtension));*/ + + setSourceFile(compiler.getSourceFile()); + setELFFile(compiler.getOutputFile()); + setCompileCommand(compiler.getLastCompileCommand()); + + return true; + } + } + + // Check dependency files + if (getELFFile() == null || !getELFFile().exists()) { + if (visAvailable) { + JFileChooser fc = new JFileChooser(); + + // Select previous directory + if (lastParentDirectory != null) { + fc.setCurrentDirectory(lastParentDirectory); + } else { + fc.setCurrentDirectory(new java.io.File(GUI + .getExternalToolsSetting("PATH_CONTIKI"))); + } + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.addChoosableFileFilter(new FileFilter() { + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + + String filename = f.getName(); + if (filename != null) { + if (filename.endsWith(firmwareFileExtension)) { + return true; + } + } + return false; + } + + public String getDescription() { + return "ELF file"; + } + }); + fc.setDialogTitle("Select ELF file"); + + if (fc.showOpenDialog(parentFrame) == JFileChooser.APPROVE_OPTION) { + lastParentDirectory = fc.getSelectedFile().getParentFile(); + setELFFile(fc.getSelectedFile()); + } else { + return false; + } + } else { + throw new MoteTypeCreationException("No ELF file was created"); + } + } + return true; + } + + protected static class MspELFCompiler { + private static int LABEL_WIDTH = 170; + + private static int LABEL_HEIGHT = 15; + + private JButton cancelButton = new JButton("Cancel"); + + private JButton compileButton = new JButton("Compile"); + + private JButton createButton = new JButton("Create"); + + private JTextField sourceTextField = new JTextField(); + + private JTextField compileCommandTextField = new JTextField(); + + // private JFormattedTextField nodeIDTextField; + // private NumberFormat integerFormat = NumberFormat.getIntegerInstance(); + + private String lastCompileCommand = null; + + private File sourceFile = null; + + private File ELFFile = null; + + private String target; + + private JDialog myDialog; + + private String customizedCompileCommand = null; + + static enum DialogState { + NO_SOURCE, SELECTED_SOURCE, IS_COMPILING, COMPILED_SOURCE + } + + public MspELFCompiler(String target) { + this.target = target; + } + + private String getCompileCommand(String filename) { + if (customizedCompileCommand != null) { + return customizedCompileCommand; + } + return GUI.getExternalToolsSetting("PATH_MAKE") + " " + filename + firmwareFileExtension + " TARGET=" + target; + } + + private void setCompileCommand(String command) { + if (command == null || command.isEmpty()) { + customizedCompileCommand = null; + return; + } + customizedCompileCommand = command; + } + + /** + * @return Compiler output + */ + public File getOutputFile() { + return ELFFile; + } + + public File getSourceFile() { + return sourceFile; + } + + public String getLastCompileCommand() { + return lastCompileCommand; + } + + private void updateDialog(DialogState dialogState) { + switch (dialogState) { + case NO_SOURCE: + compileButton.setEnabled(false); + createButton.setEnabled(false); + compileCommandTextField.setText(""); + break; + + case IS_COMPILING: + compileButton.setEnabled(false); + createButton.setEnabled(false); + break; + + case SELECTED_SOURCE: + File sourceFile = new File(sourceTextField.getText()); + if (!sourceFile.exists()) { + updateDialog(DialogState.NO_SOURCE); + break; + } + + File parentDirectory = sourceFile.getParentFile(); + if (!parentDirectory.exists()) { + updateDialog(DialogState.NO_SOURCE); + break; + } + + if (!sourceFile.getName().endsWith(".c")) { + updateDialog(DialogState.NO_SOURCE); + break; + } + + String name = sourceFile.getName().substring(0, + sourceFile.getName().length() - 2); + + compileButton.setEnabled(true); + createButton.setEnabled(false); + compileCommandTextField.setText(getCompileCommand(name)); + compileButton.requestFocusInWindow(); + break; + + case COMPILED_SOURCE: + compileButton.setEnabled(true); + createButton.setEnabled(true); + + createButton.requestFocusInWindow(); + myDialog.getRootPane().setDefaultButton(createButton); + break; + + default: + break; + } + } + + protected void compileFirmware(final File sourceFile, + final Action successAction, final Action failAction, + MessageList compilationOutput, boolean synchronous) throws Exception { + final File parentDirectory = sourceFile.getParentFile(); + final String filenameNoExtension = sourceFile.getName().substring(0, + sourceFile.getName().length() - 2); + + String command = getCompileCommand(filenameNoExtension); + logger.info("Compile command: " + command); + + compilationOutput.clearMessages(); + + try { + String[] cmd = command.split(" "); + + final Process compileProcess = Runtime.getRuntime().exec(cmd, null, + parentDirectory); + + final BufferedReader processNormal = new BufferedReader( + new InputStreamReader(compileProcess.getInputStream())); + final BufferedReader processError = new BufferedReader( + new InputStreamReader(compileProcess.getErrorStream())); + + final PrintStream listNormal = compilationOutput + .getInputStream(MessageList.NORMAL); + final PrintStream listError = compilationOutput + .getInputStream(MessageList.ERROR); + + final File ELFFile = new File(parentDirectory, filenameNoExtension + firmwareFileExtension); + if (ELFFile.exists()) { + ELFFile.delete(); + if (ELFFile.exists()) { + listError.println("Error when deleting old " + ELFFile.getName()); + if (failAction != null) { + failAction.actionPerformed(null); + } + throw new MoteTypeCreationException("Error when deleting old " + + ELFFile.getName()); + } + } + + Thread readInput = new Thread(new Runnable() { + public void run() { + String readLine; + try { + while ((readLine = processNormal.readLine()) != null) { + if (listNormal != null && readLine != null) { + listNormal.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 = processError.readLine()) != null) { + if (listError != null && readLine != null) { + listError.println(readLine); + } + } + } catch (IOException e) { + logger.warn("Error while reading from process"); + } + } + }, "read input stream thread"); + + final MoteTypeCreationException syncException = new MoteTypeCreationException( + ""); + Thread handleCompilationResultThread = new Thread(new Runnable() { + public void run() { + + /* Wait for compilation to end */ + try { + compileProcess.waitFor(); + } catch (Exception e) { + syncException.setCompilationOutput(new MessageList()); + syncException.fillInStackTrace(); + return; + } + + /* Check return value */ + if (compileProcess.exitValue() != 0) { + listError.println("Process returned error code " + + compileProcess.exitValue()); + if (failAction != null) { + failAction.actionPerformed(null); + } + syncException.setCompilationOutput(new MessageList()); + syncException.fillInStackTrace(); + return; + } + + if (!ELFFile.exists()) { + listError.println("Can't locate output file " + ELFFile); + if (failAction != null) { + failAction.actionPerformed(null); + } + syncException.setCompilationOutput(new MessageList()); + syncException.fillInStackTrace(); + return; + } + + listNormal.println(""); + listNormal.println("Compilation succeded"); + if (successAction != null) { + successAction.actionPerformed(null); + } + } + }, "enable create button thread"); + + readInput.start(); + readError.start(); + handleCompilationResultThread.start(); + + if (synchronous) { + try { + handleCompilationResultThread.join(); + } catch (Exception e) { + throw (MoteTypeCreationException) new MoteTypeCreationException( + "Compilation error: " + e.getMessage()).initCause(e); + } + + if (syncException.hasCompilationOutput()) { + throw (MoteTypeCreationException) new MoteTypeCreationException( + "Compilation error").initCause(syncException); + } + } + + } catch (IOException ex) { + if (failAction != null) { + failAction.actionPerformed(null); + } + throw (MoteTypeCreationException) new MoteTypeCreationException( + "Compilation error: " + ex.getMessage()).initCause(ex); + } + } + + public boolean showDialog(Frame parentFrame, final MspMoteType moteType) { + myDialog = new JDialog(parentFrame, "Compile ELF file", true); + final MessageList taskOutput = new MessageList(); + + // BOTTOM BUTTON PART + Box buttonBox = Box.createHorizontalBox(); + buttonBox.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + + buttonBox.add(Box.createHorizontalGlue()); + + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + sourceFile = null; + ELFFile = null; + + myDialog.dispose(); + } + }); + + compileButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final File selectedSourceFile = new File(sourceTextField.getText()); + + /* Strip .c file extension */ + final String filenameNoExtension = selectedSourceFile.getName() + .substring(0, selectedSourceFile.getName().length() - 2); + + Action successAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + updateDialog(DialogState.COMPILED_SOURCE); + File parentFile = selectedSourceFile.getParentFile(); + + lastCompileCommand = getCompileCommand(filenameNoExtension); + sourceFile = selectedSourceFile; + ELFFile = new File(parentFile, filenameNoExtension + firmwareFileExtension); + } + }; + Action failAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + updateDialog(DialogState.SELECTED_SOURCE); + } + }; + + updateDialog(DialogState.IS_COMPILING); + try { + compileFirmware(new File(sourceTextField.getText()), successAction, + failAction, taskOutput, false); + } catch (Exception e2) { + } + } + }); + + createButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + myDialog.dispose(); + } + }); + + buttonBox.add(cancelButton); + buttonBox.add(Box.createHorizontalStrut(5)); + buttonBox.add(compileButton); + buttonBox.add(Box.createHorizontalStrut(5)); + buttonBox.add(createButton); + + // MAIN DIALOG CONTENTS + Box horizBox; + JLabel label; + Box vertBox = Box.createVerticalBox(); + + // Source + horizBox = Box.createHorizontalBox(); + horizBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, LABEL_HEIGHT)); + horizBox.setAlignmentX(Component.LEFT_ALIGNMENT); + label = new JLabel("Contiki process sourcefile"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + sourceTextField.setText(""); + if (moteType.getSourceFile() != null) { + sourceTextField.setText(moteType.getSourceFile().getAbsolutePath()); + } + sourceTextField.setColumns(25); + + sourceTextField.getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + updateDialog(DialogState.SELECTED_SOURCE); + } + public void changedUpdate(DocumentEvent e) { + updateDialog(DialogState.SELECTED_SOURCE); + } + public void removeUpdate(DocumentEvent e) { + updateDialog(DialogState.SELECTED_SOURCE); + } + }); + + JButton browseButton = new JButton("Browse"); + browseButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + updateDialog(DialogState.NO_SOURCE); + + JFileChooser fc = new JFileChooser(); + if (lastParentDirectory != null) { + fc.setCurrentDirectory(lastParentDirectory); + } else { + fc.setCurrentDirectory(new java.io.File(GUI + .getExternalToolsSetting("PATH_CONTIKI"))); + } + + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.addChoosableFileFilter(new FileFilter() { + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + + String filename = f.getName(); + if (filename != null) { + if (filename.endsWith(".c")) { + return true; + } + } + return false; + } + + public String getDescription() { + return "Contiki process source"; + } + }); + fc.setDialogTitle("Select Contiki process source"); + + if (fc.showOpenDialog(myDialog) == JFileChooser.APPROVE_OPTION) { + lastParentDirectory = null; + sourceTextField.setText(""); + + File selectedFile = fc.getSelectedFile(); + if (!selectedFile.exists()) { + return; + } + + if (!selectedFile.getName().endsWith(".c")) { + return; + } + + lastParentDirectory = fc.getSelectedFile().getParentFile(); + sourceTextField.setText(fc.getSelectedFile().getAbsolutePath()); + updateDialog(DialogState.SELECTED_SOURCE); + } + } + }); + + horizBox.add(label); + horizBox.add(Box.createHorizontalStrut(10)); + horizBox.add(sourceTextField); + horizBox.add(browseButton); + + vertBox.add(horizBox); + vertBox.add(Box.createRigidArea(new Dimension(0, 5))); + + // Node ID + /* + * horizBox = Box.createHorizontalBox(); horizBox.setMaximumSize(new + * Dimension(Integer.MAX_VALUE,LABEL_HEIGHT)); + * horizBox.setAlignmentX(Component.LEFT_ALIGNMENT); label = new + * JLabel("Node ID (0=EEPROM)"); label.setPreferredSize(new + * Dimension(LABEL_WIDTH,LABEL_HEIGHT)); + * + * nodeIDTextField = new JFormattedTextField(integerFormat); + * nodeIDTextField.setValue(new Integer(0)); + * nodeIDTextField.setColumns(25); + * nodeIDTextField.addPropertyChangeListener("value", new + * PropertyChangeListener() { public void + * propertyChange(PropertyChangeEvent e) { + * updateDialog(DialogState.SELECTED_SOURCE); } }); + * + * horizBox.add(label); horizBox.add(Box.createHorizontalStrut(150)); + * horizBox.add(nodeIDTextField); + * + * vertBox.add(horizBox); vertBox.add(Box.createRigidArea(new + * Dimension(0,5))); + */ + + // Compile command + horizBox = Box.createHorizontalBox(); + horizBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, LABEL_HEIGHT)); + horizBox.setAlignmentX(Component.LEFT_ALIGNMENT); + label = new JLabel("Compile command"); + label.setPreferredSize(new Dimension(LABEL_WIDTH, LABEL_HEIGHT)); + + compileCommandTextField.setText(""); + compileCommandTextField.setColumns(25); + compileCommandTextField.setEditable(true); + + compileCommandTextField.getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + setCompileCommand(compileCommandTextField.getText()); + } + public void changedUpdate(DocumentEvent e) { + setCompileCommand(compileCommandTextField.getText()); + } + public void removeUpdate(DocumentEvent e) { + setCompileCommand(compileCommandTextField.getText()); + } + }); + + horizBox.add(label); + horizBox.add(Box.createHorizontalStrut(10)); + horizBox.add(compileCommandTextField); + + vertBox.add(horizBox); + vertBox.add(Box.createRigidArea(new Dimension(0, 5))); + + vertBox.add(Box.createRigidArea(new Dimension(0, 5))); + vertBox.add(new JLabel("Compilation output:")); + vertBox.add(Box.createRigidArea(new Dimension(0, 5))); + + vertBox.add(new JScrollPane(taskOutput)); + vertBox.add(Box.createRigidArea(new Dimension(0, 5))); + + vertBox.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + Container contentPane = myDialog.getContentPane(); + contentPane.add(vertBox, BorderLayout.CENTER); + contentPane.add(buttonBox, BorderLayout.SOUTH); + + myDialog.pack(); + myDialog.setLocationRelativeTo(parentFrame); + myDialog.getRootPane().setDefaultButton(compileButton); + + // Dispose on escape key + InputMap inputMap = myDialog.getRootPane().getInputMap( + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), + "dispose"); + AbstractAction cancelAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + cancelButton.doClick(); + } + }; + myDialog.getRootPane().getActionMap().put("dispose", cancelAction); + + myDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + myDialog.addWindowListener(new WindowListener() { + public void windowDeactivated(WindowEvent e) { + } + + public void windowIconified(WindowEvent e) { + } + + public void windowDeiconified(WindowEvent e) { + } + + public void windowOpened(WindowEvent e) { + } + + public void windowClosed(WindowEvent e) { + } + + public void windowActivated(WindowEvent e) { + } + + public void windowClosing(WindowEvent e) { + cancelButton.doClick(); + } + }); + + updateDialog(DialogState.NO_SOURCE); + if (moteType.getSourceFile() != null) { + updateDialog(DialogState.SELECTED_SOURCE); + if (customizedCompileCommand != null && !customizedCompileCommand.equals("")) { + compileCommandTextField.setText(customizedCompileCommand); + } + compileButton.requestFocus(); + } + + myDialog.setVisible(true); + + return sourceFile != null; + } + + } + + 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(getIdentifier()); + 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(getDescription()); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + // ELF Hex file + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("ELF file"); + smallPane.add(BorderLayout.WEST, label); + label = new JLabel(getELFFile().getName()); + label.setToolTipText(getELFFile().getPath()); + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + // Source file + smallPane = new JPanel(new BorderLayout()); + label = new JLabel("Source file"); + smallPane.add(BorderLayout.WEST, label); + if (getSourceFile() != null) { + label = new JLabel(getSourceFile().getName()); + label.setToolTipText(getSourceFile().getPath()); + } else { + label = new JLabel("[not specified]"); + } + smallPane.add(BorderLayout.EAST, label); + panel.add(smallPane); + + panel.add(Box.createRigidArea(new Dimension(0, 5))); + return panel; + } + + public ProjectConfig getConfig() { + logger.warn("Msp mote type project config not implemented"); + return null; + } + + public Collection getConfigXML() { + Vector config = new Vector(); + + Element element; + + // Identifier + element = new Element("identifier"); + element.setText(getIdentifier()); + config.add(element); + + // Description + element = new Element("description"); + element.setText(getDescription()); + config.add(element); + + // Source file + if (fileSource != null) { + element = new Element("source"); + element.setText(fileSource.getPath()); + config.add(element); + element = new Element("command"); + element.setText(compileCommand); + config.add(element); + } else { + // ELF file + element = new Element("elf"); + element.setText(fileELF.getPath()); + config.add(element); + } + + return config; + } + + public boolean setConfigXML(Simulation simulation, + Collection configXML, boolean visAvailable) + throws MoteTypeCreationException { + for (Element element : configXML) { + String name = element.getName(); + + if (name.equals("identifier")) { + identifier = element.getText(); + } else if (name.equals("description")) { + description = element.getText(); + } else if (name.equals("source")) { + fileSource = new File(element.getText()); + } else if (name.equals("command")) { + compileCommand = element.getText(); + } else if (name.equals("elf")) { + fileELF = new File(element.getText()); + } else { + logger.fatal("Unrecognized entry in loaded configuration: " + name); + throw new MoteTypeCreationException( + "Unrecognized entry in loaded configuration: " + name); + } + } + + return configureAndInit(GUI.frame, simulation, visAvailable); + } + +}