diff --git a/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java b/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java index 105fbdcac..913706c41 100644 --- a/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java +++ b/tools/cooja/java/se/sics/cooja/SectionMoteMemory.java @@ -23,22 +23,21 @@ * 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: SectionMoteMemory.java,v 1.7 2010/01/20 13:33:33 fros4943 Exp $ */ package se.sics.cooja; import java.util.ArrayList; -import java.util.Properties; +import java.util.Arrays; +import java.util.HashMap; import org.apache.log4j.Logger; /** * Represents a mote memory consisting of non-overlapping memory sections with - * variables' memory addresses. + * symbol addresses. *

- * When an unhandled memory segment is set a new section is automatically + * When an non-existing memory segment is written, a new section is automatically * created for this segment. *

* @@ -48,28 +47,36 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { private static Logger logger = Logger.getLogger(SectionMoteMemory.class); private ArrayList sections = new ArrayList(); + + /* readonly memory is never written to Contiki core, and is used to provide + * access to, for instance, strings */ + private ArrayList readonlySections = new ArrayList(); - private final Properties addresses; + private final HashMap addresses; + /* used to map Cooja's address space to native (Contiki's) addresses */ + private final int offset; + /** - * Create a new mote memory with information about which variables exist and - * their relative memory addresses. - * - * @param addresses Variable addresses + * @param addresses Symbol addresses + * @param offset Offset for internally used addresses */ - public SectionMoteMemory(Properties addresses) { + public SectionMoteMemory(HashMap addresses, int offset) { this.addresses = addresses; + this.offset = offset; } public String[] getVariableNames() { - return addresses.values().toArray(new String[0]); + return addresses.keySet().toArray(new String[0]); } public int getVariableAddress(String varName) throws UnknownVariableException { + /* Cooja address space */ if (!addresses.containsKey(varName)) { throw new UnknownVariableException(varName); } - return ((Integer) addresses.get(varName)).intValue(); + + return addresses.get(varName).intValue() + offset; } public int getIntegerLength() { @@ -81,16 +88,35 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } public byte[] getMemorySegment(int address, int size) { + /* Cooja address space */ + address -= offset; + for (MoteMemorySection section : sections) { if (section.includesAddr(address) && section.includesAddr(address + size - 1)) { return section.getMemorySegment(address, size); } } + + /* Check if in readonly section */ + for (MoteMemorySection section : readonlySections) { + if (section.includesAddr(address) + && section.includesAddr(address + size - 1)) { + return section.getMemorySegment(address, size); + } + } + return null; } + public void setMemorySegmentNative(int address, byte[] data) { + setMemorySegment(address+offset, data); + } + public void setMemorySegment(int address, byte[] data) { + /* Cooja address space */ + address -= offset; + /* TODO XXX Sections may overlap */ for (MoteMemorySection section : sections) { if (section.includesAddr(address) @@ -102,6 +128,13 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { sections.add(new MoteMemorySection(address, data)); } + public void setReadonlyMemorySegment(int address, byte[] data) { + /* Cooja address space */ + address -= offset; + + readonlySections.add(new MoteMemorySection(address, data)); + } + public int getTotalSize() { int totalSize = 0; for (MoteMemorySection section : sections) { @@ -120,67 +153,27 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } /** - * Removes a memory segment from this memory. The section containing the - * segment may be split into two sections. + * Get start address of given section in native address space. * - * @param startAddr Start address - * @param size Length - */ - public void removeSegmentFromMemory(int startAddr, int size) { - for (MoteMemorySection section : sections) { - // Find section containing segment to remove - if (section.includesAddr(startAddr) - && section.includesAddr(startAddr + size - 1)) { - MoteMemorySection oldSection = section; - - byte[] dataFirstPart = oldSection.getMemorySegment( - oldSection.startAddr, (startAddr - oldSection.startAddr)); - byte[] dataSecondPart = oldSection - .getMemorySegment(startAddr + size, (oldSection.startAddr - + oldSection.getSize() - (startAddr + size))); - - MoteMemorySection newSectionFirstPart = new MoteMemorySection( - oldSection.startAddr, dataFirstPart); - MoteMemorySection newSectionSecondPart = new MoteMemorySection( - startAddr + size, dataSecondPart); - - // Remove old section, add new sections - sections.remove(oldSection); - if (newSectionFirstPart.getSize() > 0) { - sections.add(newSectionFirstPart); - } - if (newSectionSecondPart.getSize() > 0) { - sections.add(newSectionSecondPart); - } - } - } - } - - /** - * Get start address of section at given position. - * - * @param sectionNr - * Section position + * @param sectionNr Section position * @return Start address of section */ - public int getStartAddrOfSection(int sectionNr) { + public int getSectionNativeAddress(int sectionNr) { if (sectionNr >= sections.size()) { - return 0; + return -1; } - return sections.get(sectionNr).getStartAddr(); } /** * Get size of section at given position. * - * @param sectionNr - * Section position + * @param sectionNr Section position * @return Size of section */ public int getSizeOfSection(int sectionNr) { if (sectionNr >= sections.size()) { - return 0; + return -1; } return sections.get(sectionNr).getSize(); @@ -189,8 +182,7 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { /** * Get data of section at given position. * - * @param sectionNr - * Section position + * @param sectionNr Section position * @return Data at section */ public byte[] getDataOfSection(int sectionNr) { @@ -206,42 +198,22 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } public int getIntValueOf(String varName) throws UnknownVariableException { - // Get start address of variable - if (!addresses.containsKey(varName)) { - throw new UnknownVariableException(varName); - } - int varAddr = ((Integer) addresses.get(varName)).intValue(); - + int varAddr = getVariableAddress(varName); byte[] varData = getMemorySegment(varAddr, 4); if (varData == null) { throw new UnknownVariableException(varName); } - int retVal = 0; - int pos = 0; - retVal += ((varData[pos++] & 0xFF)) << 24; - retVal += ((varData[pos++] & 0xFF)) << 16; - retVal += ((varData[pos++] & 0xFF)) << 8; - retVal += ((varData[pos++] & 0xFF)) << 0; - - /* TODO Correct for all platforms? */ - retVal = Integer.reverseBytes(retVal); - - return retVal; + return parseInt(varData); } public void setIntValueOf(String varName, int newVal) throws UnknownVariableException { - // Get start address of variable - if (!addresses.containsKey(varName)) { - throw new UnknownVariableException(varName); - } - int varAddr = ((Integer) addresses.get(varName)).intValue(); + int varAddr = getVariableAddress(varName); /* TODO Correct for all platforms? */ int newValToSet = Integer.reverseBytes(newVal); - // Create byte array int pos = 0; byte[] varData = new byte[4]; @@ -254,12 +226,7 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } public byte getByteValueOf(String varName) throws UnknownVariableException { - // Get start address of variable - if (!addresses.containsKey(varName)) { - throw new UnknownVariableException(varName); - } - int varAddr = ((Integer) addresses.get(varName)).intValue(); - + int varAddr = getVariableAddress(varName); byte[] varData = getMemorySegment(varAddr, 1); if (varData == null) { @@ -270,12 +237,7 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } public void setByteValueOf(String varName, byte newVal) throws UnknownVariableException { - // Get start address of variable - if (!addresses.containsKey(varName)) { - throw new UnknownVariableException(varName); - } - int varAddr = ((Integer) addresses.get(varName)).intValue(); - + int varAddr = getVariableAddress(varName); byte[] varData = new byte[1]; varData[0] = newVal; @@ -284,24 +246,12 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } public byte[] getByteArray(String varName, int length) throws UnknownVariableException { - // Get start address of variable - if (!addresses.containsKey(varName)) { - throw new UnknownVariableException(varName); - } - int varAddr = ((Integer) addresses.get(varName)).intValue(); - - // TODO Check if small/big-endian when coming from JNI? + int varAddr = getVariableAddress(varName); return getMemorySegment(varAddr, length); } public void setByteArray(String varName, byte[] data) throws UnknownVariableException { - // Get start address of variable - if (!addresses.containsKey(varName)) { - throw new UnknownVariableException(varName); - } - int varAddr = ((Integer) addresses.get(varName)).intValue(); - - // TODO Check if small/big-endian when coming from JNI? + int varAddr = getVariableAddress(varName); setMemorySegment(varAddr, data); } @@ -310,10 +260,9 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { * * @author Fredrik Osterlind */ - private class MoteMemorySection { + private static class MoteMemorySection { private byte[] data = null; - - private int startAddr; + private final int startAddr; /** * Create a new memory section. @@ -408,14 +357,75 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory { } public SectionMoteMemory clone() { - ArrayList clones = new ArrayList(); + ArrayList sectionsClone = new ArrayList(); for (MoteMemorySection section : sections) { - clones.add(section.clone()); + sectionsClone.add(section.clone()); } - SectionMoteMemory clone = new SectionMoteMemory(addresses); - clone.sections = clones; + SectionMoteMemory clone = new SectionMoteMemory(addresses, offset); + clone.sections = sectionsClone; + clone.readonlySections = readonlySections; return clone; - } + } + + private ArrayList polledMemories = new ArrayList(); + public void pollForMemoryChanges() { + for (PolledMemorySegments mem: polledMemories.toArray(new PolledMemorySegments[0])) { + mem.notifyIfChanged(); + } + } + + private class PolledMemorySegments { + public final MemoryMonitor mm; + public final int address; + public final int size; + private byte[] oldMem; + + public PolledMemorySegments(MemoryMonitor mm, int address, int size) { + this.mm = mm; + this.address = address; + this.size = size; + + oldMem = getMemorySegment(address, size); + } + + private void notifyIfChanged() { + byte[] newMem = getMemorySegment(address, size); + if (Arrays.equals(oldMem, newMem)) { + return; + } + + mm.memoryChanged(SectionMoteMemory.this, MemoryEventType.WRITE, address); + oldMem = newMem; + } + } + + public boolean addMemoryMonitor(int address, int size, MemoryMonitor mm) { + PolledMemorySegments t = new PolledMemorySegments(mm, address, size); + polledMemories.add(t); + return true; + } + + public void removeMemoryMonitor(int address, int size, MemoryMonitor mm) { + for (PolledMemorySegments mcm: polledMemories) { + if (mcm.mm != mm || mcm.address != address || mcm.size != size) { + continue; + } + polledMemories.remove(mcm); + break; + } + } + + public int parseInt(byte[] memorySegment) { + int retVal = 0; + int pos = 0; + retVal += ((memorySegment[pos++] & 0xFF)) << 24; + retVal += ((memorySegment[pos++] & 0xFF)) << 16; + retVal += ((memorySegment[pos++] & 0xFF)) << 8; + retVal += ((memorySegment[pos++] & 0xFF)) << 0; + + retVal = Integer.reverseBytes(retVal); + return retVal; + } } diff --git a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java index e7345e352..2130d1fcf 100644 --- a/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java +++ b/tools/cooja/java/se/sics/cooja/contikimote/ContikiMote.java @@ -152,8 +152,9 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { /* Copy mote memory from Contiki */ myType.getCoreMemory(myMemory); - + /* Poll mote interfaces */ + myMemory.pollForMemoryChanges(); myInterfaceHandler.doActiveActionsAfterTick(); myInterfaceHandler.doPassiveActionsAfterTick(); } diff --git a/tools/cooja/java/se/sics/cooja/motes/AbstractApplicationMote.java b/tools/cooja/java/se/sics/cooja/motes/AbstractApplicationMote.java index 3777520b2..437b15765 100644 --- a/tools/cooja/java/se/sics/cooja/motes/AbstractApplicationMote.java +++ b/tools/cooja/java/se/sics/cooja/motes/AbstractApplicationMote.java @@ -31,6 +31,7 @@ package se.sics.cooja.motes; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Observable; import java.util.Observer; import java.util.Properties; @@ -90,7 +91,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme public AbstractApplicationMote(MoteType moteType, Simulation sim) { setSimulation(sim); this.moteType = moteType; - this.memory = new SectionMoteMemory(new Properties()); + this.memory = new SectionMoteMemory(new HashMap(), 0); this.moteInterfaces = new MoteInterfaceHandler(this, moteType.getMoteInterfaceClasses()); this.moteInterfaces.getRadio().addObserver(radioDataObserver); requestImmediateWakeup(); @@ -145,7 +146,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme public boolean setConfigXML(Simulation simulation, Collection configXML, boolean visAvailable) { setSimulation(simulation); - this.memory = new SectionMoteMemory(new Properties()); + this.memory = new SectionMoteMemory(new HashMap(), 0); moteInterfaces.getRadio().addObserver(radioDataObserver); for (Element element : configXML) {