added test files for future support of mantis os.
not working yet due to threading vs jni problems
This commit is contained in:
parent
38fe078d38
commit
d6a2211918
5 changed files with 1614 additions and 1 deletions
|
@ -29,9 +29,10 @@ se.sics.cooja.contikimote.interfaces.ContikiCFS.CONSUMPTION_PER_READ_CHAR_mQ = 1
|
|||
|
||||
se.sics.cooja.contikimote.ContikiMoteType.MOTE_INTERFACES = se.sics.cooja.interfaces.Position se.sics.cooja.interfaces.Battery se.sics.cooja.contikimote.interfaces.ContikiVib se.sics.cooja.contikimote.interfaces.ContikiMoteID se.sics.cooja.contikimote.interfaces.ContikiRS232 se.sics.cooja.contikimote.interfaces.ContikiBeeper se.sics.cooja.contikimote.interfaces.ContikiIPAddress se.sics.cooja.contikimote.interfaces.ContikiRadio se.sics.cooja.contikimote.interfaces.ContikiButton se.sics.cooja.contikimote.interfaces.ContikiPIR se.sics.cooja.contikimote.interfaces.ContikiClock se.sics.cooja.contikimote.interfaces.ContikiLED se.sics.cooja.contikimote.interfaces.ContikiLog se.sics.cooja.contikimote.interfaces.ContikiCFS
|
||||
se.sics.cooja.contikimote.ContikiMoteType.C_SOURCES =
|
||||
se.sics.cooja.GUI.MOTETYPES = se.sics.cooja.contikimote.ContikiMoteType se.sics.cooja.motes.DummyMoteType
|
||||
se.sics.cooja.GUI.MOTETYPES = se.sics.cooja.contikimote.ContikiMoteType se.sics.cooja.motes.DummyMoteType se.sics.cooja.mantismote.MantisMoteType
|
||||
se.sics.cooja.GUI.PLUGINS = se.sics.cooja.plugins.VisState se.sics.cooja.plugins.VisBattery se.sics.cooja.plugins.VisTraffic se.sics.cooja.plugins.LogListener se.sics.cooja.plugins.MoteInformation se.sics.cooja.plugins.MoteInterfaceViewer se.sics.cooja.plugins.VariableWatcher
|
||||
se.sics.cooja.GUI.IP_DISTRIBUTORS = se.sics.cooja.ipdistributors.RandomIPDistributor se.sics.cooja.ipdistributors.SpatialIPDistributor se.sics.cooja.ipdistributors.IdIPDistributor
|
||||
se.sics.cooja.GUI.POSITIONERS = se.sics.cooja.positioners.RandomPositioner se.sics.cooja.positioners.LinearPositioner se.sics.cooja.positioners.EllipsePositioner
|
||||
se.sics.cooja.GUI.RADIOMEDIUMS = se.sics.cooja.radiomediums.StandardRadioMedium se.sics.cooja.radiomediums.SilentRadioMedium
|
||||
|
||||
se.sics.cooja.mantismote.MantisMoteType.MOTE_INTERFACES = se.sics.cooja.interfaces.Position
|
||||
|
|
178
tools/cooja/config/mantis_template.c
Normal file
178
tools/cooja/config/mantis_template.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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: mantis_template.c,v 1.1 2006/11/09 19:32:53 fros4943 Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* C code template for generating Mantis source code files from COOJA
|
||||
* Simulator. This file should not be compiled directly.
|
||||
* \author
|
||||
* Fredrik Osterlind <fros@sics.se>
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "mos.h"
|
||||
#include "sem.h"
|
||||
#include "msched.h"
|
||||
|
||||
extern int main(); /* in mantis/src/mos/sys/main.c */
|
||||
extern uint32_t cooja_time; /* in mantis/src/mos/sys/main.c */
|
||||
extern pthread_cond_t cooja_cv; /* in mantis/src/mos/sys/main.c */
|
||||
extern mos_thread_t threads[MAX_THREADS]; /* in mantis/src/mos/sys/main.c */
|
||||
|
||||
/*
|
||||
* referenceVar is used for comparing absolute and process relative memory.
|
||||
* (this must not be static due to memory locations)
|
||||
*/
|
||||
int referenceVar;
|
||||
|
||||
int dataVar = 1;
|
||||
int i;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialize a mote by starting processes etc.
|
||||
*
|
||||
* This function initializes a mote by starting certain
|
||||
* processes and setting up the environment.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_se_sics_cooja_corecomm_[CLASS_NAME]_init(JNIEnv *env, jobject obj)
|
||||
{
|
||||
main();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Get a segment from the process memory.
|
||||
* \param start Start address of segment
|
||||
* \param length Size of memory segment
|
||||
* \return Java byte array containing a copy of memory segment.
|
||||
*
|
||||
* Fetches a memory segment from the process memory starting at
|
||||
* (start), with size (length). This function does not perform
|
||||
* ANY error checking, and the process may crash if addresses are
|
||||
* not available/readable.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_se_sics_cooja_corecomm_[CLASS_NAME]_getMemory(JNIEnv *env, jobject obj, jint start, jint length, jbyteArray mem_arr)
|
||||
{
|
||||
(*env)->SetByteArrayRegion(env, mem_arr, 0, (size_t) length, (jbyte *) start);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Replace a segment of the process memory with given byte array.
|
||||
* \param start Start address of segment
|
||||
* \param length Size of memory segment
|
||||
* \param mem_arr Byte array contaning new memory
|
||||
*
|
||||
* Replaces a process memory segment with given byte array.
|
||||
* This function does not perform ANY error checking, and the
|
||||
* process may crash if addresses are not available/writable.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_se_sics_cooja_corecomm_[CLASS_NAME]_setMemory(JNIEnv *env, jobject obj, jint start, jint length, jbyteArray mem_arr)
|
||||
{
|
||||
jbyte *mem = (*env)->GetByteArrayElements(env, mem_arr, 0);
|
||||
memcpy((void *) start, mem, length);
|
||||
(*env)->ReleaseByteArrayElements(env, mem_arr, mem, 0);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Let mote execute one "block" of code (tick mote).
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_se_sics_cooja_corecomm_[CLASS_NAME]_tick(JNIEnv *env, jobject obj)
|
||||
{
|
||||
int readyexist = 0;
|
||||
|
||||
/* Ugly hack, setting all ready threads to BLOCKED just to discover which ones wake up */
|
||||
for(i=0; i<MAX_THREADS; i++) {
|
||||
if (threads[i].state == READY) {
|
||||
threads[i].state = BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
cooja_time += 1; // increase time
|
||||
//printf("CORE> tick, time is now %i\n", cooja_time);
|
||||
|
||||
/* Signal all threads to start working again */
|
||||
for(i=0; i<MAX_THREADS; i++) {
|
||||
if (threads[i].state == BLOCKED) {
|
||||
mos_thread_resume(&threads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait until all threads are blocked again. ??!?!!
|
||||
* For now we just assume all threads will be done within 1ms. */
|
||||
do {
|
||||
readyexist=0;
|
||||
for(i=0; i<MAX_THREADS; i++) {
|
||||
if (threads[i].state == READY) {
|
||||
readyexist = 1;
|
||||
//printf("waiting until thread finished...: %p\n", &threads[i]);
|
||||
//fflush(stdout);
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
} while (readyexist);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Get the absolute memory address of a special variable.
|
||||
* \return Absolute memory address.
|
||||
*
|
||||
* Returns the absolute memory address of a special variable
|
||||
* "referenceVar". By comparing this address with the relative
|
||||
* address (from the map file) for referenceVar, an runtime offset
|
||||
* can be calculated.
|
||||
*
|
||||
* This is a JNI function and should only be called via the
|
||||
* responsible Java part (MoteType.java).
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_se_sics_cooja_corecomm_[CLASS_NAME]_getReferenceAbsAddr(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return (jint) &referenceVar;
|
||||
}
|
234
tools/cooja/java/se/sics/cooja/mantismote/MantisMote.java
Normal file
234
tools/cooja/java/se/sics/cooja/mantismote/MantisMote.java
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* 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";
|
||||
}
|
||||
|
||||
}
|
407
tools/cooja/java/se/sics/cooja/mantismote/MantisMoteType.java
Normal file
407
tools/cooja/java/se/sics/cooja/mantismote/MantisMoteType.java
Normal file
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,793 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue