[cooja] memory: SectionMoteMemory implementation of MemoryInterface functions

as forwarding to encapsulated memory sections

Requires to make use of Symbol class for cooja motes, too
This commit is contained in:
Enrico Joerns 2014-07-29 17:50:11 +02:00
parent 070e0ba0fc
commit f4979ffeeb
4 changed files with 212 additions and 245 deletions

View file

@ -68,6 +68,10 @@ import org.contikios.cooja.dialogs.CompileContiki;
import org.contikios.cooja.dialogs.ContikiMoteCompileDialog;
import org.contikios.cooja.dialogs.MessageList;
import org.contikios.cooja.dialogs.MessageList.MessageContainer;
import org.contikios.cooja.mote.memory.ArrayMemory;
import org.contikios.cooja.mote.memory.MemoryInterface;
import org.contikios.cooja.mote.memory.MemoryInterface.Symbol;
import org.contikios.cooja.mote.memory.MemoryLayout;
import org.contikios.cooja.mote.memory.VarMemory;
import org.contikios.cooja.util.StringUtils;
@ -406,7 +410,7 @@ public class ContikiMoteType implements MoteType {
int commonSectionRelAddr = -1, commonSectionSize = -1;
int readonlySectionRelAddr = -1, readonlySectionSize = -1;
HashMap<String, Integer> addresses = new HashMap<String, Integer>();
HashMap<String, Symbol> addresses = new HashMap<String, Symbol>();
if (useCommand) {
/* Parse command output */
String[] output = loadCommandData(getContikiFirmwareFile());
@ -500,7 +504,7 @@ public class ContikiMoteType implements MoteType {
try {
/* Relative <-> absolute addresses offset */
int referenceVar = addresses.get("referenceVar");
int referenceVar = (int) addresses.get("referenceVar").addr;
myCoreComm.setReferenceAddress(referenceVar);
} catch (Exception e) {
throw new MoteTypeCreationException("JNI call error: " + e.getMessage(), e);
@ -518,10 +522,10 @@ public class ContikiMoteType implements MoteType {
VarMemory varMem = new VarMemory(tmp);
byte[] data = new byte[dataSectionSize];
getCoreMemory(dataSectionRelAddr, dataSectionSize, data);
tmp.setMemorySegment(dataSectionRelAddr, data);
tmp.addMemorySection("data", new ArrayMemory(dataSectionRelAddr, MemoryLayout.getNative(), data, null));
byte[] bss = new byte[bssSectionSize];
getCoreMemory(bssSectionRelAddr, bssSectionSize, bss);
tmp.setMemorySegment(bssSectionRelAddr, bss);
tmp.addMemorySection("bss", new ArrayMemory(bssSectionRelAddr, MemoryLayout.getNative(), bss, null));
offset = varMem.getIntValueOf("referenceVar");
logger.info(getContikiFirmwareFile().getName()
@ -533,23 +537,23 @@ public class ContikiMoteType implements MoteType {
byte[] initialDataSection = new byte[dataSectionSize];
getCoreMemory(dataSectionRelAddr, dataSectionSize, initialDataSection);
initialMemory.setMemorySegmentNative(dataSectionRelAddr, initialDataSection);
initialMemory.addMemorySection("data", new ArrayMemory(dataSectionRelAddr, MemoryLayout.getNative(), initialDataSection, null));
byte[] initialBssSection = new byte[bssSectionSize];
getCoreMemory(bssSectionRelAddr, bssSectionSize, initialBssSection);
initialMemory.setMemorySegmentNative(bssSectionRelAddr, initialBssSection);
initialMemory.addMemorySection("bss", new ArrayMemory(bssSectionRelAddr, MemoryLayout.getNative(), initialBssSection, null));
if (commonSectionRelAddr >= 0 && commonSectionSize > 0) {
byte[] initialCommonSection = new byte[commonSectionSize];
getCoreMemory(commonSectionRelAddr, commonSectionSize, initialCommonSection);
initialMemory.setMemorySegmentNative(commonSectionRelAddr, initialCommonSection);
initialMemory.addMemorySection("common", new ArrayMemory(commonSectionRelAddr, MemoryLayout.getNative(), initialCommonSection, null));
}
/* Read "read-only" memory */
if (readonlySectionRelAddr >= 0 && readonlySectionSize > 0) {
byte[] readonlySection = new byte[readonlySectionSize];
getCoreMemory(readonlySectionRelAddr, readonlySectionSize, readonlySection);
initialMemory.setReadonlyMemorySegment(readonlySectionRelAddr+offset, readonlySection);
initialMemory.addMemorySection("readonly", new ArrayMemory(readonlySectionRelAddr, MemoryLayout.getNative(), readonlySection, true, null));
}
}
@ -580,11 +584,8 @@ public class ContikiMoteType implements MoteType {
* Memory to set
*/
public void getCoreMemory(SectionMoteMemory mem) {
for (int i = 0; i < mem.getNumberOfSections(); i++) {
getCoreMemory(
(int) mem.getSectionNativeAddress(i) /* native address space */,
mem.getSizeOfSection(i),
mem.getDataOfSection(i));
for (MemoryInterface section : mem.getSections().values()) {
getCoreMemory((int) section.getStartAddr(), section.getTotalSize(), section.getMemory());
}
}
@ -600,11 +601,8 @@ public class ContikiMoteType implements MoteType {
* New memory
*/
public void setCoreMemory(SectionMoteMemory mem) {
for (int i = 0; i < mem.getNumberOfSections(); i++) {
setCoreMemory(
(int) mem.getSectionNativeAddress(i) /* native address space */,
mem.getSizeOfSection(i),
mem.getDataOfSection(i));
for (MemoryInterface section : mem.getSections().values()) {
setCoreMemory((int) section.getStartAddr(), section.getTotalSize(), section.getMemory());
}
}
@ -621,16 +619,16 @@ public class ContikiMoteType implements MoteType {
* @param varAddresses
* Properties that should contain the name to addresses mappings.
*/
public static boolean parseMapFileData(String[] mapFileData, HashMap<String, Integer> varAddresses) {
public static boolean parseMapFileData(String[] mapFileData, HashMap<String, Symbol> varAddresses) {
String[] varNames = getMapFileVarNames(mapFileData);
if (varNames == null || varNames.length == 0) {
return false;
}
for (String varName : varNames) {
int varAddress = getMapFileVarAddress(mapFileData, varName, varAddresses);
int varAddress = getMapFileVarAddress(mapFileData, varName);
if (varAddress > 0) {
varAddresses.put(varName, new Integer(varAddress));
varAddresses.put(varName, new Symbol(Symbol.Type.VARIABLE, varName, varAddress, 1));
} else {
logger.warn("Parsed Contiki variable '" + varName
+ "' but could not find address");
@ -647,7 +645,7 @@ public class ContikiMoteType implements MoteType {
* @param output Command output
* @param addresses Variable addresses mappings
*/
public static boolean parseCommandData(String[] output, HashMap<String, Integer> addresses) {
public static boolean parseCommandData(String[] output, HashMap<String, Symbol> addresses) {
int nrNew = 0, nrOld = 0, nrMismatch = 0;
Pattern pattern
@ -663,9 +661,9 @@ public class ContikiMoteType implements MoteType {
if (!addresses.containsKey(symbol)) {
nrNew++;
addresses.put(symbol, new Integer(address));
addresses.put(symbol, new Symbol(Symbol.Type.VARIABLE, symbol, address, 1));
} else {
int oldAddress = addresses.get(symbol);
int oldAddress = (int) addresses.get(symbol).addr;
if (oldAddress != address) {
/*logger.warn("Warning, command response not matching previous entry of: "
+ varName);*/
@ -814,11 +812,7 @@ public class ContikiMoteType implements MoteType {
* @param varName Name of variable
* @return Relative memory address of variable or -1 if not found
*/
private static int getMapFileVarAddress(String[] mapFileData, String varName, HashMap<String, Integer> varAddresses) {
Integer varAddrInteger;
if ((varAddrInteger = varAddresses.get(varName)) != null) {
return varAddrInteger.intValue();
}
private static int getMapFileVarAddress(String[] mapFileData, String varName) {
String regExp = Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_1")
+ varName
@ -826,9 +820,7 @@ public class ContikiMoteType implements MoteType {
String retString = getFirstMatchGroup(mapFileData, regExp, 1);
if (retString != null) {
varAddrInteger = Integer.parseInt(retString.trim(), 16);
varAddresses.put(varName, varAddrInteger);
return varAddrInteger.intValue();
return Integer.parseInt(retString.trim(), 16);
}
else {
return -1;

View file

@ -68,6 +68,7 @@ import org.contikios.cooja.Cooja;
import org.contikios.cooja.MoteType.MoteTypeCreationException;
import org.contikios.cooja.mote.memory.SectionMoteMemory;
import org.contikios.cooja.contikimote.ContikiMoteType;
import org.contikios.cooja.mote.memory.MemoryInterface.Symbol;
import org.contikios.cooja.mote.memory.VarMemory;
/* TODO Test common section */
@ -142,7 +143,7 @@ public class ConfigurationWizard extends JDialog {
private static File cLibraryFile;
private static String javaLibraryName;
private static CoreComm javaLibrary;
private static HashMap<String, Integer> addresses;
private static HashMap<String, Symbol> addresses;
private static int relDataSectionAddr;
private static int dataSectionSize;
private static int relBssSectionAddr;
@ -758,7 +759,7 @@ public class ConfigurationWizard extends JDialog {
}
testOutput.addMessage("### Parsing map file data for addresses");
addresses = new HashMap<String, Integer>();
addresses = new HashMap<String, Symbol>();
boolean parseOK = ContikiMoteType.parseMapFileData(mapData, addresses);
if (!parseOK) {
testOutput.addMessage("### Error: Failed parsing map file data", MessageList.ERROR);
@ -838,7 +839,7 @@ public class ConfigurationWizard extends JDialog {
}
testOutput.addMessage("### Parsing command output for addresses");
addresses = new HashMap<String, Integer>();
addresses = new HashMap<String, Symbol>();
boolean parseOK = ContikiMoteType.parseCommandData(commandData, addresses);
if (!parseOK) {
testOutput.addMessage("### Error: Failed parsing command output", MessageList.ERROR);
@ -936,7 +937,7 @@ public class ConfigurationWizard extends JDialog {
testOutput.addMessage("Could not find address of referenceVar", MessageList.ERROR);
return false;
}
int relRefAddress = addresses.get("referenceVar");
int relRefAddress = (int) addresses.get("referenceVar").addr;
javaLibrary.setReferenceAddress(relRefAddress);
testOutput.addMessage("### Creating data and BSS memory sections");

View file

@ -1,4 +1,5 @@
/*
* Copyright (c) 2014, TU Braunschweig. All rights reserved.
* Copyright (c) 2006, Swedish Institute of Computer Science. All rights
* reserved.
*
@ -33,66 +34,90 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.contikios.cooja.mote.memory.MemoryInterface;
import org.contikios.cooja.mote.memory.MemoryLayout;
/**
* Represents a mote memory consisting of non-overlapping memory sections with
* symbol addresses.
* <p>
* When an non-existing memory segment is written, a new section is automatically
* created for this segment.
* Every section must implement MemoyInterface.
* <p>
* Implements MemoryInterface by forwarding calls to available sections or returning
* an error if no section is available.
*
* @author Fredrik Osterlind
* @author Enrico Jorns
*/
public class SectionMoteMemory implements MemoryInterface {
private static Logger logger = Logger.getLogger(SectionMoteMemory.class);
private static final boolean DEBUG = logger.isDebugEnabled();
private ArrayList<MoteMemorySection> sections = new ArrayList<MoteMemorySection>();
/* 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 Map<String, MemoryInterface> sections = new HashMap<>();
private final HashMap<String, Integer> addresses;
private final Map<String, Symbol> symbols;
private MemoryLayout memLayout;
private long startAddr = Long.MAX_VALUE;
/* used to map Cooja's address space to native (Contiki's) addresses */
private final int offset;
/**
* @param addresses Symbol addresses
* @param symbols Symbol addresses
* @param offset Offset for internally used addresses
*/
public SectionMoteMemory(HashMap<String, Integer> addresses, int offset) {
this.addresses = addresses;
public SectionMoteMemory(Map<String, Symbol> symbols, int offset) {
this.symbols = symbols;
this.offset = offset;
}
/**
* Adds a section to this memory.
*
* A new section will be checked for address overlap with existing sections.
*
* @param name
* @param section
* @return true if adding succeeded, false otherwise
*/
public boolean addMemorySection(String name ,MemoryInterface section) {
@Override
public void clearMemory() {
sections.clear();
}
public void setMemorySegmentNative(int address, byte[] data) {
setMemorySegment(address+offset, 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) {
totalSize += section.getSize();
if (section == null) {
return false;
}
return totalSize;
/* Cooja address space */
for (MemoryInterface sec : sections.values()) {
/* check for overlap with existing region */
if ((section.getStartAddr() <= sec.getStartAddr() + sec.getTotalSize() - 1)
&& (section.getStartAddr() + section.getTotalSize() - 1 >= sec.getStartAddr())) {
logger.error(String.format(
"Failed adding section '%s' of size %d @0x%x",
name,
section.getTotalSize(),
section.getStartAddr()));
return false;
}
/* Min start address is main start address */
startAddr = sec.getStartAddr() < startAddr ? sec.getStartAddr() : startAddr;
/* Layout is last layout. XXX Check layout consistency? */
memLayout = section.getLayout();
}
sections.put(name, section);
if (section.getSymbolMap() != null) {
for (String s : section.getSymbolMap().keySet()) {
// XXX how to handle double names here?
symbols.put(s, section.getSymbolMap().get(s));
}
}
if (DEBUG) {
logger.debug(String.format(
"Added section '%s' of size %d @0x%x",
name,
section.getTotalSize(),
section.getStartAddr()));
}
return true;
}
/**
@ -105,44 +130,69 @@ public class SectionMoteMemory implements MemoryInterface {
}
/**
* Get start address of given section in native address space.
*
* @param sectionNr Section position
* @return Start address of section
* Returns memory section of this memory.
* @param name Name of section
* @return memory section
*/
public int getSectionNativeAddress(int sectionNr) {
if (sectionNr >= sections.size()) {
return -1;
public MemoryInterface getSection(String name) {
for (String memsec : sections.keySet()) {
if (memsec.equals(name)) {
return sections.get(name);
}
}
return sections.get(sectionNr).getStartAddr();
logger.warn("Section '" + name + "' not found");
return null;
}
/**
* Get size of section at given position.
*
* @param sectionNr Section position
* @return Size of section
* Return all sections of this memory.
* @return All memory sections
*/
public int getSizeOfSection(int sectionNr) {
if (sectionNr >= sections.size()) {
return -1;
}
return sections.get(sectionNr).getSize();
public Map<String, MemoryInterface> getSections() {
return sections;
}
/**
* Get data of section at given position.
* True if given address is part of this memory section.
*
* @param sectionNr Section position
* @return Data at section
* @param intf
* @param addr
* Address
* @return True if given address is part of this memory section, false
* otherwise
*/
public byte[] getDataOfSection(int sectionNr) {
if (sectionNr >= sections.size()) {
return null;
}
public static boolean includesAddr(MemoryInterface intf, long addr) {
return addr >= intf.getStartAddr() && addr < (intf.getStartAddr() + intf.getTotalSize());
}
return sections.get(sectionNr).getData();
/**
* True if the whole address range specified by address and size
* lies inside this memory section.
*
* @param intf
* @param addr Start address of segment to check
* @param size Size of segment to check
*
* @return True if given address range lies inside address range of this
* section
*/
public static boolean inSection(MemoryInterface intf, long addr, int size) {
return addr >= intf.getStartAddr() && addr + size <= intf.getStartAddr() + intf.getTotalSize();
}
@Override
public void clearMemory() {
sections.clear();
}
@Override
public int getTotalSize() {
int totalSize = 0;
for (MemoryInterface section : sections.values()) {
totalSize += section.getTotalSize();
}
return totalSize;
}
@Override
@ -150,153 +200,106 @@ public class SectionMoteMemory implements MemoryInterface {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Returns memory segment from section matching segment given by address and size
* @param address start address of segment to get
* @param size size of segmetn to get
* @return Array containing data of segment
* @throws MoteMemoryException if no single section containing the given address range was found
*/
@Override
public byte[] getMemorySegment(long addr, int size) throws MoteMemoryException {
throw new UnsupportedOperationException("Not supported yet.");
public byte[] getMemorySegment(long address, int size) throws MoteMemoryException {
for (MemoryInterface section : sections.values()) {
if (includesAddr(section, address) && includesAddr(section, address + size - 1)) {
return section.getMemorySegment(address, size);
}
}
throw new MoteMemoryException(
"Getting memory segment [0x%x,0x%x] failed: No section available",
address, address + size - 1);
}
/**
* Sets memory segment of section matching segment given by address and size.
* @param address start address of segment to set
* @param data data to set
* @throws MoteMemoryException if no single section containing the given address range was found
* or memory is readonly.
*/
@Override
public void setMemorySegment(long addr, byte[] data) throws MoteMemoryException {
throw new UnsupportedOperationException("Not supported yet.");
public void setMemorySegment(long address, byte[] data) throws MoteMemoryException {
for (MemoryInterface section : sections.values()) {
if (inSection(section, address, data.length)) {
section.setMemorySegment(address, data);
if (DEBUG) {
logger.debug(String.format(
"Wrote memory segment [0x%x,0x%x]",
address, address + data.length - 1));
}
return;
}
}
throw new MoteMemoryException(
"Writing memory segment [0x%x,0x%x] failed: No section available",
address, address + data.length - 1);
}
public void setMemorySegmentNative(long address, byte[] data) throws MoteMemoryException {
setMemorySegment(address + offset, data);
}
@Override
public long getStartAddr() {
throw new UnsupportedOperationException("Not supported yet.");
return startAddr;
}
@Override
public Map<String, Symbol> getSymbolMap() {
throw new UnsupportedOperationException("Not supported yet.");
return symbols;
}
@Override
public MemoryLayout getLayout() {
throw new UnsupportedOperationException("Not supported yet.");
return memLayout;
}
@Override
public boolean addSegmentMonitor(SegmentMonitor.EventType flag, long address, int size, SegmentMonitor monitor) {
throw new UnsupportedOperationException("Not supported yet.");
PolledMemorySegments t = new PolledMemorySegments(monitor, (int) address, size);
polledMemories.add(t);
return true;
}
@Override
public boolean removeSegmentMonitor(long address, int size, SegmentMonitor monitor) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* A memory section contains a byte array and a start address.
*
* @author Fredrik Osterlind
*/
private static class MoteMemorySection {
private byte[] data = null;
private final int startAddr;
/**
* Create a new memory section.
*
* @param startAddr
* Start address of section
* @param data
* Data of section
*/
public MoteMemorySection(int startAddr, byte[] data) {
this.startAddr = startAddr;
this.data = data;
}
/**
* Returns start address of this memory section.
*
* @return Start address
*/
public int getStartAddr() {
return startAddr;
}
/**
* Returns size of this memory section.
*
* @return Size
*/
public int getSize() {
return data.length;
}
/**
* Returns the entire byte array which defines this section.
*
* @return Byte array
*/
public byte[] getData() {
return data;
}
/**
* True if given address is part of this memory section.
*
* @param addr
* Address
* @return True if given address is part of this memory section, false
* otherwise
*/
public boolean includesAddr(int addr) {
if (data == null) {
return false;
for (PolledMemorySegments mcm: polledMemories) {
if (mcm.mm != monitor || mcm.address != address || mcm.size != size) {
continue;
}
return (addr >= startAddr && addr < (startAddr + data.length));
}
/**
* Returns memory segment.
*
* @param addr
* Start address of memory segment
* @param size
* Size of memory segment
* @return Memory segment
*/
public byte[] getMemorySegment(int addr, int size) {
byte[] ret = new byte[size];
System.arraycopy(data, addr - startAddr, ret, 0, size);
return ret;
}
/**
* Sets a memory segment.
*
* @param addr
* Start of memory segment
* @param data
* Data of memory segment
*/
public void setMemorySegment(int addr, byte[] data) {
System.arraycopy(data, 0, this.data, addr - startAddr, data.length);
}
@Override
public MoteMemorySection clone() {
byte[] dataClone = new byte[data.length];
System.arraycopy(data, 0, dataClone, 0, data.length);
MoteMemorySection clone = new MoteMemorySection(startAddr, dataClone);
return clone;
polledMemories.remove(mcm);
return true;
}
return false;
}
/** Copies seciton memory to new (array backed) one
* @return Cloned memory
*/
@Override
public SectionMoteMemory clone() {
ArrayList<MoteMemorySection> sectionsClone = new ArrayList<MoteMemorySection>();
for (MoteMemorySection section : sections) {
sectionsClone.add(section.clone());
}
SectionMoteMemory clone = new SectionMoteMemory(addresses, offset);
clone.sections = sectionsClone;
clone.readonlySections = readonlySections;
SectionMoteMemory clone = new SectionMoteMemory(symbols, offset);
for (String secname : sections.keySet()) {
// Copy section memory to new ArrayMemory
MemoryInterface section = sections.get(secname);
MemoryInterface cpmem = new ArrayMemory(section.getStartAddr(), section.getLayout(), section.getMemory().clone(), section.getSymbolMap());
clone.addMemorySection(secname, cpmem);
}
return clone;
}
@ -333,34 +336,4 @@ public class SectionMoteMemory implements MemoryInterface {
}
}
// @Override
public boolean addMemoryMonitor(int address, int size, SegmentMonitor mm) {
PolledMemorySegments t = new PolledMemorySegments(mm, address, size);
polledMemories.add(t);
return true;
}
// @Override
public void removeMemoryMonitor(int address, int size, SegmentMonitor mm) {
for (PolledMemorySegments mcm: polledMemories) {
if (mcm.mm != mm || mcm.address != address || mcm.size != size) {
continue;
}
polledMemories.remove(mcm);
break;
}
}
// @Override
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

@ -47,6 +47,7 @@ import org.contikios.cooja.interfaces.ApplicationRadio;
import org.contikios.cooja.interfaces.ApplicationSerialPort;
import org.contikios.cooja.interfaces.Radio;
import org.contikios.cooja.mote.memory.MemoryInterface;
import org.contikios.cooja.mote.memory.MemoryInterface.Symbol;
import org.contikios.cooja.mote.memory.MemoryLayout;
/**
@ -91,7 +92,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme
setSimulation(sim);
this.moteType = moteType;
MemoryLayout.getNative();
this.memory = new SectionMoteMemory(new HashMap<String, Integer>(), 0);
this.memory = new SectionMoteMemory(new HashMap<String, Symbol>(), 0);
this.moteInterfaces = new MoteInterfaceHandler(this, moteType.getMoteInterfaceClasses());
this.moteInterfaces.getRadio().addObserver(radioDataObserver);
requestImmediateWakeup();
@ -151,7 +152,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme
public boolean setConfigXML(Simulation simulation,
Collection<Element> configXML, boolean visAvailable) {
setSimulation(simulation);
this.memory = new SectionMoteMemory(new HashMap<String, Integer>(), 0);
this.memory = new SectionMoteMemory(new HashMap<String, Symbol>(), 0);
moteInterfaces.getRadio().addObserver(radioDataObserver);
for (Element element : configXML) {