added support for mapping Cooja motes' and Contiki's address

implemented poll-based memory monitor support
improved code
This commit is contained in:
Fredrik Osterlind 2012-03-09 14:56:53 +01:00
parent 129a854b54
commit 85323adc1e
3 changed files with 133 additions and 121 deletions

View File

@ -23,22 +23,21 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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; package se.sics.cooja;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Properties; import java.util.Arrays;
import java.util.HashMap;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
* Represents a mote memory consisting of non-overlapping memory sections with * Represents a mote memory consisting of non-overlapping memory sections with
* variables' memory addresses. * symbol addresses.
* <p> * <p>
* 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. * created for this segment.
* <p> * <p>
* *
@ -49,27 +48,35 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
private ArrayList<MoteMemorySection> sections = new ArrayList<MoteMemorySection>(); private ArrayList<MoteMemorySection> sections = new ArrayList<MoteMemorySection>();
private final Properties addresses; /* readonly memory is never written to Contiki core, and is used to provide
* access to, for instance, strings */
private ArrayList<MoteMemorySection> readonlySections = new ArrayList<MoteMemorySection>();
private final HashMap<String, Integer> 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 * @param addresses Symbol addresses
* their relative memory addresses. * @param offset Offset for internally used addresses
*
* @param addresses Variable addresses
*/ */
public SectionMoteMemory(Properties addresses) { public SectionMoteMemory(HashMap<String, Integer> addresses, int offset) {
this.addresses = addresses; this.addresses = addresses;
this.offset = offset;
} }
public String[] getVariableNames() { public String[] getVariableNames() {
return addresses.values().toArray(new String[0]); return addresses.keySet().toArray(new String[0]);
} }
public int getVariableAddress(String varName) throws UnknownVariableException { public int getVariableAddress(String varName) throws UnknownVariableException {
/* Cooja address space */
if (!addresses.containsKey(varName)) { if (!addresses.containsKey(varName)) {
throw new UnknownVariableException(varName); throw new UnknownVariableException(varName);
} }
return ((Integer) addresses.get(varName)).intValue();
return addresses.get(varName).intValue() + offset;
} }
public int getIntegerLength() { public int getIntegerLength() {
@ -81,16 +88,35 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
} }
public byte[] getMemorySegment(int address, int size) { public byte[] getMemorySegment(int address, int size) {
/* Cooja address space */
address -= offset;
for (MoteMemorySection section : sections) { for (MoteMemorySection section : sections) {
if (section.includesAddr(address) if (section.includesAddr(address)
&& section.includesAddr(address + size - 1)) { && section.includesAddr(address + size - 1)) {
return section.getMemorySegment(address, size); 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; return null;
} }
public void setMemorySegmentNative(int address, byte[] data) {
setMemorySegment(address+offset, data);
}
public void setMemorySegment(int address, byte[] data) { public void setMemorySegment(int address, byte[] data) {
/* Cooja address space */
address -= offset;
/* TODO XXX Sections may overlap */ /* TODO XXX Sections may overlap */
for (MoteMemorySection section : sections) { for (MoteMemorySection section : sections) {
if (section.includesAddr(address) if (section.includesAddr(address)
@ -102,6 +128,13 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
sections.add(new MoteMemorySection(address, data)); 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() { public int getTotalSize() {
int totalSize = 0; int totalSize = 0;
for (MoteMemorySection section : sections) { 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 * Get start address of given section in native address space.
* segment may be split into two sections.
* *
* @param startAddr Start address * @param sectionNr Section position
* @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
* @return Start address of section * @return Start address of section
*/ */
public int getStartAddrOfSection(int sectionNr) { public int getSectionNativeAddress(int sectionNr) {
if (sectionNr >= sections.size()) { if (sectionNr >= sections.size()) {
return 0; return -1;
} }
return sections.get(sectionNr).getStartAddr(); return sections.get(sectionNr).getStartAddr();
} }
/** /**
* Get size of section at given position. * Get size of section at given position.
* *
* @param sectionNr * @param sectionNr Section position
* Section position
* @return Size of section * @return Size of section
*/ */
public int getSizeOfSection(int sectionNr) { public int getSizeOfSection(int sectionNr) {
if (sectionNr >= sections.size()) { if (sectionNr >= sections.size()) {
return 0; return -1;
} }
return sections.get(sectionNr).getSize(); return sections.get(sectionNr).getSize();
@ -189,8 +182,7 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
/** /**
* Get data of section at given position. * Get data of section at given position.
* *
* @param sectionNr * @param sectionNr Section position
* Section position
* @return Data at section * @return Data at section
*/ */
public byte[] getDataOfSection(int sectionNr) { public byte[] getDataOfSection(int sectionNr) {
@ -206,42 +198,22 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
} }
public int getIntValueOf(String varName) throws UnknownVariableException { public int getIntValueOf(String varName) throws UnknownVariableException {
// Get start address of variable int varAddr = getVariableAddress(varName);
if (!addresses.containsKey(varName)) {
throw new UnknownVariableException(varName);
}
int varAddr = ((Integer) addresses.get(varName)).intValue();
byte[] varData = getMemorySegment(varAddr, 4); byte[] varData = getMemorySegment(varAddr, 4);
if (varData == null) { if (varData == null) {
throw new UnknownVariableException(varName); throw new UnknownVariableException(varName);
} }
int retVal = 0; return parseInt(varData);
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;
} }
public void setIntValueOf(String varName, int newVal) throws UnknownVariableException { public void setIntValueOf(String varName, int newVal) throws UnknownVariableException {
// Get start address of variable int varAddr = getVariableAddress(varName);
if (!addresses.containsKey(varName)) {
throw new UnknownVariableException(varName);
}
int varAddr = ((Integer) addresses.get(varName)).intValue();
/* TODO Correct for all platforms? */ /* TODO Correct for all platforms? */
int newValToSet = Integer.reverseBytes(newVal); int newValToSet = Integer.reverseBytes(newVal);
// Create byte array
int pos = 0; int pos = 0;
byte[] varData = new byte[4]; byte[] varData = new byte[4];
@ -254,12 +226,7 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
} }
public byte getByteValueOf(String varName) throws UnknownVariableException { public byte getByteValueOf(String varName) throws UnknownVariableException {
// Get start address of variable int varAddr = getVariableAddress(varName);
if (!addresses.containsKey(varName)) {
throw new UnknownVariableException(varName);
}
int varAddr = ((Integer) addresses.get(varName)).intValue();
byte[] varData = getMemorySegment(varAddr, 1); byte[] varData = getMemorySegment(varAddr, 1);
if (varData == null) { if (varData == null) {
@ -270,12 +237,7 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
} }
public void setByteValueOf(String varName, byte newVal) throws UnknownVariableException { public void setByteValueOf(String varName, byte newVal) throws UnknownVariableException {
// Get start address of variable int varAddr = getVariableAddress(varName);
if (!addresses.containsKey(varName)) {
throw new UnknownVariableException(varName);
}
int varAddr = ((Integer) addresses.get(varName)).intValue();
byte[] varData = new byte[1]; byte[] varData = new byte[1];
varData[0] = newVal; varData[0] = newVal;
@ -284,24 +246,12 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
} }
public byte[] getByteArray(String varName, int length) throws UnknownVariableException { public byte[] getByteArray(String varName, int length) throws UnknownVariableException {
// Get start address of variable int varAddr = getVariableAddress(varName);
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?
return getMemorySegment(varAddr, length); return getMemorySegment(varAddr, length);
} }
public void setByteArray(String varName, byte[] data) throws UnknownVariableException { public void setByteArray(String varName, byte[] data) throws UnknownVariableException {
// Get start address of variable int varAddr = getVariableAddress(varName);
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?
setMemorySegment(varAddr, data); setMemorySegment(varAddr, data);
} }
@ -310,10 +260,9 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
* *
* @author Fredrik Osterlind * @author Fredrik Osterlind
*/ */
private class MoteMemorySection { private static class MoteMemorySection {
private byte[] data = null; private byte[] data = null;
private final int startAddr;
private int startAddr;
/** /**
* Create a new memory section. * Create a new memory section.
@ -408,14 +357,75 @@ public class SectionMoteMemory implements MoteMemory, AddressMemory {
} }
public SectionMoteMemory clone() { public SectionMoteMemory clone() {
ArrayList<MoteMemorySection> clones = new ArrayList<MoteMemorySection>(); ArrayList<MoteMemorySection> sectionsClone = new ArrayList<MoteMemorySection>();
for (MoteMemorySection section : sections) { for (MoteMemorySection section : sections) {
clones.add(section.clone()); sectionsClone.add(section.clone());
} }
SectionMoteMemory clone = new SectionMoteMemory(addresses); SectionMoteMemory clone = new SectionMoteMemory(addresses, offset);
clone.sections = clones; clone.sections = sectionsClone;
clone.readonlySections = readonlySections;
return clone; return clone;
} }
private ArrayList<PolledMemorySegments> polledMemories = new ArrayList<PolledMemorySegments>();
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;
}
} }

View File

@ -154,6 +154,7 @@ public class ContikiMote extends AbstractWakeupMote implements Mote {
myType.getCoreMemory(myMemory); myType.getCoreMemory(myMemory);
/* Poll mote interfaces */ /* Poll mote interfaces */
myMemory.pollForMemoryChanges();
myInterfaceHandler.doActiveActionsAfterTick(); myInterfaceHandler.doActiveActionsAfterTick();
myInterfaceHandler.doPassiveActionsAfterTick(); myInterfaceHandler.doPassiveActionsAfterTick();
} }

View File

@ -31,6 +31,7 @@ package se.sics.cooja.motes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Properties; import java.util.Properties;
@ -90,7 +91,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme
public AbstractApplicationMote(MoteType moteType, Simulation sim) { public AbstractApplicationMote(MoteType moteType, Simulation sim) {
setSimulation(sim); setSimulation(sim);
this.moteType = moteType; this.moteType = moteType;
this.memory = new SectionMoteMemory(new Properties()); this.memory = new SectionMoteMemory(new HashMap<String, Integer>(), 0);
this.moteInterfaces = new MoteInterfaceHandler(this, moteType.getMoteInterfaceClasses()); this.moteInterfaces = new MoteInterfaceHandler(this, moteType.getMoteInterfaceClasses());
this.moteInterfaces.getRadio().addObserver(radioDataObserver); this.moteInterfaces.getRadio().addObserver(radioDataObserver);
requestImmediateWakeup(); requestImmediateWakeup();
@ -145,7 +146,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme
public boolean setConfigXML(Simulation simulation, public boolean setConfigXML(Simulation simulation,
Collection<Element> configXML, boolean visAvailable) { Collection<Element> configXML, boolean visAvailable) {
setSimulation(simulation); setSimulation(simulation);
this.memory = new SectionMoteMemory(new Properties()); this.memory = new SectionMoteMemory(new HashMap<String, Integer>(), 0);
moteInterfaces.getRadio().addObserver(radioDataObserver); moteInterfaces.getRadio().addObserver(radioDataObserver);
for (Element element : configXML) { for (Element element : configXML) {