diff --git a/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/AvrMoteMemory.java b/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/AvrMoteMemory.java index 0dbdbb45d..61cd12b8c 100644 --- a/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/AvrMoteMemory.java +++ b/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/AvrMoteMemory.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014, TU Braunschweig. All rights reserved. * Copyright (c) 2009, Swedish Institute of Computer Science. All rights * reserved. * @@ -28,158 +29,196 @@ package org.contikios.cooja.avrmote; -import java.util.ArrayList; -import java.util.Iterator; import org.apache.log4j.Logger; -import org.contikios.cooja.AddressMemory; -import org.contikios.cooja.MoteMemory; import avrora.arch.avr.AVRProperties; import avrora.core.SourceMapping; import avrora.core.SourceMapping.Location; import avrora.sim.AtmelInterpreter; import avrora.sim.Simulator.Watch; +import avrora.sim.State; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor.EventType; +import org.contikios.cooja.mote.memory.MemoryLayout; /** - * @author Joakim Eriksson + * @author Joakim Eriksson, Fredrik Osterlind, David Kopf, Enrico Jorns */ -public class AvrMoteMemory implements MoteMemory, AddressMemory { - private static Logger logger = Logger.getLogger(AvrMoteMemory.class); +public class AvrMoteMemory implements MemoryInterface { + private static Logger logger = Logger.getLogger(AvrMoteMemory.class); + private static final boolean DEBUG = logger.isDebugEnabled(); + + private final SourceMapping memoryMap; + private final AVRProperties avrProperties; + private final AtmelInterpreter interpreter; + private final ArrayList memoryMonitors = new ArrayList<>(); + private final MemoryLayout memLayout = new MemoryLayout(ByteOrder.LITTLE_ENDIAN, MemoryLayout.ARCH_8BIT, 2); + + private boolean coojaIsAccessingMemory; - private SourceMapping memoryMap; - private AtmelInterpreter interpreter; - private AVRProperties avrProperties; - public AvrMoteMemory(SourceMapping map, AVRProperties avrProperties, AtmelInterpreter interpreter) { memoryMap = map; this.interpreter = interpreter; this.avrProperties = avrProperties; } - public void insertWatch(Watch w, int address) { - interpreter.getSimulator().insertWatch(w, address); - } - - public void clearMemory() { - logger.fatal("not implemented"); + @Override + public int getTotalSize() { + return avrProperties.sram_size; + } + + @Override + public byte[] getMemory() throws MoteMemoryException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public byte[] getMemorySegment(long address, int size) throws MoteMemoryException { + /*logger.info("getMemorySegment(" + String.format("0x%04x", address) + + ", " + size + ")");*/ + if (!accessInRange(address, size)) { + throw new MoteMemoryException( + "Getting memory segment [0x%x,0x%x] failed: Out of range", + address, address + size - 1); } - public byte[] getMemorySegment(int address, int size) { - logger.fatal("getMemorySegment is not implemented"); - return null; + /* XXX Unsure whether this is the appropriate method to use, as it + * triggers memoryRead monitor. Right now I'm using a flag to indicate + * that Cooja (as opposed to Contiki) read the memory, to avoid infinite + * recursion. */ + coojaIsAccessingMemory = true; + byte[] data = new byte[(int) size]; + for (int i = 0; i < size; i++) { + data[i] = (byte) (interpreter.getDataByte((int) address + i) & 0xff); + } + coojaIsAccessingMemory = false; + return data; + } + + @Override + public void setMemorySegment(long address, byte[] data) throws MoteMemoryException { + if (!accessInRange(address, data.length)) { + throw new MoteMemoryException( + "Writing memory segment [0x%x,0x%x] failed: Out of range", + address, address + data.length - 1); } - public int getTotalSize() { - return 0; + /* XXX See comment in getMemorySegment. */ + coojaIsAccessingMemory = true; + for (int i = 0; i < data.length; i++) { + interpreter.writeDataByte((int) address + i, data[i]); + } + coojaIsAccessingMemory = false; + if (DEBUG) { + logger.debug(String.format( + "Wrote memory segment [0x%x,0x%x]", + address, address + data.length - 1)); + } + } + + @Override + public void clearMemory() { + setMemorySegment(0L, new byte[avrProperties.sram_size]); + } + + private boolean accessInRange(long address, int size) { + return (address >= 0) && (address + size <= avrProperties.sram_size); + } + + @Override + public long getStartAddr() { + return 0;// XXX + } + + @Override + public Map getSymbolMap() { + // XXX do not fetch in function! + Map symbols = new HashMap<>(); + for (Iterator iter = memoryMap.getIterator(); iter.hasNext();) { + Location loc = iter.next(); + if (loc == null || (loc.section.equals(".text"))) { + continue; + } + symbols.put(loc.name, new Symbol(Symbol.Type.VARIABLE, loc.name, loc.section, loc.vma_addr & 0x7fffff, -1)); + } + return symbols; + } + + + @Override + public MemoryLayout getLayout() { + return memLayout; + } + + class AvrByteMonitor extends Watch.Empty { + + /** start address to monitor */ + final long address; + /** size to monitor */ + final int size; + /** Segment monitor to notify */ + final SegmentMonitor mm; + /** MonitorType we are listening to */ + final EventType flag; + + public AvrByteMonitor(long address, int size, SegmentMonitor mm, EventType flag) { + this.address = address; + this.size = size; + this.mm = mm; + this.flag = flag; } - public void setMemorySegment(int address, byte[] data) { - logger.fatal("setMemorySegment is not implemented"); + @Override + public void fireAfterRead(State state, int data_addr, byte value) { + if (flag == EventType.WRITE || coojaIsAccessingMemory) { + return; + } + mm.memoryChanged(AvrMoteMemory.this, EventType.READ, data_addr); } - public byte[] getByteArray(String varName, int length) - throws UnknownVariableException { - return null; + @Override + public void fireAfterWrite(State state, int data_addr, byte value) { + if (flag == EventType.READ || coojaIsAccessingMemory) { + return; + } + mm.memoryChanged(AvrMoteMemory.this, EventType.WRITE, data_addr); } + } - public byte getByteValueOf(String varName) throws UnknownVariableException { - return (byte) getValueOf(varName, 1); + @Override + public boolean addSegmentMonitor(EventType flag, long address, int size, SegmentMonitor mm) { + AvrByteMonitor mon = new AvrByteMonitor(address, size, mm, flag); + + memoryMonitors.add(mon); + /* logger.debug("Added AvrByteMonitor " + Integer.toString(mon.hashCode()) + " for addr " + mon.address + " size " + mon.size + " with watch" + mon.watch); */ + + /* Add byte monitor (watch) for every byte in range */ + for (int idx = 0; idx < mon.size; idx++) { + interpreter.getSimulator().insertWatch(mon, (int) mon.address + idx); + /* logger.debug("Inserted watch " + Integer.toString(mon.watch.hashCode()) + " for " + (mon.address + idx)); */ } - - private int getValueOf(String varName, int len) throws UnknownVariableException { - Location mem = memoryMap.getLocation(varName); - if (mem == null) throw new UnknownVariableException("Variable does not exist: " + varName); + return true; + } - System.out.println("Variable:" + varName + " in section: " + mem.section); - System.out.println("LMA: " + Integer.toHexString(mem.lma_addr)); - System.out.println("VMA: " + Integer.toHexString(mem.vma_addr)); - - System.out.println("Data: " + interpreter.getDataByte(mem.lma_addr & 0xfffff)); - System.out.println("Flash: " + interpreter.getFlashByte(mem.lma_addr & 0xfffff)); - int data = 0; - if (mem.vma_addr > 0xfffff) { - for (int i = 0; i < len; i++) { - data = (data << 8) + (interpreter.getDataByte((mem.vma_addr & 0xfffff) + len - i - 1) & 0xff); - System.out.println("Read byte: " + interpreter.getDataByte((mem.vma_addr & 0xfffff) + i) + - " => " + data); - } - } else { - for (int i = 0; i < len; i++) { - data = (data << 8) + interpreter.getFlashByte(mem.vma_addr + len - i - 1) & 0xff; - } - } - return data; + @Override + public boolean removeSegmentMonitor(long address, int size, SegmentMonitor mm) { + for (AvrByteMonitor mcm : memoryMonitors) { + if (mcm.mm != mm || mcm.address != address || mcm.size != size) { + continue; + } + for (int idx = 0; idx < mcm.size; idx++) { + interpreter.getSimulator().removeWatch(mcm, (int) mcm.address + idx); + /* logger.debug("Removed watch " + Integer.toString(mcm.watch.hashCode()) + " for " + (mcm.address + idx)); */ + } + memoryMonitors.remove(mcm); + return true; } + return false; + } - private void setValue(String varName, int val, int len) throws UnknownVariableException { - Location mem = memoryMap.getLocation(varName); - if (mem == null) throw new UnknownVariableException("Variable does not exist: " + varName); - - int data = val; - if (mem.vma_addr > 0xfffff) { - // write LSB first. - for (int i = 0; i < len; i++) { - interpreter.writeDataByte((mem.vma_addr & 0xfffff) + i, (byte) (data & 0xff)); - System.out.println("Wrote byte: " + (data & 0xff)); - data = data >> 8; - } - } else { - for (int i = 0; i < len; i++) { - interpreter.writeFlashByte(mem.vma_addr + i, (byte) (data & 0xff)); - data = data >> 8; - } - } - } - - public int getIntValueOf(String varName) throws UnknownVariableException { - return getValueOf(varName, 2); - } - - public int getIntegerLength() { - return 2; - } - - public int getVariableAddress(String varName) - throws UnknownVariableException { - return 0; - } - - public String[] getVariableNames() { - ArrayList symbols = new ArrayList(); - for (Iterator i = memoryMap.getIterator(); i.hasNext();) { - symbols.add(((Location) i.next()).name); - } - return symbols.toArray(new String[0]); - } - - public void setByteArray(String varName, byte[] data) - throws UnknownVariableException { - } - - public void setByteValueOf(String varName, byte newVal) - throws UnknownVariableException { - setValue(varName, newVal, 1); - } - - public void setIntValueOf(String varName, int newVal) - throws UnknownVariableException { - setValue(varName, newVal, 2); - } - - public boolean variableExists(String varName) { - return memoryMap.getLocation(varName) != null; - } - - public boolean addMemoryMonitor(int address, int size, MemoryMonitor mm) { - logger.warn("Not implemented"); - return false; - } - - public void removeMemoryMonitor(int address, int size, MemoryMonitor mm) { - } - - public int parseInt(byte[] memorySegment) { - logger.warn("Not implemented"); - return 0; - } } diff --git a/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/MicaZMote.java b/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/MicaZMote.java index 97cca433a..0819b616e 100644 --- a/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/MicaZMote.java +++ b/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/MicaZMote.java @@ -40,9 +40,9 @@ import org.jdom.Element; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; import org.contikios.cooja.MoteInterfaceHandler; -import org.contikios.cooja.MoteMemory; import org.contikios.cooja.MoteType; import org.contikios.cooja.Simulation; +import org.contikios.cooja.mote.memory.MemoryInterface; import org.contikios.cooja.motes.AbstractEmulatedMote; import avrora.arch.avr.AVRProperties; import avrora.core.LoadableProgram; @@ -264,11 +264,12 @@ public class MicaZMote extends AbstractEmulatedMote implements Mote { return config; } - public MoteMemory getMemory() { + @Override + public MemoryInterface getMemory() { return myMemory; } - public void setMemory(MoteMemory memory) { + public void setMemory(AvrMoteMemory memory) { myMemory = (AvrMoteMemory) memory; } diff --git a/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/interfaces/MicaZID.java b/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/interfaces/MicaZID.java index a9b9e2190..b52e40730 100644 --- a/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/interfaces/MicaZID.java +++ b/tools/cooja/apps/avrora/src/org/contikios/cooja/avrmote/interfaces/MicaZID.java @@ -38,16 +38,15 @@ import javax.swing.JPanel; import org.apache.log4j.Logger; import org.jdom.Element; -import avrora.sim.State; -import avrora.sim.Simulator.Watch; - import org.contikios.cooja.Mote; import org.contikios.cooja.MoteTimeEvent; import org.contikios.cooja.Simulation; import org.contikios.cooja.TimeEvent; -import org.contikios.cooja.avrmote.AvrMoteMemory; import org.contikios.cooja.avrmote.MicaZMote; import org.contikios.cooja.interfaces.MoteID; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.VarMemory; public class MicaZID extends MoteID { @@ -57,7 +56,7 @@ public class MicaZID extends MoteID { private int moteID = -1; /* TODO Implement */ - private AvrMoteMemory moteMem; + private VarMemory moteMem; boolean tosID = false; boolean contikiID = false; private MicaZMote mote; @@ -80,23 +79,26 @@ public class MicaZID extends MoteID { public MicaZID(Mote mote) { this.mote = (MicaZMote) mote; - this.moteMem = (AvrMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); if (moteMem.variableExists("node_id")) { contikiID = true; - int addr = moteMem.getVariableAddress("node_id"); - moteMem.insertWatch(new Watch() { - public void fireAfterRead(State arg0, int arg1, byte arg2) { - System.out.println("Read from node_id: " + arg2); + int addr = (int) moteMem.getVariableAddress("node_id"); + moteMem.addVarMonitor( + SegmentMonitor.EventType.READWRITE, + "node_id", + new SegmentMonitor() { + + @Override + public void memoryChanged(MemoryInterface memory, SegmentMonitor.EventType type, long address) { + if (type == EventType.READ) { + System.out.println("Read from node_id."); + } else { + System.out.println("Writing to node_id."); + } } - public void fireAfterWrite(State arg0, int arg1, byte arg2) { - } - public void fireBeforeRead(State arg0, int arg1) { - } - public void fireBeforeWrite(State arg0, int arg1, byte arg2) { - System.out.println("Writing to node_id: " + arg2); - }}, addr); + }); } if (moteMem.variableExists("TOS_NODE_ID")) { diff --git a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMote.java b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMote.java index 3d66c6b08..403376583 100644 --- a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMote.java +++ b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMote.java @@ -45,12 +45,12 @@ import org.contikios.cooja.Cooja; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; import org.contikios.cooja.MoteInterfaceHandler; -import org.contikios.cooja.MoteMemory; import org.contikios.cooja.MoteType; import org.contikios.cooja.Simulation; import org.contikios.cooja.Watchpoint; import org.contikios.cooja.WatchpointMote; import org.contikios.cooja.interfaces.IPAddress; +import org.contikios.cooja.mote.memory.MemoryInterface; import org.contikios.cooja.motes.AbstractEmulatedMote; import org.contikios.cooja.mspmote.interfaces.Msp802154Radio; import org.contikios.cooja.mspmote.interfaces.MspSerial; @@ -185,12 +185,13 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc myCpu = cpu; } - public MoteMemory getMemory() { + @Override + public MemoryInterface getMemory() { return myMemory; } - public void setMemory(MoteMemory memory) { - myMemory = (MspMoteMemory) memory; + public void setMemory(MspMoteMemory memory) { + myMemory = memory; } /** diff --git a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMoteMemory.java b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMoteMemory.java index 47d18b9ca..6e2e58c36 100644 --- a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMoteMemory.java +++ b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/MspMoteMemory.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014, TU Braunschweig. All rights reserved. * Copyright (c) 2007, Swedish Institute of Computer Science. All rights * reserved. * @@ -28,21 +29,27 @@ package org.contikios.cooja.mspmote; +import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import org.apache.log4j.Logger; -import org.contikios.cooja.AddressMemory; import org.contikios.cooja.Mote; -import org.contikios.cooja.MoteMemory; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor.EventType; +import org.contikios.cooja.mote.memory.MemoryLayout; import se.sics.mspsim.core.MSP430; import se.sics.mspsim.core.Memory.AccessMode; import se.sics.mspsim.core.Memory.AccessType; import se.sics.mspsim.util.MapEntry; -public class MspMoteMemory implements MoteMemory, AddressMemory { +public class MspMoteMemory implements MemoryInterface { private static Logger logger = Logger.getLogger(MspMoteMemory.class); private final ArrayList mapEntries; + private final MemoryLayout memLayout; private final MSP430 cpu; @@ -56,143 +63,85 @@ public class MspMoteMemory implements MoteMemory, AddressMemory { } this.cpu = cpu; + memLayout = new MemoryLayout(ByteOrder.LITTLE_ENDIAN, MemoryLayout.ARCH_16BIT, 2); } - public String[] getVariableNames() { - String[] names = new String[mapEntries.size()]; - for (int i = 0; i < mapEntries.size(); i++) { - names[i] = mapEntries.get(i).getName(); - } - return names; + @Override + public int getTotalSize() { + return cpu.memory.length; } - private MapEntry getMapEntry(String varName) throws UnknownVariableException { - for (MapEntry entry: mapEntries) { - if (entry.getName().equals(varName)) { - return entry; - } - } - throw new UnknownVariableException(varName); + @Override + public byte[] getMemory() throws MoteMemoryException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - public int getVariableAddress(String varName) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - return entry.getAddress(); - } - - public int getIntegerLength() { - return 2; - } - - public void clearMemory() { - logger.fatal("clearMemory() not implemented"); - } - - public byte[] getMemorySegment(int address, int size) { + @Override + public byte[] getMemorySegment(long address, int size) { int[] memInts = new int[size]; - System.arraycopy(cpu.memory, address, memInts, 0, size); + System.arraycopy(cpu.memory, (int) address, memInts, 0, size); /* Convert to byte array */ byte[] memBytes = new byte[size]; - for (int i=0; i < size; i++) { + for (int i = 0; i < size; i++) { memBytes[i] = (byte) memInts[i]; } return memBytes; } - public void setMemorySegment(int address, byte[] data) { + @Override + public void setMemorySegment(long address, byte[] data) { /* Convert to int array */ int[] memInts = new int[data.length]; - for (int i=0; i < data.length; i++) { + for (int i = 0; i < data.length; i++) { memInts[i] = data[i]; } - System.arraycopy(memInts, 0, cpu.memory, address, data.length); + System.arraycopy(memInts, 0, cpu.memory, (int) address, data.length); } - public int getTotalSize() { - return cpu.memory.length; + @Override + public void clearMemory() { + Arrays.fill(cpu.memory, 0); } - public boolean variableExists(String varName) { - for (MapEntry entry: mapEntries) { - if (entry.getName().equals(varName)) { - return true; + @Override + public long getStartAddr() { + return 0;// XXXX + } + + @Override + public Map getSymbolMap() { + Map vars = new HashMap<>(); + for (MapEntry entry : mapEntries) { + if (entry.getType() != MapEntry.TYPE.variable) { + continue; } + vars.put(entry.getName(), new Symbol( + Symbol.Type.VARIABLE, + entry.getName(), + entry.getAddress(), + entry.getSize())); } - - return false; + return vars; } - /* TODO Check correct variable size in below methods */ - - public int getIntValueOf(String varName) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - - int varAddr = entry.getAddress(); - byte[] varData = getMemorySegment(varAddr, 2); - return parseInt(varData); + @Override + public MemoryLayout getLayout() { + return memLayout; } - public void setIntValueOf(String varName, int newVal) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - int varAddr = entry.getAddress(); + private final ArrayList cpuMonitorArray = new ArrayList<>(); - int newValToSet = Integer.reverseBytes(newVal); - - // Create byte array - int pos = 0; - - byte[] varData = new byte[2]; - varData[pos++] = (byte) ((newValToSet & 0xFF000000) >> 24); - varData[pos++] = (byte) ((newValToSet & 0xFF0000) >> 16); - - setMemorySegment(varAddr, varData); - } - - public byte getByteValueOf(String varName) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - int varAddr = entry.getAddress(); - - byte[] varData = getMemorySegment(varAddr, 1); - - return varData[0]; - } - - public void setByteValueOf(String varName, byte newVal) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - int varAddr = entry.getAddress(); - - byte[] varData = new byte[1]; - - varData[0] = newVal; - - setMemorySegment(varAddr, varData); - } - - public byte[] getByteArray(String varName, int length) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - int varAddr = entry.getAddress(); - - return getMemorySegment(varAddr, length); - } - - public void setByteArray(String varName, byte[] data) throws UnknownVariableException { - MapEntry entry = getMapEntry(varName); - int varAddr = entry.getAddress(); - - setMemorySegment(varAddr, data); - } - - private ArrayList cpuMonitorArray = new ArrayList(); class MemoryCPUMonitor extends se.sics.mspsim.core.MemoryMonitor.Adapter { - public final MemoryMonitor mm; + + public final SegmentMonitor mm; public final int address; public final int size; - public MemoryCPUMonitor(MemoryMonitor mm, int address, int size) { + public MemoryCPUMonitor(SegmentMonitor mm, int address, int size) { this.mm = mm; this.address = address; this.size = size; @@ -200,49 +149,39 @@ public class MspMoteMemory implements MoteMemory, AddressMemory { @Override public void notifyReadAfter(int address, AccessMode mode, AccessType type) { - mm.memoryChanged(MspMoteMemory.this, MemoryEventType.READ, address); + mm.memoryChanged(MspMoteMemory.this, EventType.READ, address); } @Override public void notifyWriteAfter(int dstAddress, int data, AccessMode mode) { - mm.memoryChanged(MspMoteMemory.this, MemoryEventType.WRITE, dstAddress); + mm.memoryChanged(MspMoteMemory.this, EventType.WRITE, dstAddress); } } - public boolean addMemoryMonitor(int address, int size, MemoryMonitor mm) { - MemoryCPUMonitor t = new MemoryCPUMonitor(mm, address, size); + @Override + public boolean addSegmentMonitor(EventType type, long address, int size, SegmentMonitor mm) { + MemoryCPUMonitor t = new MemoryCPUMonitor(mm, (int) address, size); cpuMonitorArray.add(t); - for (int a = address; a < address+size; a++) { + for (int a = (int) address; a < address + size; a++) { cpu.addWatchPoint(a, t); } return true; } - public void removeMemoryMonitor(int address, int size, MemoryMonitor mm) { - for (MemoryCPUMonitor mcm: cpuMonitorArray) { + @Override + public boolean removeSegmentMonitor(long address, int size, SegmentMonitor mm) { + for (MemoryCPUMonitor mcm : cpuMonitorArray) { if (mcm.mm != mm || mcm.address != address || mcm.size != size) { continue; } - for (int a = address; a < address+size; a++) { + for (int a = (int) address; a < (int) address + size; a++) { cpu.removeWatchPoint(a, mcm); } cpuMonitorArray.remove(mcm); - break; + return true; } - } - - public int parseInt(byte[] memorySegment) { - if (memorySegment.length < 2) { - return -1; - } - - int retVal = 0; - int pos = 0; - retVal += ((memorySegment[pos++] & 0xFF)) << 8; - retVal += ((memorySegment[pos++] & 0xFF)) << 0; - - return Integer.reverseBytes(retVal) >> 16; + return false; } } diff --git a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspDebugOutput.java b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspDebugOutput.java index 80df3ece4..af72bc63a 100644 --- a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspDebugOutput.java +++ b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspDebugOutput.java @@ -40,8 +40,9 @@ import org.jdom.Element; import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Mote; import org.contikios.cooja.interfaces.Log; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.VarMemory; import org.contikios.cooja.mspmote.MspMote; -import org.contikios.cooja.mspmote.MspMoteMemory; import se.sics.mspsim.core.Memory; import se.sics.mspsim.core.MemoryMonitor; @@ -64,24 +65,24 @@ public class MspDebugOutput extends Log { private final static String CONTIKI_POINTER = "cooja_debug_ptr"; private MspMote mote; - private MspMoteMemory mem; + private VarMemory mem; private String lastLog = null; private MemoryMonitor memoryMonitor = null; public MspDebugOutput(Mote mote) { this.mote = (MspMote) mote; - this.mem = (MspMoteMemory) this.mote.getMemory(); + this.mem = new VarMemory(this.mote.getMemory()); if (!mem.variableExists(CONTIKI_POINTER)) { /* Disabled */ return; } - this.mote.getCPU().addWatchPoint(mem.getVariableAddress(CONTIKI_POINTER), + this.mote.getCPU().addWatchPoint((int) mem.getVariableAddress(CONTIKI_POINTER), memoryMonitor = new MemoryMonitor.Adapter() { @Override public void notifyWriteAfter(int adr, int data, Memory.AccessMode mode) { - String msg = extractString(mem, data); + String msg = extractString(MspDebugOutput.this.mote.getMemory(), data); if (msg != null && msg.length() > 0) { lastLog = "DEBUG: " + msg; setChanged(); @@ -91,7 +92,7 @@ public class MspDebugOutput extends Log { }); } - private String extractString(MspMoteMemory mem, int address) { + private String extractString(MemoryInterface mem, int address) { StringBuilder sb = new StringBuilder(); while (true) { byte[] data = mem.getMemorySegment(address, 8); @@ -136,7 +137,7 @@ public class MspDebugOutput extends Log { super.removed(); if (memoryMonitor != null) { - mote.getCPU().removeWatchPoint(mem.getVariableAddress(CONTIKI_POINTER), memoryMonitor); + mote.getCPU().removeWatchPoint((int) mem.getVariableAddress(CONTIKI_POINTER), memoryMonitor); } } } diff --git a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspMoteID.java b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspMoteID.java index 0c71ca208..a7ced648b 100644 --- a/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspMoteID.java +++ b/tools/cooja/apps/mspsim/src/org/contikios/cooja/mspmote/interfaces/MspMoteID.java @@ -39,8 +39,8 @@ import org.apache.log4j.Logger; import org.contikios.cooja.Mote; import org.contikios.cooja.interfaces.MoteID; +import org.contikios.cooja.mote.memory.VarMemory; import org.contikios.cooja.mspmote.MspMote; -import org.contikios.cooja.mspmote.MspMoteMemory; import se.sics.mspsim.core.Memory; import se.sics.mspsim.core.MemoryMonitor; @@ -53,7 +53,7 @@ public class MspMoteID extends MoteID { private static Logger logger = Logger.getLogger(MspMoteID.class); private MspMote mote; - private MspMoteMemory moteMem = null; + private VarMemory moteMem = null; private boolean writeFlashHeader = true; private int moteID = -1; @@ -69,7 +69,7 @@ public class MspMoteID extends MoteID { */ public MspMoteID(Mote m) { this.mote = (MspMote) m; - this.moteMem = (MspMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public int getMoteID() { @@ -144,7 +144,7 @@ public class MspMoteID extends MoteID { byte[] id = new byte[2]; id[0] = (byte) (moteID & 0xff); id[1] = (byte) ((moteID >> 8) & 0xff); - moteMem.setMemorySegment(dstAddress & ~1, id); + mote.getMemory().setMemorySegment(dstAddress & ~1, id); } }; @@ -201,7 +201,7 @@ public class MspMoteID extends MoteID { private void addMonitor(String variable, MemoryMonitor monitor) { if (moteMem.variableExists(variable)) { - int address = moteMem.getVariableAddress(variable); + int address = (int) moteMem.getVariableAddress(variable); if ((address & 1) != 0) { // Variable can not be a word - must be a byte } else { @@ -213,7 +213,7 @@ public class MspMoteID extends MoteID { private void removeMonitor(String variable, MemoryMonitor monitor) { if (moteMem.variableExists(variable)) { - int address = moteMem.getVariableAddress(variable); + int address = (int) moteMem.getVariableAddress(variable); mote.getCPU().removeWatchPoint(address, monitor); mote.getCPU().removeWatchPoint(address + 1, monitor); } diff --git a/tools/cooja/config/external_tools.config b/tools/cooja/config/external_tools.config index 18ad0be46..89d9c4f7d 100644 --- a/tools/cooja/config/external_tools.config +++ b/tools/cooja/config/external_tools.config @@ -25,7 +25,6 @@ PATH_JAVAC = javac DEFAULT_PROJECTDIRS = [CONTIKI_DIR]/tools/cooja/apps/mrm;[CONTIKI_DIR]/tools/cooja/apps/mspsim;[CONTIKI_DIR]/tools/cooja/apps/avrora;[CONTIKI_DIR]/tools/cooja/apps/serial_socket;[CONTIKI_DIR]/tools/cooja/apps/collect-view;[CONTIKI_DIR]/tools/cooja/apps/powertracker PARSE_WITH_COMMAND=false -PARSE_COMMAND=nm -a $(LIBFILE) MAPFILE_DATA_START = ^.data[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$ MAPFILE_DATA_SIZE = ^.data[ \t]*0x[0-9A-Fa-f]*[ \t]*0x([0-9A-Fa-f]*)[ \t]*$ MAPFILE_BSS_START = ^.bss[ \t]*0x([0-9A-Fa-f]*)[ \t]*0x[0-9A-Fa-f]*[ \t]*$ @@ -35,11 +34,19 @@ MAPFILE_VAR_ADDRESS_1 = ^[ \t]*0x([0-9A-Fa-f]*)[ \t]* MAPFILE_VAR_ADDRESS_2 = [ \t]*$ MAPFILE_VAR_SIZE_1 = ^ MAPFILE_VAR_SIZE_2 = [ \t]*(0x[0-9A-Fa-f]*)[ \t]*[^ ]*[ \t]*$ -COMMAND_VAR_NAME_ADDRESS = ^([0-9A-Fa-f][0-9A-Fa-f]*)[ \t][^Tt][ \t]([^ ._][^ ]*) -COMMAND_DATA_START = ^([0-9A-Fa-f]*)[ \t]d[ \t].data$ -COMMAND_DATA_END = ^([0-9A-Fa-f]*)[ \t]A[ \t]_edata$ -COMMAND_BSS_START = ^([0-9A-Fa-f]*)[ \t]A[ \t]__bss_start$ -COMMAND_BSS_END = ^([0-9A-Fa-f]*)[ \t]A[ \t]_end$ + +PARSE_COMMAND=nm -aP $(LIBFILE) +COMMAND_VAR_NAME_ADDRESS_SIZE = ^([^.].*?)
([0-9a-fA-F]+) ([0-9a-fA-F])* +COMMAND_VAR_SEC_DATA = [DdGg] +COMMAND_VAR_SEC_BSS = [Bb] +COMMAND_VAR_SEC_COMMON = [C] +COMMAND_VAR_SEC_READONLY = [Rr] +COMMAND_DATA_START = ^.data[ \t]d[ \t]([0-9A-Fa-f]*)[ \t]*$ +COMMAND_DATA_END = ^_edata[ \t]A[ \t]([0-9A-Fa-f]*)[ \t]*$ +COMMAND_BSS_START = ^__bss_start[ \t]A[ \t]([0-9A-Fa-f]*)[ \t]*$ +COMMAND_BSS_END = ^_end[ \t]A[ \t]([0-9A-Fa-f]*)[ \t]*$ +COMMAND_READONLY_START = ^.rodata[ \t]r[ \t]([0-9A-Fa-f]*)[ \t]*$ +COMMAND_READONLY_END = ^.eh_frame_hdr[ \t]r[ \t]([0-9A-Fa-f]*)[ \t]*$ VISUALIZER_DEFAULT_SKINS=\ org.contikios.cooja.plugins.skins.IDVisualizerSkin;\ diff --git a/tools/cooja/config/external_tools_win32.config b/tools/cooja/config/external_tools_win32.config index 484f95a21..2d5dd7e4a 100644 --- a/tools/cooja/config/external_tools_win32.config +++ b/tools/cooja/config/external_tools_win32.config @@ -6,8 +6,14 @@ COMPILER_ARGS=-D__int64\="long long" -Wall -I'$(JAVA_HOME)/include' -I'$(JAVA_HO LINK_COMMAND_1 = mingw32-gcc -shared -Wl,-Map=$(MAPFILE) -Wl,--add-stdcall-alias -o $(LIBFILE) LINK_COMMAND_2 = -L/usr/lib/mingw PARSE_WITH_COMMAND = true -PARSE_COMMAND=nm -n -C $(LIBFILE) -COMMAND_DATA_START = ^([0-9A-Fa-f]*)[ \t]D[ \t].*_data_start__$ -COMMAND_DATA_END = ^([0-9A-Fa-f]*)[ \t]D[ \t].*_data_end__$ -COMMAND_BSS_START = ^([0-9A-Fa-f]*)[ \t]B[ \t].*_bss_start__$ -COMMAND_BSS_END = ^([0-9A-Fa-f]*)[ \t]B[ \t].*_bss_end__$ + +# Hack: nm with arguments -S --size-sort does not display __data_start symbols +PARSE_COMMAND=sh -c "/bin/nm -aP --size-sort -S $(LIBFILE) && /bin/nm -aP $(LIBFILE)" + +COMMAND_VAR_NAME_ADDRESS_SIZE = ^[_]([^.].*?)[ \t]
[ \t]([0-9a-fA-F]+)[ \t]([0-9a-fA-F]+) +COMMAND_DATA_START = ^__data_start__[ \t]D[ \t]([0-9A-Fa-f]*) +COMMAND_DATA_END = ^__data_end__[ \t]D[ \t]([0-9A-Fa-f]*) +COMMAND_BSS_START = ^__bss_start__[ \t]B[ \t]([0-9A-Fa-f]*) +COMMAND_BSS_END = ^__bss_end__[ \t]B[ \t]([0-9A-Fa-f]*) +COMMAND_READONLY_START = ^.rodata[ \t]r[ \t]([0-9A-Fa-f]*) +COMMAND_READONLY_END = ^.eh_frame_hdr[ \t]r[ \t]([0-9A-Fa-f]*) diff --git a/tools/cooja/config/log4j_config.xml b/tools/cooja/config/log4j_config.xml index ff9741f0c..d3d269bb8 100644 --- a/tools/cooja/config/log4j_config.xml +++ b/tools/cooja/config/log4j_config.xml @@ -18,7 +18,7 @@ - + diff --git a/tools/cooja/java/org/contikios/cooja/AddressMemory.java b/tools/cooja/java/org/contikios/cooja/AddressMemory.java deleted file mode 100644 index 4f126ab7e..000000000 --- a/tools/cooja/java/org/contikios/cooja/AddressMemory.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - * - */ - -package org.contikios.cooja; - -public interface AddressMemory { - - /** - * @return All variable names known and residing in this memory - */ - public String[] getVariableNames(); - - /** - * Checks if given variable exists in memory. - * - * @param varName Variable name - * @return True if variable exists, false otherwise - */ - public boolean variableExists(String varName); - - /** - * Returns address of variable with given name. - * - * @param varName Variable name - * @return Variable address - * @throws UnknownVariableException Variable does not exist - */ - public int getVariableAddress(String varName) throws UnknownVariableException; - - /** - * Returns a value of the byte variable with the given name. - * - * @param varName Name of byte variable - * @return Value of byte variable - * @throws UnknownVariableException Variable does not exist - */ - public byte getByteValueOf(String varName) throws UnknownVariableException; - - /** - * Set byte value of variable with given name. - * - * @param varName Name of byte variable - * @param newVal New value of byte - * @throws UnknownVariableException Variable does not exist - */ - public void setByteValueOf(String varName, byte newVal) throws UnknownVariableException; - - /** - * Returns byte array of given length and with the given name. - * - * @param varName Name of array - * @param length Length of array - * @return Data of array - * @throws UnknownVariableException Variable does not exist - */ - public byte[] getByteArray(String varName, int length) throws UnknownVariableException; - - /** - * Set byte array of the variable with the given name. - * - * @param varName Name of array - * @param data New data of array - * @throws UnknownVariableException Variable does not exist - */ - public void setByteArray(String varName, byte[] data) throws UnknownVariableException; - - /** - * @return Number of bytes in an integer - */ - public int getIntegerLength(); - - /** - * Returns a value of the integer variable with the given name. - * - * @param varName Name of integer variable - * @return Value of integer variable - * @throws UnknownVariableException Variable does not exist - */ - public int getIntValueOf(String varName) throws UnknownVariableException; - - /** - * Set integer value of variable with given name. - * - * @param varName Name of integer variable - * @param newVal New integer value - * @throws UnknownVariableException Variable does not exist - */ - public void setIntValueOf(String varName, int newVal) throws UnknownVariableException; - - /** - * Unknown variable name exception. - */ - public class UnknownVariableException extends RuntimeException { - public UnknownVariableException(String varName) { - super("Unknown variable name: " + varName); - } - } - -} diff --git a/tools/cooja/java/org/contikios/cooja/Cooja.java b/tools/cooja/java/org/contikios/cooja/Cooja.java index 4d1770b6b..055cb46f4 100644 --- a/tools/cooja/java/org/contikios/cooja/Cooja.java +++ b/tools/cooja/java/org/contikios/cooja/Cooja.java @@ -274,7 +274,7 @@ public class Cooja extends Observable { "MAPFILE_VAR_SIZE_1", "MAPFILE_VAR_SIZE_2", "PARSE_COMMAND", - "COMMAND_VAR_NAME_ADDRESS", + "COMMAND_VAR_NAME_ADDRESS_SIZE", "COMMAND_DATA_START", "COMMAND_DATA_END", "COMMAND_BSS_START", "COMMAND_BSS_END", "COMMAND_COMMON_START", "COMMAND_COMMON_END", diff --git a/tools/cooja/java/org/contikios/cooja/Mote.java b/tools/cooja/java/org/contikios/cooja/Mote.java index 7eeb326a0..167a24ff4 100644 --- a/tools/cooja/java/org/contikios/cooja/Mote.java +++ b/tools/cooja/java/org/contikios/cooja/Mote.java @@ -28,6 +28,7 @@ package org.contikios.cooja; import java.util.Collection; +import org.contikios.cooja.mote.memory.MemoryInterface; import org.jdom.Element; @@ -63,7 +64,7 @@ public interface Mote { * @see #setMemory(MoteMemory) * @return Mote memory */ - public MoteMemory getMemory(); + public MemoryInterface getMemory(); /** * Returns mote type. diff --git a/tools/cooja/java/org/contikios/cooja/MoteMemory.java b/tools/cooja/java/org/contikios/cooja/MoteMemory.java deleted file mode 100644 index a730bee4f..000000000 --- a/tools/cooja/java/org/contikios/cooja/MoteMemory.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * - */ - -package org.contikios.cooja; - - -/** - * This interface represents a mote memory. - * - * Mote memory is represented by byte arrays and this - * interface provides a few of basic operations. - * - * Note that this memory internally may consist of several - * different memory sections, not covering the entire range - * between the start address and the end address of this memory. - * - * @see org.contikios.cooja.SectionMoteMemory - * @author Fredrik Osterlind - */ -public interface MoteMemory extends AddressMemory { - - /** - * Clears the entire memory. - */ - public void clearMemory(); - - /** - * Returns a memory segment. - * - * @param address Start address of memory segment - * @param size Size of memory segment - * @return Memory segment or null if segment not available - */ - public byte[] getMemorySegment(int address, int size); - - /** - * Sets a memory segment. - * - * @param address Start address of memory segment - * @param data Data - */ - public void setMemorySegment(int address, byte[] data); - - /** - * Returns the sum of all byte array sizes in this memory. - * This is not neccessarily the the same as the total memory range, - * since the entire memory range may not be handled by this memory. - * - * @return Total size - */ - public int getTotalSize(); - - public abstract int parseInt(byte[] memorySegment); - - public enum MemoryEventType { READ, WRITE }; - - public interface MemoryMonitor { - public void memoryChanged(MoteMemory memory, MemoryEventType type, int address); - } - - public boolean addMemoryMonitor(int address, int size, MemoryMonitor mm); - public void removeMemoryMonitor(int address, int size, MemoryMonitor mm); -} diff --git a/tools/cooja/java/org/contikios/cooja/SectionMoteMemory.java b/tools/cooja/java/org/contikios/cooja/SectionMoteMemory.java deleted file mode 100644 index 267bfac7b..000000000 --- a/tools/cooja/java/org/contikios/cooja/SectionMoteMemory.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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. - */ - -package org.contikios.cooja; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; - -import org.apache.log4j.Logger; - -/** - * Represents a mote memory consisting of non-overlapping memory sections with - * symbol addresses. - *

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

- * - * @author Fredrik Osterlind - */ -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 HashMap addresses; - - /* used to map Cooja's address space to native (Contiki's) addresses */ - private final int offset; - - /** - * @param addresses Symbol addresses - * @param offset Offset for internally used addresses - */ - public SectionMoteMemory(HashMap addresses, int offset) { - this.addresses = addresses; - this.offset = offset; - } - - public String[] getVariableNames() { - 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 addresses.get(varName).intValue() + offset; - } - - public int getIntegerLength() { - return 4; - } - - public void clearMemory() { - sections.clear(); - } - - 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) - && section.includesAddr(address + data.length - 1)) { - section.setMemorySegment(address, data); - return; - } - } - 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) { - totalSize += section.getSize(); - } - return totalSize; - } - - /** - * Returns the total number of sections in this memory. - * - * @return Number of sections - */ - public int getNumberOfSections() { - return sections.size(); - } - - /** - * Get start address of given section in native address space. - * - * @param sectionNr Section position - * @return Start address of section - */ - public int getSectionNativeAddress(int sectionNr) { - if (sectionNr >= sections.size()) { - return -1; - } - return sections.get(sectionNr).getStartAddr(); - } - - /** - * Get size of section at given position. - * - * @param sectionNr Section position - * @return Size of section - */ - public int getSizeOfSection(int sectionNr) { - if (sectionNr >= sections.size()) { - return -1; - } - - return sections.get(sectionNr).getSize(); - } - - /** - * Get data of section at given position. - * - * @param sectionNr Section position - * @return Data at section - */ - public byte[] getDataOfSection(int sectionNr) { - if (sectionNr >= sections.size()) { - return null; - } - - return sections.get(sectionNr).getData(); - } - - public boolean variableExists(String varName) { - return addresses.containsKey(varName); - } - - public int getIntValueOf(String varName) throws UnknownVariableException { - int varAddr = getVariableAddress(varName); - byte[] varData = getMemorySegment(varAddr, 4); - - if (varData == null) { - throw new UnknownVariableException(varName); - } - - return parseInt(varData); - } - - public void setIntValueOf(String varName, int newVal) throws UnknownVariableException { - int varAddr = getVariableAddress(varName); - - /* TODO Correct for all platforms? */ - int newValToSet = Integer.reverseBytes(newVal); - - int pos = 0; - - byte[] varData = new byte[4]; - varData[pos++] = (byte) ((newValToSet & 0xFF000000) >> 24); - varData[pos++] = (byte) ((newValToSet & 0xFF0000) >> 16); - varData[pos++] = (byte) ((newValToSet & 0xFF00) >> 8); - varData[pos++] = (byte) ((newValToSet & 0xFF) >> 0); - - setMemorySegment(varAddr, varData); - } - - public byte getByteValueOf(String varName) throws UnknownVariableException { - int varAddr = getVariableAddress(varName); - byte[] varData = getMemorySegment(varAddr, 1); - - if (varData == null) { - throw new UnknownVariableException(varName); - } - - return varData[0]; - } - - public void setByteValueOf(String varName, byte newVal) throws UnknownVariableException { - int varAddr = getVariableAddress(varName); - byte[] varData = new byte[1]; - - varData[0] = newVal; - - setMemorySegment(varAddr, varData); - } - - public byte[] getByteArray(String varName, int length) throws UnknownVariableException { - int varAddr = getVariableAddress(varName); - return getMemorySegment(varAddr, length); - } - - public void setByteArray(String varName, byte[] data) throws UnknownVariableException { - int varAddr = getVariableAddress(varName); - setMemorySegment(varAddr, data); - } - - /** - * 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; - } - - 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); - } - - 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; - } - } - - public SectionMoteMemory clone() { - ArrayList sectionsClone = new ArrayList(); - for (MoteMemorySection section : sections) { - sectionsClone.add(section.clone()); - } - - 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/org/contikios/cooja/contikimote/ContikiMote.java b/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMote.java index b2c814b7b..de033aaa4 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMote.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMote.java @@ -38,10 +38,10 @@ import org.jdom.Element; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; import org.contikios.cooja.MoteInterfaceHandler; -import org.contikios.cooja.MoteMemory; import org.contikios.cooja.MoteType; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.Simulation; +import org.contikios.cooja.mote.memory.MemoryInterface; import org.contikios.cooja.motes.AbstractWakeupMote; /** @@ -83,10 +83,12 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { requestImmediateWakeup(); } + @Override public int getID() { return myInterfaceHandler.getMoteID().getMoteID(); } + @Override public MoteInterfaceHandler getInterfaces() { return myInterfaceHandler; } @@ -95,14 +97,16 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { myInterfaceHandler = newInterfaces; } - public MoteMemory getMemory() { + @Override + public MemoryInterface getMemory() { return myMemory; } - public void setMemory(MoteMemory memory) { - myMemory = (SectionMoteMemory) memory; + public void setMemory(SectionMoteMemory memory) { + myMemory = memory; } + @Override public MoteType getType() { return myType; } @@ -121,6 +125,7 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { * * @param simTime Current simulation time */ + @Override public void execute(long simTime) { /* Poll mote interfaces */ @@ -154,6 +159,7 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { * * @return Current simulation config */ + @Override public Collection getConfigXML() { ArrayList config = new ArrayList(); Element element; @@ -173,6 +179,7 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { return config; } + @Override public boolean setConfigXML(Simulation simulation, Collection configXML, boolean visAvailable) { setSimulation(simulation); myMemory = myType.createInitialMemory(); @@ -212,6 +219,7 @@ public class ContikiMote extends AbstractWakeupMote implements Mote { return true; } + @Override public String toString() { return "Contiki " + getID(); } diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMoteType.java b/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMoteType.java index 78e05abe9..c80c375b1 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMoteType.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/ContikiMoteType.java @@ -27,7 +27,6 @@ * SUCH DAMAGE. * */ - package org.contikios.cooja.contikimote; import java.awt.Container; @@ -41,8 +40,10 @@ import java.lang.reflect.Method; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.Map; import java.util.Random; import java.util.Vector; import java.util.regex.Matcher; @@ -50,6 +51,7 @@ import java.util.regex.Pattern; import javax.swing.JComponent; import javax.swing.JLabel; +import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.jdom.Element; @@ -62,12 +64,18 @@ import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; import org.contikios.cooja.MoteType; import org.contikios.cooja.ProjectConfig; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.Simulation; 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.UnknownVariableException; +import org.contikios.cooja.mote.memory.VarMemory; import org.contikios.cooja.util.StringUtils; /** @@ -92,7 +100,8 @@ import org.contikios.cooja.util.StringUtils; @ClassDescription("Cooja mote") @AbstractionLevelDescription("OS level") public class ContikiMoteType implements MoteType { - private static Logger logger = Logger.getLogger(ContikiMoteType.class); + + private static final Logger logger = Logger.getLogger(ContikiMoteType.class); public static final String ID_PREFIX = "mtype"; @@ -120,9 +129,11 @@ public class ContikiMoteType implements MoteType { * Communication stacks in Contiki. */ public enum NetworkStack { + DEFAULT, MANUAL; public String manualHeader = "netstack-conf-example.h"; + @Override public String toString() { if (this == DEFAULT) { return "Default (from contiki-conf.h)"; @@ -165,7 +176,7 @@ public class ContikiMoteType implements MoteType { } } - private final String[] sensors = { "button_sensor", "pir_sensor", "vib_sensor" }; + private final String[] sensors = {"button_sensor", "pir_sensor", "vib_sensor"}; private String identifier = null; private String description = null; @@ -175,10 +186,15 @@ public class ContikiMoteType implements MoteType { /* For internal use only: using during Contiki compilation. */ private File contikiApp = null; /* Contiki application: hello-world.c */ + public File libSource = null; /* JNI library: obj_cooja/mtype1.c */ + public File libFile = null; /* JNI library: obj_cooja/mtype1.lib */ + public File archiveFile = null; /* Contiki archive: obj_cooja/mtype1.a */ + public File mapFile = null; /* Contiki map: obj_cooja/mtype1.map */ + public String javaClassName = null; /* Loading Java class name: Lib1 */ private String[] coreInterfaces = null; @@ -197,6 +213,9 @@ public class ContikiMoteType implements MoteType { // Initial memory for all motes of this type private SectionMoteMemory initialMemory = null; + /** Offset between native (cooja) and contiki address space */ + long offset; + /** * Creates a new uninitialized Cooja mote type. This mote type needs to load * a library file and parse a map file before it can be used. @@ -204,23 +223,25 @@ public class ContikiMoteType implements MoteType { public ContikiMoteType() { } + @Override public Mote generateMote(Simulation simulation) { return new ContikiMote(this, simulation); } + @Override public boolean configureAndInit(Container parentContainer, Simulation simulation, - boolean visAvailable) throws MoteTypeCreationException { + boolean visAvailable) throws MoteTypeCreationException { myConfig = simulation.getCooja().getProjectConfig().clone(); if (visAvailable) { if (getDescription() == null) { - setDescription("Cooja Mote Type #" + (simulation.getMoteTypes().length+1)); + setDescription("Cooja Mote Type #" + (simulation.getMoteTypes().length + 1)); } /* Compile Contiki from dialog */ - boolean compileOK = - ContikiMoteCompileDialog.showDialog(parentContainer, simulation, this); + boolean compileOK + = ContikiMoteCompileDialog.showDialog(parentContainer, simulation, this); if (!compileOK) { return false; } @@ -236,17 +257,17 @@ public class ContikiMoteType implements MoteType { /* Create variables used for compiling Contiki */ contikiApp = getContikiSourceFile(); libSource = new File( - contikiApp.getParentFile(), - "obj_cooja/" + getIdentifier() + ".c"); + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + ".c"); libFile = new File( - contikiApp.getParentFile(), - "obj_cooja/" + getIdentifier() + librarySuffix); + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + librarySuffix); archiveFile = new File( - contikiApp.getParentFile(), - "obj_cooja/" + getIdentifier() + dependSuffix); + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + dependSuffix); mapFile = new File( - contikiApp.getParentFile(), - "obj_cooja/" + getIdentifier() + mapSuffix); + contikiApp.getParentFile(), + "obj_cooja/" + getIdentifier() + mapSuffix); javaClassName = CoreComm.getAvailableClassName(); if (javaClassName == null) { @@ -261,37 +282,36 @@ public class ContikiMoteType implements MoteType { /* Generate Contiki main source */ /*try { - CompileContiki.generateSourceFile( - libSource, - javaClassName, - getSensors(), - getCoreInterfaces() - ); - } catch (Exception e) { - throw (MoteTypeCreationException) new MoteTypeCreationException( - "Error when generating Contiki main source").initCause(e); - }*/ + CompileContiki.generateSourceFile( + libSource, + javaClassName, + getSensors(), + getCoreInterfaces() + ); + } catch (Exception e) { + throw (MoteTypeCreationException) new MoteTypeCreationException( + "Error when generating Contiki main source").initCause(e); + }*/ /* Prepare compiler environment */ String[][] env; try { env = CompileContiki.createCompilationEnvironment( - getIdentifier(), - contikiApp, - mapFile, - libFile, - archiveFile, - javaClassName); + getIdentifier(), + contikiApp, + mapFile, + libFile, + archiveFile, + javaClassName); CompileContiki.redefineCOOJASources( - this, - env + this, + env ); } catch (Exception e) { - throw (MoteTypeCreationException) new MoteTypeCreationException( - "Error when creating environment: " + e.getMessage()).initCause(e); + throw new MoteTypeCreationException("Error when creating environment: " + e.getMessage(), e); } String[] envOneDimension = new String[env.length]; - for (int i=0; i < env.length; i++) { + for (int i = 0; i < env.length; i++) { envOneDimension[i] = env[i][0] + "=" + env[i][1]; } @@ -301,31 +321,31 @@ public class ContikiMoteType implements MoteType { } final MessageList compilationOutput = new MessageList(); String[] arr = getCompileCommands().split("\n"); - for (String cmd: arr) { + for (String cmd : arr) { if (cmd.trim().isEmpty()) { continue; } try { CompileContiki.compile( - cmd, - envOneDimension, - null /* Do not observe output firmware file */, - getContikiSourceFile().getParentFile(), - null, - null, - compilationOutput, - true + cmd, + envOneDimension, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true ); } catch (Exception e) { - MoteTypeCreationException newException = - new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + MoteTypeCreationException newException + = new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); newException = (MoteTypeCreationException) newException.initCause(e); newException.setCompilationOutput(compilationOutput); /* Print last 10 compilation errors to console */ MessageContainer[] messages = compilationOutput.getMessages(); - for (int i=messages.length-10; i < messages.length; i++) { + for (int i = messages.length - 10; i < messages.length; i++) { if (i < 0) { continue; } @@ -338,8 +358,8 @@ public class ContikiMoteType implements MoteType { } /* Make sure compiled firmware exists */ - if (getContikiFirmwareFile() == null || - !getContikiFirmwareFile().exists()) { + if (getContikiFirmwareFile() == null + || !getContikiFirmwareFile().exists()) { throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); } } @@ -351,7 +371,7 @@ public class ContikiMoteType implements MoteType { public static File getExpectedFirmwareFile(File source) { File parentDir = source.getParentFile(); - String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + String sourceNoExtension = source.getName().substring(0, source.getName().length() - 2); return new File(parentDir, sourceNoExtension + librarySuffix); } @@ -359,8 +379,10 @@ public class ContikiMoteType implements MoteType { /** * For internal use. * - * This method creates a core communicator linking a Contiki library and a Java class. - * It furthermore parses library Contiki memory addresses and creates the initial memory. + * This method creates a core communicator linking a Contiki library and a + * Java class. + * It furthermore parses library Contiki memory addresses and creates the + * initial memory. * * @throws MoteTypeCreationException */ @@ -368,11 +390,11 @@ public class ContikiMoteType implements MoteType { if (myCoreComm != null) { throw new MoteTypeCreationException( - "Core communicator already used: " + myCoreComm.getClass().getName()); + "Core communicator already used: " + myCoreComm.getClass().getName()); } - if (getContikiFirmwareFile() == null || - !getContikiFirmwareFile().exists()) { + if (getContikiFirmwareFile() == null + || !getContikiFirmwareFile().exists()) { throw new MoteTypeCreationException("Library file could not be found: " + getContikiFirmwareFile()); } @@ -384,46 +406,50 @@ public class ContikiMoteType implements MoteType { logger.info("Creating core communicator between Java class '" + javaClassName + "' and Contiki library '" + getContikiFirmwareFile().getName() + "'"); myCoreComm = CoreComm.createCoreComm(this.javaClassName, getContikiFirmwareFile()); - /* Parse addresses using map file or command */ + /* Parse addresses using map file + * or output of command specified in external tools settings (e.g. nm -a ) + */ boolean useCommand = Boolean.parseBoolean(Cooja.getExternalToolsSetting("PARSE_WITH_COMMAND", "false")); - int dataSectionAddr = -1, dataSectionSize = -1; - int bssSectionAddr = -1, bssSectionSize = -1; - int commonSectionAddr = -1, commonSectionSize = -1; - int readonlySectionAddr = -1, readonlySectionSize = -1; + SectionParser dataSecParser; + SectionParser bssSecParser; + SectionParser commonSecParser; + SectionParser readonlySecParser = null; - HashMap addresses = new HashMap(); + HashMap variables = new HashMap<>(); if (useCommand) { /* Parse command output */ String[] output = loadCommandData(getContikiFirmwareFile()); if (output == null) { throw new MoteTypeCreationException("No parse command output loaded"); } - boolean parseOK = parseCommandData(output, addresses); - if (!parseOK) { - logger.fatal("Command output parsing failed"); - throw new MoteTypeCreationException("Command output parsing failed"); - } - dataSectionAddr = parseCommandDataSectionAddr(output); - dataSectionSize = parseCommandDataSectionSize(output); - bssSectionAddr = parseCommandBssSectionAddr(output); - bssSectionSize = parseCommandBssSectionSize(output); - commonSectionAddr = parseCommandCommonSectionAddr(output); - commonSectionSize = parseCommandCommonSectionSize(output); - - try { - readonlySectionAddr = parseCommandReadonlySectionAddr(output); - readonlySectionSize = parseCommandReadonlySectionSize(output); - } catch (Exception e) { - readonlySectionAddr = -1; - readonlySectionSize = -1; - } + dataSecParser = new CommandSectionParser( + output, + Cooja.getExternalToolsSetting("COMMAND_DATA_START"), + Cooja.getExternalToolsSetting("COMMAND_DATA_END"), + Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_DATA")); + bssSecParser = new CommandSectionParser( + output, + Cooja.getExternalToolsSetting("COMMAND_BSS_START"), + Cooja.getExternalToolsSetting("COMMAND_BSS_END"), + Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_BSS")); + commonSecParser = new CommandSectionParser( + output, + Cooja.getExternalToolsSetting("COMMAND_COMMON_START"), + Cooja.getExternalToolsSetting("COMMAND_COMMON_END"), + Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_COMMON")); + /* XXX Currently Cooja tries to sync readonly memory */ + readonlySecParser = null;/* new CommandSectionParser( + output, + Cooja.getExternalToolsSetting("COMMAND_READONLY_START"), + Cooja.getExternalToolsSetting("COMMAND_READONLY_END"), + Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_READONLY"));*/ } else { - /* Parse command output */ - if (mapFile == null || - !mapFile.exists()) { + /* Parse map file */ + if (mapFile == null + || !mapFile.exists()) { throw new MoteTypeCreationException("Map file " + mapFile + " could not be found"); } String[] mapData = loadMapFile(mapFile); @@ -431,111 +457,332 @@ public class ContikiMoteType implements MoteType { logger.fatal("No map data could be loaded"); throw new MoteTypeCreationException("No map data could be loaded: " + mapFile); } - boolean parseOK = parseMapFileData(mapData, addresses); - if (!parseOK) { - logger.fatal("Map data parsing failed"); - throw new MoteTypeCreationException("Map data parsing failed: " + mapFile); - } - dataSectionAddr = parseMapDataSectionAddr(mapData); - dataSectionSize = parseMapDataSectionSize(mapData); - bssSectionAddr = parseMapBssSectionAddr(mapData); - bssSectionSize = parseMapBssSectionSize(mapData); - commonSectionAddr = parseMapCommonSectionAddr(mapData); - commonSectionSize = parseMapCommonSectionSize(mapData); - readonlySectionAddr = -1; - readonlySectionSize = -1; + dataSecParser = new MapSectionParser( + mapData, + Cooja.getExternalToolsSetting("MAPFILE_DATA_START"), + Cooja.getExternalToolsSetting("MAPFILE_DATA_SIZE")); + bssSecParser = new MapSectionParser( + mapData, + Cooja.getExternalToolsSetting("MAPFILE_BSS_START"), + Cooja.getExternalToolsSetting("MAPFILE_BSS_SIZE")); + commonSecParser = new MapSectionParser( + mapData, + Cooja.getExternalToolsSetting("MAPFILE_COMMON_START"), + Cooja.getExternalToolsSetting("MAPFILE_COMMON_SIZE")); + readonlySecParser = null; } - if (dataSectionAddr >= 0) { - logger.info(getContikiFirmwareFile().getName() + - ": data section at 0x" + Integer.toHexString(dataSectionAddr) + - " (" + dataSectionSize + " == 0x" + Integer.toHexString(dataSectionSize) + " bytes)"); - } else { - logger.fatal(getContikiFirmwareFile().getName() + ": no data section found"); - } - if (bssSectionAddr >= 0) { - logger.info(getContikiFirmwareFile().getName() + - ": BSS section at 0x" + Integer.toHexString(bssSectionAddr) + - " (" + bssSectionSize + " == 0x" + Integer.toHexString(bssSectionSize) + " bytes)"); - } else { - logger.fatal(getContikiFirmwareFile().getName() + ": no BSS section found"); - } - if (commonSectionAddr >= 0) { - logger.info(getContikiFirmwareFile().getName() + - ": common section at 0x" + Integer.toHexString(commonSectionAddr) + - " (" + commonSectionSize + " == 0x" + Integer.toHexString(commonSectionSize) + " bytes)"); - } else { - logger.info(getContikiFirmwareFile().getName() + ": no common section found"); - } - if (readonlySectionAddr >= 0) { - logger.info(getContikiFirmwareFile().getName() + - ": readonly section at 0x" + Integer.toHexString(readonlySectionAddr) + - " (" + readonlySectionSize + " == 0x" + Integer.toHexString(readonlySectionSize) + " bytes)"); - } else { - logger.warn(getContikiFirmwareFile().getName() + ": no readonly section found"); - } - if (addresses.size() == 0) { - throw new MoteTypeCreationException("Library variables parsing failed"); - } - if (dataSectionAddr <= 0 || dataSectionSize <= 0 - || bssSectionAddr <= 0 || bssSectionSize <= 0) { - throw new MoteTypeCreationException("Library section addresses parsing failed"); - } - - try { - /* Relative <-> absolute addresses offset */ - int referenceVar = addresses.get("referenceVar"); - myCoreComm.setReferenceAddress(referenceVar); - } catch (Exception e) { - throw (MoteTypeCreationException) new MoteTypeCreationException( - "JNI call error: " + e.getMessage()).initCause(e); - } - /* We first need the value of Contiki's referenceVar, which tells us the * memory offset between Contiki's variable and the relative addresses that * were calculated directly from the library file. * * This offset will be used in Cooja in the memory abstraction to match * Contiki's and Cooja's address spaces */ - int offset; { - SectionMoteMemory tmp = new SectionMoteMemory(addresses, 0); - byte[] data = new byte[dataSectionSize]; - getCoreMemory(dataSectionAddr, dataSectionSize, data); - tmp.setMemorySegment(dataSectionAddr, data); - byte[] bss = new byte[bssSectionSize]; - getCoreMemory(bssSectionAddr, bssSectionSize, bss); - tmp.setMemorySegment(bssSectionAddr, bss); + SectionMoteMemory tmp = new SectionMoteMemory(variables); + VarMemory varMem = new VarMemory(tmp); + tmp.addMemorySection("tmp.data", dataSecParser.parse(0)); - offset = tmp.getIntValueOf("referenceVar"); - logger.info(getContikiFirmwareFile().getName() + - ": offsetting Cooja mote address space: " + offset); + tmp.addMemorySection("tmp.bss", bssSecParser.parse(0)); + + try { + int referenceVar = (int) varMem.getVariable("referenceVar").addr; + myCoreComm.setReferenceAddress(referenceVar); + } catch (UnknownVariableException e) { + throw new MoteTypeCreationException("Error setting reference variable: " + e.getMessage(), e); + } catch (RuntimeException e) { + throw new MoteTypeCreationException("Error setting reference variable: " + e.getMessage(), e); + } + + getCoreMemory(tmp); + + offset = varMem.getIntValueOf("referenceVar") & 0xFFFFFFFFL; + logger.info(getContikiFirmwareFile().getName() + + ": offsetting Cooja mote address space: 0x" + Long.toHexString(offset)); } /* Create initial memory: data+bss+optional common */ - initialMemory = new SectionMoteMemory(addresses, offset); + initialMemory = new SectionMoteMemory(variables); - byte[] initialDataSection = new byte[dataSectionSize]; - getCoreMemory(dataSectionAddr, dataSectionSize, initialDataSection); - initialMemory.setMemorySegmentNative(dataSectionAddr, initialDataSection); + initialMemory.addMemorySection("data", dataSecParser.parse(offset)); - byte[] initialBssSection = new byte[bssSectionSize]; - getCoreMemory(bssSectionAddr, bssSectionSize, initialBssSection); - initialMemory.setMemorySegmentNative(bssSectionAddr, initialBssSection); + initialMemory.addMemorySection("bss", bssSecParser.parse(offset)); - if (commonSectionAddr >= 0 && commonSectionSize > 0) { - byte[] initialCommonSection = new byte[commonSectionSize]; - getCoreMemory(commonSectionAddr, commonSectionSize, initialCommonSection); - initialMemory.setMemorySegmentNative(commonSectionAddr, initialCommonSection); + initialMemory.addMemorySection("common", commonSecParser.parse(offset)); + + if (readonlySecParser != null) { + initialMemory.addMemorySection("readonly", readonlySecParser.parse(offset)); } - /* Read "read-only" memory */ - if (readonlySectionAddr >= 0 && readonlySectionSize > 0) { - byte[] readonlySection = new byte[readonlySectionSize]; - getCoreMemory(readonlySectionAddr, readonlySectionSize, readonlySection); - initialMemory.setReadonlyMemorySegment(readonlySectionAddr+offset, readonlySection); + getCoreMemory(initialMemory); + } + + /** + * Abstract base class for concrete section parser class. + */ + public static abstract class SectionParser { + + private final String[] mapFileData; + protected int startAddr; + protected int size; + + public SectionParser(String[] mapFileData) { + this.mapFileData = mapFileData; + } + + public String[] getData() { + return mapFileData; + } + + public int getStartAddr() { + return startAddr; + } + + public int getSize() { + return size; + } + + protected abstract void parseStartAddr(); + + protected abstract void parseSize(); + + abstract Map parseSymbols(long offset); + + protected int parseFirstHexInt(String regexp, String[] data) { + String retString = getFirstMatchGroup(data, regexp, 1); + + if (retString == null || retString.equals("")) { + return -1; + } + + return Integer.parseInt(retString.trim(), 16); + } + + public MemoryInterface parse(long offset) { + + /* Parse start address and size of section */ + parseStartAddr(); + parseSize(); + + if (getStartAddr() < 0 || getSize() <= 0) { + return null; + } + + Map variables = parseSymbols(offset); + + logger.info(String.format("Parsed section at 0x%x ( %d == 0x%x bytes)", + getStartAddr() + offset, + getSize(), + getSize())); + + if (logger.isDebugEnabled()) { + for (String var : variables.keySet()) { + logger.debug(String.format("Found Symbol: %s, 0x%x, %d", + var, + variables.get(var).addr, + variables.get(var).size)); + } + } + + return new ArrayMemory( + getStartAddr() + offset, + getSize(), + MemoryLayout.getNative(), + variables); + } + + } + + /** + * Parses Map file for seciton data. + */ + public static class MapSectionParser extends SectionParser { + + private final String startRegExp; + private final String sizeRegExp; + + public MapSectionParser(String[] mapFileData, String startRegExp, String sizeRegExp) { + super(mapFileData); + this.startRegExp = startRegExp; + this.sizeRegExp = sizeRegExp; + } + + @Override + protected void parseStartAddr() { + if (startRegExp == null || startRegExp.equals("")) { + startAddr = -1; + return; + } + startAddr = parseFirstHexInt(startRegExp, getData()); + } + + @Override + protected void parseSize() { + if (sizeRegExp == null || sizeRegExp.equals("")) { + size = -1; + return; + } + size = parseFirstHexInt(sizeRegExp, getData()); + } + + @Override + public Map parseSymbols(long offset) { + Map varNames = new HashMap<>(); + + Pattern pattern = Pattern.compile(Cooja.getExternalToolsSetting("MAPFILE_VAR_NAME")); + for (String line : getData()) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + if (Integer.decode(matcher.group(1)).intValue() >= getStartAddr() + && Integer.decode(matcher.group(1)).intValue() <= getStartAddr() + getSize()) { + String varName = matcher.group(2); + varNames.put(varName, new Symbol( + Symbol.Type.VARIABLE, + varName, + getMapFileVarAddress(getData(), varName) + offset, + getMapFileVarSize(getData(), varName))); + } + } + } + return varNames; + } + + /** + * Get relative address of variable with given name. + * + * @param varName Name of variable + * @return Relative memory address of variable or -1 if not found + */ + private int getMapFileVarAddress(String[] mapFileData, String varName) { + + String regExp = Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_1") + + varName + + Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); + String retString = getFirstMatchGroup(mapFileData, regExp, 1); + + if (retString != null) { + return Integer.parseInt(retString.trim(), 16); + } else { + return -1; + } + } + + private int getMapFileVarSize(String[] mapFileData, String varName) { + Pattern pattern = Pattern.compile( + Cooja.getExternalToolsSetting("MAPFILE_VAR_SIZE_1") + + varName + + Cooja.getExternalToolsSetting("MAPFILE_VAR_SIZE_2")); + for (int idx = 0; idx < mapFileData.length; idx++) { + String parseString = mapFileData[idx]; + Matcher matcher = pattern.matcher(parseString); + if (matcher.find()) { + return Integer.decode(matcher.group(1)); + } + // second approach with lines joined + if (idx < mapFileData.length - 1) { + parseString += mapFileData[idx + 1]; + } + matcher = pattern.matcher(parseString); + if (matcher.find()) { + return Integer.decode(matcher.group(1)); + } + } + return -1; + } + } + + /** + * Parses command output for section data. + */ + public static class CommandSectionParser extends SectionParser { + + private final String startRegExp; + private final String endRegExp; + private final String sectionRegExp; + + /** + * Creates SectionParser based on output of configurable command. + * + * @param mapFileData Map file lines as array of String + * @param startRegExp Regular expression for parsing start of section + * @param endRegExp Regular expression for parsing end of section + * @param sectionRegExp Reqular expression describing symbol table section identifier (e.g. '[Rr]' for readonly) + * Will be used to replaced '

'in 'COMMAND_VAR_NAME_ADDRESS_SIZE' + */ + public CommandSectionParser(String[] mapFileData, String startRegExp, String endRegExp, String sectionRegExp) { + super(mapFileData); + this.startRegExp = startRegExp; + this.endRegExp = endRegExp; + this.sectionRegExp = sectionRegExp; + } + + @Override + protected void parseStartAddr() { + if (startRegExp == null || startRegExp.equals("")) { + startAddr = -1; + return; + } + startAddr = parseFirstHexInt(startRegExp, getData()); + } + + @Override + public void parseSize() { + if (endRegExp == null || endRegExp.equals("")) { + size = -1; + return; + } + + if (getStartAddr() < 0) { + size = -1; + return; + } + + int end = parseFirstHexInt(endRegExp, getData()); + if (end < 0) { + size = -1; + return; + } + size = end - getStartAddr(); + } + + @Override + public Map parseSymbols(long offset) { + HashMap addresses = new HashMap<>(); + /* Replace "
" in regexp by section specific regex */ + Pattern pattern = Pattern.compile( + Cooja.getExternalToolsSetting("COMMAND_VAR_NAME_ADDRESS_SIZE") + .replace("
", sectionRegExp)); + + for (String line : getData()) { + Matcher matcher = pattern.matcher(line); + + if (matcher.find()) { + /* Line matched variable address */ + String symbol = matcher.group(1); + long varAddr = Integer.parseInt(matcher.group(2), 16) + offset; + int varSize; + if (matcher.group(3) != null) { + varSize = Integer.parseInt(matcher.group(3), 16); + } else { + varSize = -1; + } + + /* XXX needs to be checked */ + if (!addresses.containsKey(symbol)) { + addresses.put(symbol, new Symbol(Symbol.Type.VARIABLE, symbol, varAddr, varSize)); + } else { + int oldAddress = (int) addresses.get(symbol).addr; + if (oldAddress != varAddr) { + /*logger.warn("Warning, command response not matching previous entry of: " + + varName);*/ + } + } + } + } + + return addresses; } } @@ -558,97 +805,6 @@ public class ContikiMoteType implements MoteType { return initialMemory.clone(); } - /** - * Copy given memory to the Contiki system. This should not be used directly, - * but instead via ContikiMote.setMemory(). - * - * @param mem - * New memory - */ - public void setCoreMemory(SectionMoteMemory mem) { - for (int i = 0; i < mem.getNumberOfSections(); i++) { - setCoreMemory( - mem.getSectionNativeAddress(i) /* native address space */, - mem.getSizeOfSection(i), mem.getDataOfSection(i)); - } - } - - /** - * Parses specified map file data for variable name to addresses mappings. The - * mappings are added to the given properties object. - * - * @param mapFileData - * Contents of entire map file - * @param varAddresses - * Properties that should contain the name to addresses mappings. - */ - public static boolean parseMapFileData(String[] mapFileData, HashMap varAddresses) { - String[] varNames = getMapFileVarNames(mapFileData); - if (varNames == null || varNames.length == 0) { - return false; - } - - for (String varName : varNames) { - int varAddress = getMapFileVarAddress(mapFileData, varName, varAddresses); - if (varAddress > 0) { - varAddresses.put(varName, new Integer(varAddress)); - } else { - logger.warn("Parsed Contiki variable '" + varName - + "' but could not find address"); - } - } - - return true; - } - - /** - * Parses parse command output for variable name to addresses mappings. - * The mappings are written to the given properties object. - * - * @param output Command output - * @param addresses Variable addresses mappings - */ - public static boolean parseCommandData(String[] output, HashMap addresses) { - int nrNew = 0, nrOld = 0, nrMismatch = 0; - - Pattern pattern = - Pattern.compile(Cooja.getExternalToolsSetting("COMMAND_VAR_NAME_ADDRESS")); - - for (String line : output) { - Matcher matcher = pattern.matcher(line); - - if (matcher.find()) { - /* Line matched variable address */ - String symbol = matcher.group(2); - int address = Integer.parseInt(matcher.group(1), 16); - - if (!addresses.containsKey(symbol)) { - nrNew++; - addresses.put(symbol, new Integer(address)); - } else { - int oldAddress = addresses.get(symbol); - if (oldAddress != address) { - /*logger.warn("Warning, command response not matching previous entry of: " - + varName);*/ - nrMismatch++; - } - nrOld++; - } - } - } - - /*if (nrMismatch > 0) { - logger.debug("Command response parsing summary: Added " + nrNew - + " variables. Found " + nrOld - + " old variables. Mismatching addresses: " + nrMismatch); - } else { - logger.debug("Command response parsing summary: Added " + nrNew - + " variables. Found " + nrOld + " old variables"); - }*/ - - return (nrNew + nrOld) > 0; - } - /** * Copy core memory to given memory. This should not be used directly, but * instead via ContikiMote.getMemory(). @@ -657,42 +813,74 @@ public class ContikiMoteType implements MoteType { * Memory to set */ public void getCoreMemory(SectionMoteMemory mem) { - for (int i = 0; i < mem.getNumberOfSections(); i++) { - int startAddr = mem.getSectionNativeAddress(i); /* native address space */ - int size = mem.getSizeOfSection(i); - byte[] data = mem.getDataOfSection(i); - getCoreMemory(startAddr, size, data); + for (MemoryInterface section : mem.getSections().values()) { + getCoreMemory( + (int) (section.getStartAddr() - offset), + section.getTotalSize(), + section.getMemory()); } } + private void getCoreMemory(int relAddr, int length, byte[] data) { + myCoreComm.getMemory(relAddr, length, data); + } + + /** + * Copy given memory to the Contiki system. This should not be used directly, + * but instead via ContikiMote.setMemory(). + * + * @param mem + * New memory + */ + public void setCoreMemory(SectionMoteMemory mem) { + for (MemoryInterface section : mem.getSections().values()) { + setCoreMemory( + (int) (section.getStartAddr() - offset), + section.getTotalSize(), + section.getMemory()); + } + } + + private void setCoreMemory(int relAddr, int length, byte[] mem) { + myCoreComm.setMemory(relAddr, length, mem); + } + + @Override public String getIdentifier() { return identifier; } + @Override public void setIdentifier(String identifier) { this.identifier = identifier; } + @Override public File getContikiSourceFile() { return fileSource; } + @Override public void setContikiSourceFile(File file) { fileSource = file; } + @Override public File getContikiFirmwareFile() { return fileFirmware; } + @Override public void setContikiFirmwareFile(File file) { fileFirmware = file; } + @Override public String getCompileCommands() { return compileCommands; } + @Override public void setCompileCommands(String commands) { this.compileCommands = commands; } @@ -725,42 +913,10 @@ public class ContikiMoteType implements MoteType { return netStack; } - /** - * Get relative address of variable with given name. - * - * @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 varAddresses) { - Integer varAddrInteger; - if ((varAddrInteger = varAddresses.get(varName)) != null) { - return varAddrInteger.intValue(); - } - - String regExp = - Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_1") + - varName + - Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); - String retString = getFirstMatchGroup(mapFileData, regExp, 1); - - if (retString != null) { - varAddrInteger = Integer.parseInt(retString.trim(), 16); - varAddresses.put(varName, varAddrInteger); - return varAddrInteger.intValue(); - } else { - return -1; - } - } - - private void getCoreMemory(int relAddr, int length, byte[] data) { - myCoreComm.getMemory(relAddr, length, data); - } - - private void setCoreMemory(int relAddr, int length, byte[] mem) { - myCoreComm.setMemory(relAddr, length, mem); - } - private static String getFirstMatchGroup(String[] lines, String regexp, int groupNr) { + if (regexp == null) { + return null; + } Pattern pattern = Pattern.compile(regexp); for (String line : lines) { Matcher matcher = pattern.matcher(line); @@ -771,219 +927,6 @@ public class ContikiMoteType implements MoteType { return null; } - /** - * Returns all variable names in both data and BSS section by parsing the map - * file. These values should not be trusted completely as the parsing may - * fail. - * - * @return Variable names found in the data and bss section - */ - public static String[] getMapFileVarNames(String[] mapFileData) { - ArrayList varNames = new ArrayList(); - - String[] dataVariables = getAllVariableNames( - mapFileData, - parseMapDataSectionAddr(mapFileData), - parseMapDataSectionAddr(mapFileData) + parseMapDataSectionSize(mapFileData)); - for (String v: dataVariables) { - varNames.add(v); - } - - String[] bssVariables = getAllVariableNames( - mapFileData, - parseMapBssSectionAddr(mapFileData), - parseMapBssSectionAddr(mapFileData) + parseMapBssSectionSize(mapFileData)); - for (String v: bssVariables) { - varNames.add(v); - } - - return varNames.toArray(new String[0]); - } - - private static String[] getAllVariableNames(String[] lines, - int startAddress, int endAddress) { - ArrayList varNames = new ArrayList(); - - Pattern pattern = Pattern.compile(Cooja.getExternalToolsSetting("MAPFILE_VAR_NAME")); - for (String line : lines) { - Matcher matcher = pattern.matcher(line); - if (matcher.find()) { - if (Integer.decode(matcher.group(1)).intValue() >= startAddress - && Integer.decode(matcher.group(1)).intValue() <= endAddress) { - varNames.add(matcher.group(2)); - } - } - } - return varNames.toArray(new String[0]); - } - - protected int getVariableSize(Vector lines, String varName) { - Pattern pattern = Pattern.compile( - Cooja.getExternalToolsSetting("MAPFILE_VAR_SIZE_1") + - varName + - Cooja.getExternalToolsSetting("MAPFILE_VAR_SIZE_2")); - for (int i = 0; i < lines.size(); i++) { - Matcher matcher = pattern.matcher(lines.get(i)); - if (matcher.find()) { - return Integer.decode(matcher.group(1)); - } - } - return -1; - } - - private static int parseFirstHexInt(String regexp, String[] data) { - String retString = - getFirstMatchGroup(data, regexp, 1); - - if (retString != null) { - return Integer.parseInt(retString.trim(), 16); - } else { - return -1; - } - } - - public static int parseMapDataSectionAddr(String[] mapFileData) { - String regexp = Cooja.getExternalToolsSetting("MAPFILE_DATA_START", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, mapFileData); - } - public static int parseMapDataSectionSize(String[] mapFileData) { - String regexp = Cooja.getExternalToolsSetting("MAPFILE_DATA_SIZE", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, mapFileData); - } - public static int parseMapBssSectionAddr(String[] mapFileData) { - String regexp = Cooja.getExternalToolsSetting("MAPFILE_BSS_START", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, mapFileData); - } - public static int parseMapBssSectionSize(String[] mapFileData) { - String regexp = Cooja.getExternalToolsSetting("MAPFILE_BSS_SIZE", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, mapFileData); - } - public static int parseMapCommonSectionAddr(String[] mapFileData) { - String regexp = Cooja.getExternalToolsSetting("MAPFILE_COMMON_START", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, mapFileData); - } - public static int parseMapCommonSectionSize(String[] mapFileData) { - String regexp = Cooja.getExternalToolsSetting("MAPFILE_COMMON_SIZE", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, mapFileData); - } - - public static int parseCommandDataSectionAddr(String[] output) { - String regexp = Cooja.getExternalToolsSetting("COMMAND_DATA_START", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, output); - } - public static int parseCommandDataSectionSize(String[] output) { - String regexp = Cooja.getExternalToolsSetting("COMMAND_DATA_END", ""); - if (regexp.equals("")) { - return -1; - } - int start = parseCommandDataSectionAddr(output); - if (start < 0) { - return -1; - } - - int end = parseFirstHexInt(regexp, output); - if (end < 0) { - return -1; - } - return end - start; - } - public static int parseCommandBssSectionAddr(String[] output) { - String regexp = Cooja.getExternalToolsSetting("COMMAND_BSS_START", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, output); - } - public static int parseCommandBssSectionSize(String[] output) { - String regexp = Cooja.getExternalToolsSetting("COMMAND_BSS_END", ""); - if (regexp.equals("")) { - return -1; - } - int start = parseCommandBssSectionAddr(output); - if (start < 0) { - return -1; - } - - int end = parseFirstHexInt(regexp, output); - if (end < 0) { - return -1; - } - return end - start; - } - public static int parseCommandCommonSectionAddr(String[] output) { - String regexp = Cooja.getExternalToolsSetting("COMMAND_COMMON_START", ""); - if (regexp.equals("")) { - return -1; - } - return parseFirstHexInt(regexp, output); - } - public static int parseCommandCommonSectionSize(String[] output) { - String regexp = Cooja.getExternalToolsSetting("COMMAND_COMMON_END", ""); - if (regexp.equals("")) { - return -1; - } - int start = parseCommandCommonSectionAddr(output); - if (start < 0) { - return -1; - } - - int end = parseFirstHexInt(regexp, output); - if (end < 0) { - return -1; - } - return end - start; - } - - private static int parseCommandReadonlySectionAddr(String[] output) { - return parseFirstHexInt("^([0-9A-Fa-f]*)[ \t]t[ \t].text$", output); - } - private static int parseCommandReadonlySectionSize(String[] output) { - int start = parseCommandReadonlySectionAddr(output); - if (start < 0) { - return -1; - } - - /* Extract the last specified address, assuming that the interval covers all the memory */ - String last = output[output.length-1]; - int lastAddress = Integer.parseInt(last.split("[ \t]")[0],16); - return lastAddress - start; - } - - private static int getRelVarAddr(String mapFileData[], String varName) { - String regExp = - Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_1") + - varName + - Cooja.getExternalToolsSetting("MAPFILE_VAR_ADDRESS_2"); - String retString = getFirstMatchGroup(mapFileData, regExp, 1); - - if (retString != null) { - return Integer.parseInt(retString.trim(), 16); - } else { - return -1; - } - } - public static String[] loadMapFile(File mapFile) { String contents = StringUtils.loadFromFile(mapFile); if (contents == null) { @@ -999,7 +942,7 @@ public class ContikiMoteType implements MoteType { * @return Execution response, or null at failure */ public static String[] loadCommandData(File libraryFile) { - ArrayList output = new ArrayList(); + ArrayList output = new ArrayList<>(); try { String command = Cooja.getExternalToolsSetting("PARSE_COMMAND"); @@ -1009,17 +952,17 @@ public class ContikiMoteType implements MoteType { /* Prepare command */ command = command.replace("$(LIBFILE)", - libraryFile.getName().replace(File.separatorChar, '/')); + libraryFile.getName().replace(File.separatorChar, '/')); /* Execute command, read response */ String line; Process p = Runtime.getRuntime().exec( - command.split(" "), - null, - libraryFile.getParentFile() + command.split(" "), + null, + libraryFile.getParentFile() ); BufferedReader input = new BufferedReader( - new InputStreamReader(p.getInputStream()) + new InputStreamReader(p.getInputStream()) ); p.getErrorStream().close(); while ((line = input.readLine()) != null) { @@ -1027,24 +970,27 @@ public class ContikiMoteType implements MoteType { } input.close(); - if (output == null || output.size() == 0) { + if (output == null || output.isEmpty()) { return null; } return output.toArray(new String[0]); - } catch (Exception err) { + } catch (IOException err) { logger.fatal("Command error: " + err.getMessage(), err); return null; } } + @Override public String getDescription() { return description; } + @Override public void setDescription(String newDescription) { description = newDescription; } + @Override public ProjectConfig getConfig() { return myConfig; } @@ -1054,7 +1000,7 @@ public class ContikiMoteType implements MoteType { * simulator project configuration. * * @param moteTypeConfig - * Project configuration + * Project configuration */ public void setConfig(ProjectConfig moteTypeConfig) { myConfig = moteTypeConfig; @@ -1082,12 +1028,13 @@ public class ContikiMoteType implements MoteType { * Set core interfaces * * @param coreInterfaces - * New core interfaces + * New core interfaces */ public void setCoreInterfaces(String[] coreInterfaces) { this.coreInterfaces = coreInterfaces; } + @Override public Class[] getMoteInterfaceClasses() { if (moteInterfacesClasses == null) { return null; @@ -1097,11 +1044,10 @@ public class ContikiMoteType implements MoteType { return arr; } + @Override public void setMoteInterfaceClasses(Class[] moteInterfaces) { - this.moteInterfacesClasses = new ArrayList>(); - for (Class intf: moteInterfaces) { - this.moteInterfacesClasses.add(intf); - } + this.moteInterfacesClasses = new ArrayList<>(); + this.moteInterfacesClasses.addAll(Arrays.asList(moteInterfaces)); } /** @@ -1109,7 +1055,7 @@ public class ContikiMoteType implements MoteType { * when loading a saved simulation. * * @param file - * File containg data to checksum + * File containg data to checksum * @return Checksum */ protected byte[] createChecksum(File file) { @@ -1128,9 +1074,7 @@ public class ContikiMoteType implements MoteType { } } fileInputStream.close(); - } catch (NoSuchAlgorithmException e) { - return null; - } catch (IOException e) { + } catch (NoSuchAlgorithmException | IOException e) { return null; } return messageDigest.digest(); @@ -1177,8 +1121,8 @@ public class ContikiMoteType implements MoteType { // Check if identifier library has been loaded /* XXX Currently only checks the build directory! */ File libraryFile = new File( - ContikiMoteType.tempOutputDirectory, - testID + ContikiMoteType.librarySuffix); + ContikiMoteType.tempOutputDirectory, + testID + ContikiMoteType.librarySuffix); if (libraryFile.exists() || CoreComm.hasLibraryFileBeenLoaded(libraryFile)) { okID = false; } @@ -1192,45 +1136,46 @@ public class ContikiMoteType implements MoteType { * * @return Mote type visualizer */ + @Override public JComponent getTypeVisualizer() { StringBuilder sb = new StringBuilder(); // Identifier sb.append(""); + .append(getIdentifier()).append(""); // Description sb.append(""); + .append(getDescription()).append(""); /* Contiki application */ sb.append(""); + .append(getContikiSourceFile().getAbsolutePath()).append(""); /* Contiki firmware */ sb.append(""); + .append(getContikiFirmwareFile().getAbsolutePath()).append(""); /* JNI class */ sb.append(""); + .append(this.javaClassName).append(""); /* Contiki sensors */ sb.append(""); /* Mote interfaces */ sb.append(""); /* Contiki core mote interfaces */ sb.append(""); @@ -1240,8 +1185,9 @@ public class ContikiMoteType implements MoteType { return label; } + @Override public Collection getConfigXML(Simulation simulation) { - ArrayList config = new ArrayList(); + ArrayList config = new ArrayList<>(); Element element; element = new Element("identifier"); @@ -1280,9 +1226,10 @@ public class ContikiMoteType implements MoteType { return config; } + @Override public boolean setConfigXML(Simulation simulation, - Collection configXML, boolean visAvailable) - throws MoteTypeCreationException { + Collection configXML, boolean visAvailable) + throws MoteTypeCreationException { boolean warnedOldVersion = false; File oldVersionSource = null; @@ -1290,91 +1237,87 @@ public class ContikiMoteType implements MoteType { for (Element element : configXML) { String name = element.getName(); - - if (name.equals("identifier")) { - identifier = element.getText(); - } else if (name.equals("description")) { - description = element.getText(); - } else if (name.equals("contikiapp") || name.equals("source")) { - File file = new File(element.getText()); - if (!file.exists()) { - file = simulation.getCooja().restorePortablePath(file); - } - - setContikiSourceFile(file); - - /* XXX Do not load the generated firmware. Instead, load the unique library file directly */ + switch (name) { + case "identifier": + identifier = element.getText(); + break; + case "description": + description = element.getText(); + break; + case "contikiapp": + case "source": + File file = new File(element.getText()); + if (!file.exists()) { + file = simulation.getCooja().restorePortablePath(file); + } setContikiSourceFile(file); + /* XXX Do not load the generated firmware. Instead, load the unique library file directly */ File contikiFirmware = new File( - getContikiSourceFile().getParentFile(), - "obj_cooja/" + getIdentifier() + librarySuffix); - setContikiFirmwareFile(contikiFirmware); - - } else if (name.equals("commands")) { - compileCommands = element.getText(); - } else if (name.equals("symbols")) { - hasSystemSymbols = Boolean.parseBoolean(element.getText()); - } else if (name.equals("commstack")) { - logger.warn("The Cooja communication stack config was removed: " + element.getText()); - logger.warn("Instead assuming default network stack."); - netStack = NetworkStack.DEFAULT; - } else if (name.equals("netstack")) { - netStack = NetworkStack.parseConfig(element.getText()); - } else if (name.equals("moteinterface")) { - String intfClass = element.getText().trim(); - - /* Backwards compatibility: se.sics -> org.contikios */ - if (intfClass.startsWith("se.sics")) { - intfClass = intfClass.replaceFirst("se\\.sics", "org.contikios"); - } - - Class moteInterfaceClass = - simulation.getCooja().tryLoadClass( - this, MoteInterface.class, intfClass); - + getContikiSourceFile().getParentFile(), + "obj_cooja/" + getIdentifier() + librarySuffix); + setContikiFirmwareFile(contikiFirmware); + break; + case "commands": + compileCommands = element.getText(); + break; + case "symbols": + hasSystemSymbols = Boolean.parseBoolean(element.getText()); + break; + case "commstack": + logger.warn("The Cooja communication stack config was removed: " + element.getText()); + logger.warn("Instead assuming default network stack."); + netStack = NetworkStack.DEFAULT; + break; + case "netstack": + netStack = NetworkStack.parseConfig(element.getText()); + break; + case "moteinterface": + String intfClass = element.getText().trim(); + /* Backwards compatibility: se.sics -> org.contikios */ + if (intfClass.startsWith("se.sics")) { + intfClass = intfClass.replaceFirst("se\\.sics", "org.contikios"); + } Class moteInterfaceClass + = simulation.getCooja().tryLoadClass( + this, MoteInterface.class, intfClass); if (moteInterfaceClass == null) { logger.warn("Can't find mote interface class: " + intfClass); } else { moteInterfacesClasses.add(moteInterfaceClass); - } - } else if ( - name.equals("contikibasedir") || - name.equals("contikicoredir") || - name.equals("projectdir") || - name.equals("compilefile") || - name.equals("process") || - name.equals("sensor") || - name.equals("coreinterface")) { - /* Backwards compatibility: old cooja mote type is being loaded */ - if (!warnedOldVersion) { - warnedOldVersion = true; - logger.warn("Old simulation config detected: Cooja mote types may not load correctly"); - } - - if (name.equals("compilefile")) { + } break; + case "contikibasedir": + case "contikicoredir": + case "projectdir": + case "compilefile": + case "process": + case "sensor": + case "coreinterface": + /* Backwards compatibility: old cooja mote type is being loaded */ + if (!warnedOldVersion) { + warnedOldVersion = true; + logger.warn("Old simulation config detected: Cooja mote types may not load correctly"); + } if (name.equals("compilefile")) { if (element.getText().endsWith(".c")) { File potentialFile = new File(element.getText()); if (potentialFile.exists()) { oldVersionSource = potentialFile; } } - } - - } else { - logger.fatal("Unrecognized entry in loaded configuration: " + name); + } break; + default: + logger.fatal("Unrecognized entry in loaded configuration: " + name); + break; } } /* Create initial core interface dependencies */ - Class[] arr = - new Class[moteInterfacesClasses.size()]; + Class[] arr + = new Class[moteInterfacesClasses.size()]; moteInterfacesClasses.toArray(arr); setCoreInterfaces(ContikiMoteType.getRequiredCoreInterfaces(arr)); /* Backwards compatibility: old cooja mote type is being loaded */ - if (getContikiSourceFile() == null && - warnedOldVersion && - oldVersionSource != null) - { + if (getContikiSourceFile() == null + && warnedOldVersion + && oldVersionSource != null) { /* Guess Contiki source */ setContikiSourceFile(oldVersionSource); logger.info("Guessing Contiki source: " + oldVersionSource.getAbsolutePath()); @@ -1383,8 +1326,8 @@ public class ContikiMoteType implements MoteType { logger.info("Guessing Contiki firmware: " + getContikiFirmwareFile().getAbsolutePath()); /* Guess compile commands */ - String compileCommands = - "make " + getExpectedFirmwareFile(oldVersionSource).getName() + " TARGET=cooja"; + String compileCommands + = "make " + getExpectedFirmwareFile(oldVersionSource).getName() + " TARGET=cooja"; logger.info("Guessing compile commands: " + compileCommands); setCompileCommands(compileCommands); } @@ -1394,10 +1337,10 @@ public class ContikiMoteType implements MoteType { } public static String[] getRequiredCoreInterfaces( - Class[] moteInterfaces) { + Class[] moteInterfaces) { /* Extract Contiki dependencies from currently selected mote interfaces */ - ArrayList coreInterfacesList = new ArrayList(); - for (Class intf: moteInterfaces) { + ArrayList coreInterfacesList = new ArrayList<>(); + for (Class intf : moteInterfaces) { if (!ContikiMoteInterface.class.isAssignableFrom(intf)) { continue; } @@ -1416,10 +1359,7 @@ public class ContikiMoteType implements MoteType { if (deps == null || deps.length == 0) { continue; } - - for (String dep: deps) { - coreInterfacesList.add(dep); - } + coreInterfacesList.addAll(Arrays.asList(deps)); } String[] coreInterfaces = new String[coreInterfacesList.size()]; diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiBeeper.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiBeeper.java index c9ef326a9..01f9c757e 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiBeeper.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiBeeper.java @@ -44,10 +44,11 @@ import org.apache.log4j.Logger; import org.jdom.Element; import org.contikios.cooja.Mote; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.Beeper; import org.contikios.cooja.interfaces.PolledAfterActiveTicks; +import org.contikios.cooja.mote.memory.VarMemory; /** * Beeper mote interface. @@ -70,7 +71,7 @@ import org.contikios.cooja.interfaces.PolledAfterActiveTicks; */ public class ContikiBeeper extends Beeper implements ContikiMoteInterface, PolledAfterActiveTicks { private Mote mote = null; - private SectionMoteMemory moteMem = null; + private VarMemory moteMem = null; private static Logger logger = Logger.getLogger(ContikiBeeper.class); /** @@ -83,7 +84,7 @@ public class ContikiBeeper extends Beeper implements ContikiMoteInterface, Polle */ public ContikiBeeper(Mote mote) { this.mote = mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public boolean isBeeping() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiButton.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiButton.java index 57f7b7fd6..852383a09 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiButton.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiButton.java @@ -40,6 +40,7 @@ import org.contikios.cooja.*; import org.contikios.cooja.contikimote.ContikiMote; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.Button; +import org.contikios.cooja.mote.memory.VarMemory; /** * Button mote interface. @@ -62,7 +63,7 @@ import org.contikios.cooja.interfaces.Button; * @author Fredrik Osterlind */ public class ContikiButton extends Button implements ContikiMoteInterface { - private SectionMoteMemory moteMem; + private VarMemory moteMem; private ContikiMote mote; private static Logger logger = Logger.getLogger(ContikiButton.class); @@ -76,7 +77,7 @@ public class ContikiButton extends Button implements ContikiMoteInterface { */ public ContikiButton(Mote mote) { this.mote = (ContikiMote) mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiCFS.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiCFS.java index e831a1607..5a8dbb41e 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiCFS.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiCFS.java @@ -43,6 +43,7 @@ import org.jdom.Element; import org.contikios.cooja.*; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.PolledAfterActiveTicks; +import org.contikios.cooja.mote.memory.VarMemory; /** * Contiki FileSystem (CFS) interface (such as external flash). @@ -71,7 +72,7 @@ public class ContikiCFS extends MoteInterface implements ContikiMoteInterface, P public int FILESYSTEM_SIZE = 4000; /* Configure CFS size here and in cfs-cooja.c */ private Mote mote = null; - private SectionMoteMemory moteMem = null; + private VarMemory moteMem = null; private int lastRead = 0; private int lastWritten = 0; @@ -85,7 +86,7 @@ public class ContikiCFS extends MoteInterface implements ContikiMoteInterface, P */ public ContikiCFS(Mote mote) { this.mote = mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiClock.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiClock.java index 3864c4724..127a7a3a7 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiClock.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiClock.java @@ -37,13 +37,14 @@ import org.apache.log4j.Logger; import org.jdom.Element; import org.contikios.cooja.Mote; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.Simulation; import org.contikios.cooja.contikimote.ContikiMote; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.Clock; import org.contikios.cooja.interfaces.PolledAfterAllTicks; import org.contikios.cooja.interfaces.PolledBeforeActiveTicks; +import org.contikios.cooja.mote.memory.VarMemory; /** * Clock mote interface. Controls Contiki time. @@ -71,7 +72,7 @@ public class ContikiClock extends Clock implements ContikiMoteInterface, PolledB private Simulation simulation; private ContikiMote mote; - private SectionMoteMemory moteMem; + private VarMemory moteMem; private long moteTime; /* Microseconds */ private long timeDrift; /* Microseconds */ @@ -85,7 +86,7 @@ public class ContikiClock extends Clock implements ContikiMoteInterface, PolledB public ContikiClock(Mote mote) { this.simulation = mote.getSimulation(); this.mote = (ContikiMote) mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); timeDrift = 0; moteTime = 0; } diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java index a1b1d5e56..aeca322d1 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java @@ -45,6 +45,7 @@ import org.jdom.Element; import org.contikios.cooja.*; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.PolledAfterActiveTicks; +import org.contikios.cooja.mote.memory.VarMemory; /** * Contiki EEPROM interface @@ -73,7 +74,7 @@ public class ContikiEEPROM extends MoteInterface implements ContikiMoteInterface public int EEPROM_SIZE = 1024; /* Configure EEPROM size here and in eeprom.c. Should really be multiple of 16 */ private Mote mote = null; - private SectionMoteMemory moteMem = null; + private VarMemory moteMem = null; private int lastRead = 0; private int lastWritten = 0; @@ -87,7 +88,7 @@ public class ContikiEEPROM extends MoteInterface implements ContikiMoteInterface */ public ContikiEEPROM(Mote mote) { this.mote = mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiLED.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiLED.java index b6372751d..cc549e142 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiLED.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiLED.java @@ -40,6 +40,7 @@ import org.contikios.cooja.*; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.LED; import org.contikios.cooja.interfaces.PolledAfterActiveTicks; +import org.contikios.cooja.mote.memory.VarMemory; /** * LEDs mote interface. @@ -64,7 +65,7 @@ public class ContikiLED extends LED implements ContikiMoteInterface, PolledAfter private static Logger logger = Logger.getLogger(ContikiLED.class); private Mote mote = null; - private SectionMoteMemory moteMem = null; + private VarMemory moteMem = null; private byte currentLedValue = 0; private static final byte LEDS_GREEN = 1; @@ -91,7 +92,7 @@ public class ContikiLED extends LED implements ContikiMoteInterface, PolledAfter */ public ContikiLED(Mote mote) { this.mote = mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiMoteID.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiMoteID.java index 8a9887638..e83d0c2fa 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiMoteID.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiMoteID.java @@ -38,6 +38,7 @@ import org.jdom.Element; import org.contikios.cooja.*; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.MoteID; +import org.contikios.cooja.mote.memory.VarMemory; /** * Mote ID interface: 'node_id'. @@ -60,7 +61,7 @@ import org.contikios.cooja.interfaces.MoteID; * @author Fredrik Osterlind */ public class ContikiMoteID extends MoteID implements ContikiMoteInterface { - private SectionMoteMemory moteMem = null; + private VarMemory moteMem = null; private static Logger logger = Logger.getLogger(ContikiMoteID.class); private int moteID = 0; @@ -77,7 +78,7 @@ public class ContikiMoteID extends MoteID implements ContikiMoteInterface { */ public ContikiMoteID(Mote mote) { this.mote = mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiPIR.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiPIR.java index 0dbb90f03..cbfb7d66c 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiPIR.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiPIR.java @@ -37,10 +37,11 @@ import javax.swing.JButton; import javax.swing.JPanel; import org.jdom.Element; import org.contikios.cooja.Mote; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.contikimote.ContikiMote; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.PIR; +import org.contikios.cooja.mote.memory.VarMemory; /** * Passive IR sensor mote interface. @@ -65,7 +66,7 @@ import org.contikios.cooja.interfaces.PIR; public class ContikiPIR extends PIR implements ContikiMoteInterface { private ContikiMote mote; - private SectionMoteMemory moteMem; + private VarMemory moteMem; /** * Creates an interface to the PIR at mote. @@ -77,7 +78,7 @@ public class ContikiPIR extends PIR implements ContikiMoteInterface { */ public ContikiPIR(Mote mote) { this.mote = (ContikiMote) mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRS232.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRS232.java index 304ffa5ae..2607bc1ea 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRS232.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRS232.java @@ -38,6 +38,7 @@ import org.contikios.cooja.contikimote.ContikiMote; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.dialogs.SerialUI; import org.contikios.cooja.interfaces.PolledAfterActiveTicks; +import org.contikios.cooja.mote.memory.VarMemory; /** * Contiki mote serial port and log interfaces. @@ -68,7 +69,7 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll private static Logger logger = Logger.getLogger(ContikiRS232.class); private ContikiMote mote = null; - private SectionMoteMemory moteMem = null; + private VarMemory moteMem = null; static final int SERIAL_BUF_SIZE = 1024; /* rs232.c:40 */ @@ -82,7 +83,7 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll */ public ContikiRS232(Mote mote) { this.mote = (ContikiMote) mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRadio.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRadio.java index ebe24e52a..5502b9a8a 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRadio.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiRadio.java @@ -39,13 +39,14 @@ import org.jdom.Element; import org.contikios.cooja.COOJARadioPacket; import org.contikios.cooja.Mote; import org.contikios.cooja.RadioPacket; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.Simulation; import org.contikios.cooja.contikimote.ContikiMote; import org.contikios.cooja.contikimote.ContikiMoteInterface; import org.contikios.cooja.interfaces.PolledAfterActiveTicks; import org.contikios.cooja.interfaces.Position; import org.contikios.cooja.interfaces.Radio; +import org.contikios.cooja.mote.memory.VarMemory; import org.contikios.cooja.radiomediums.UDGM; /** @@ -89,7 +90,7 @@ import org.contikios.cooja.radiomediums.UDGM; public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledAfterActiveTicks { private ContikiMote mote; - private SectionMoteMemory myMoteMemory; + private VarMemory myMoteMemory; private static Logger logger = Logger.getLogger(ContikiRadio.class); @@ -132,7 +133,7 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA ContikiRadio.class, "RADIO_TRANSMISSION_RATE_kbps"); this.mote = (ContikiMote) mote; - this.myMoteMemory = (SectionMoteMemory) mote.getMemory(); + this.myMoteMemory = new VarMemory(mote.getMemory()); radioOn = myMoteMemory.getByteValueOf("simRadioHWOn") == 1; } diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiVib.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiVib.java index 9584674ac..ba1920715 100644 --- a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiVib.java +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiVib.java @@ -39,9 +39,10 @@ import org.jdom.Element; import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.contikimote.ContikiMote; import org.contikios.cooja.contikimote.ContikiMoteInterface; +import org.contikios.cooja.mote.memory.VarMemory; /** * Vibration sensor mote interface. @@ -67,7 +68,7 @@ import org.contikios.cooja.contikimote.ContikiMoteInterface; public class ContikiVib extends MoteInterface implements ContikiMoteInterface { private ContikiMote mote; - private SectionMoteMemory moteMem; + private VarMemory moteMem; /** * Creates an interface to the vibration sensor at mote. @@ -79,7 +80,7 @@ public class ContikiVib extends MoteInterface implements ContikiMoteInterface { */ public ContikiVib(Mote mote) { this.mote = (ContikiMote) mote; - this.moteMem = (SectionMoteMemory) mote.getMemory(); + this.moteMem = new VarMemory(mote.getMemory()); } public static String[] getCoreInterfaceDependencies() { diff --git a/tools/cooja/java/org/contikios/cooja/dialogs/ConfigurationWizard.java b/tools/cooja/java/org/contikios/cooja/dialogs/ConfigurationWizard.java index 3010625e4..a677c07a9 100644 --- a/tools/cooja/java/org/contikios/cooja/dialogs/ConfigurationWizard.java +++ b/tools/cooja/java/org/contikios/cooja/dialogs/ConfigurationWizard.java @@ -66,8 +66,11 @@ import javax.swing.JScrollPane; import org.contikios.cooja.CoreComm; import org.contikios.cooja.Cooja; import org.contikios.cooja.MoteType.MoteTypeCreationException; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.contikimote.ContikiMoteType; +import org.contikios.cooja.contikimote.ContikiMoteType.SectionParser; +import org.contikios.cooja.mote.memory.MemoryInterface.Symbol; +import org.contikios.cooja.mote.memory.VarMemory; /* TODO Test common section */ /* TODO Test readonly section */ @@ -141,7 +144,7 @@ public class ConfigurationWizard extends JDialog { private static File cLibraryFile; private static String javaLibraryName; private static CoreComm javaLibrary; - private static HashMap addresses; + private static HashMap addresses; private static int relDataSectionAddr; private static int dataSectionSize; private static int relBssSectionAddr; @@ -757,18 +760,28 @@ public class ConfigurationWizard extends JDialog { } testOutput.addMessage("### Parsing map file data for addresses"); - addresses = new HashMap(); - boolean parseOK = ContikiMoteType.parseMapFileData(mapData, addresses); - if (!parseOK) { - testOutput.addMessage("### Error: Failed parsing map file data", MessageList.ERROR); - return false; - } + addresses = new HashMap(); +// boolean parseOK = ContikiMoteType.parseMapFileData(mapData, addresses); +// if (!parseOK) { +// testOutput.addMessage("### Error: Failed parsing map file data", MessageList.ERROR); +// return false; +// } testOutput.addMessage("### Validating section addresses"); - relDataSectionAddr = ContikiMoteType.parseMapDataSectionAddr(mapData); - dataSectionSize = ContikiMoteType.parseMapDataSectionSize(mapData); - relBssSectionAddr = ContikiMoteType.parseMapBssSectionAddr(mapData); - bssSectionSize = ContikiMoteType.parseMapBssSectionSize(mapData); + SectionParser dataSecParser = new ContikiMoteType.MapSectionParser( + mapData, + Cooja.getExternalToolsSetting("MAPFILE_DATA_START"), + Cooja.getExternalToolsSetting("MAPFILE_DATA_SIZE")); + SectionParser bssSecParser = new ContikiMoteType.MapSectionParser( + mapData, + Cooja.getExternalToolsSetting("MAPFILE_BSS_START"), + Cooja.getExternalToolsSetting("MAPFILE_BSS_SIZE")); + dataSecParser.parse(0); + bssSecParser.parse(0); + relDataSectionAddr = dataSecParser.getStartAddr(); + dataSectionSize = dataSecParser.getSize(); + relBssSectionAddr = bssSecParser.getStartAddr(); + bssSectionSize = bssSecParser.getSize(); testOutput.addMessage("Data section address: 0x" + Integer.toHexString(relDataSectionAddr)); testOutput.addMessage("Data section size: 0x" + Integer.toHexString(dataSectionSize)); testOutput.addMessage("BSS section address: 0x" + Integer.toHexString(relBssSectionAddr)); @@ -837,18 +850,31 @@ public class ConfigurationWizard extends JDialog { } testOutput.addMessage("### Parsing command output for addresses"); - addresses = new HashMap(); - boolean parseOK = ContikiMoteType.parseCommandData(commandData, addresses); - if (!parseOK) { - testOutput.addMessage("### Error: Failed parsing command output", MessageList.ERROR); - return false; - } + addresses = new HashMap(); +// boolean parseOK = ContikiMoteType.parseCommandData(commandData, addresses); +// if (!parseOK) { +// testOutput.addMessage("### Error: Failed parsing command output", MessageList.ERROR); +// return false; +// } testOutput.addMessage("### Validating section addresses"); - relDataSectionAddr = ContikiMoteType.parseCommandDataSectionAddr(commandData); - dataSectionSize = ContikiMoteType.parseCommandDataSectionSize(commandData); - relBssSectionAddr = ContikiMoteType.parseCommandBssSectionAddr(commandData); - bssSectionSize = ContikiMoteType.parseCommandBssSectionSize(commandData); + SectionParser dataSecParser = new ContikiMoteType.CommandSectionParser( + commandData, + Cooja.getExternalToolsSetting("COMMAND_DATA_START"), + Cooja.getExternalToolsSetting("COMMAND_DATA_SIZE"), + Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_DATA")); + SectionParser bssSecParser = new ContikiMoteType.CommandSectionParser( + commandData, + Cooja.getExternalToolsSetting("COMMAND_BSS_START"), + Cooja.getExternalToolsSetting("COMMAND_BSS_SIZE"), + Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_BSS")); + + dataSecParser.parse(0); + bssSecParser.parse(0); + relDataSectionAddr = dataSecParser.getStartAddr(); + dataSectionSize = dataSecParser.getSize(); + relBssSectionAddr = bssSecParser.getStartAddr(); + bssSectionSize = bssSecParser.getSize(); testOutput.addMessage("Data section address: 0x" + Integer.toHexString(relDataSectionAddr)); testOutput.addMessage("Data section size: 0x" + Integer.toHexString(dataSectionSize)); testOutput.addMessage("BSS section address: 0x" + Integer.toHexString(relBssSectionAddr)); @@ -935,7 +961,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"); @@ -943,15 +969,16 @@ public class ConfigurationWizard extends JDialog { byte[] initialBssSection = new byte[bssSectionSize]; javaLibrary.getMemory(relDataSectionAddr, dataSectionSize, initialDataSection); javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); - SectionMoteMemory memory = new SectionMoteMemory(addresses, 0); + SectionMoteMemory memory = new SectionMoteMemory(addresses); + VarMemory varMem = new VarMemory(memory); memory.setMemorySegment(relDataSectionAddr, initialDataSection); memory.setMemorySegment(relBssSectionAddr, initialBssSection); int contikiDataCounter, contikiBSSCounter; testOutput.addMessage("### Checking initial variable values: 1,0"); - contikiDataCounter = memory.getIntValueOf("var1"); - contikiBSSCounter = memory.getIntValueOf("uvar1"); + contikiDataCounter = varMem.getIntValueOf("var1"); + contikiBSSCounter = varMem.getIntValueOf("uvar1"); int javaDataCounter = 1; int javaBSSCounter = 0; if (contikiDataCounter != javaDataCounter) { @@ -975,8 +1002,8 @@ public class ConfigurationWizard extends JDialog { javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); memory.setMemorySegment(relDataSectionAddr, initialDataSection); memory.setMemorySegment(relBssSectionAddr, initialBssSection); - contikiDataCounter = memory.getIntValueOf("var1"); - contikiBSSCounter = memory.getIntValueOf("uvar1"); + contikiDataCounter = varMem.getIntValueOf("var1"); + contikiBSSCounter = varMem.getIntValueOf("uvar1"); if (contikiDataCounter != javaDataCounter) { testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); return false; @@ -1004,8 +1031,8 @@ public class ConfigurationWizard extends JDialog { javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); memory.setMemorySegment(relDataSectionAddr, initialDataSection); memory.setMemorySegment(relBssSectionAddr, initialBssSection); - contikiDataCounter = memory.getIntValueOf("var1"); - contikiBSSCounter = memory.getIntValueOf("uvar1"); + contikiDataCounter = varMem.getIntValueOf("var1"); + contikiBSSCounter = varMem.getIntValueOf("uvar1"); if (contikiDataCounter != javaDataCounter) { testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); return false; @@ -1029,8 +1056,8 @@ public class ConfigurationWizard extends JDialog { javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); memory.setMemorySegment(relDataSectionAddr, initialDataSection); memory.setMemorySegment(relBssSectionAddr, initialBssSection); - contikiDataCounter = memory.getIntValueOf("var1"); - contikiBSSCounter = memory.getIntValueOf("uvar1"); + contikiDataCounter = varMem.getIntValueOf("var1"); + contikiBSSCounter = varMem.getIntValueOf("uvar1"); if (contikiDataCounter != javaDataCounter) { testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); return false; @@ -1049,8 +1076,8 @@ public class ConfigurationWizard extends JDialog { javaLibrary.getMemory(relBssSectionAddr, bssSectionSize, initialBssSection); memory.setMemorySegment(relDataSectionAddr, initialDataSection); memory.setMemorySegment(relBssSectionAddr, initialBssSection); - contikiDataCounter = memory.getIntValueOf("var1"); - contikiBSSCounter = memory.getIntValueOf("uvar1"); + contikiDataCounter = varMem.getIntValueOf("var1"); + contikiBSSCounter = varMem.getIntValueOf("uvar1"); if (contikiDataCounter != javaDataCounter) { testOutput.addMessage("### Data section mismatch (" + contikiDataCounter + " != " + javaDataCounter + ")", MessageList.ERROR); return false; diff --git a/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java b/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java index 7216f8010..a0263d077 100644 --- a/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java +++ b/tools/cooja/java/org/contikios/cooja/interfaces/IPAddress.java @@ -42,9 +42,9 @@ import org.jdom.Element; import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; -import org.contikios.cooja.MoteMemory; -import org.contikios.cooja.MoteMemory.MemoryEventType; -import org.contikios.cooja.MoteMemory.MemoryMonitor; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.VarMemory; /** * Read-only interface to IPv4 or IPv6 address. @@ -54,21 +54,22 @@ import org.contikios.cooja.MoteMemory.MemoryMonitor; @ClassDescription("IP Address") public class IPAddress extends MoteInterface { private static Logger logger = Logger.getLogger(IPAddress.class); - private final MoteMemory moteMem; + private final VarMemory moteMem; private static final int IPv6_MAX_ADDRESSES = 4; private boolean ipv6IsGlobal = false; private int ipv6AddressIndex = -1; private static final int MONITORED_SIZE = 150; - private MemoryMonitor memMonitor; + private SegmentMonitor memMonitor; public IPAddress(final Mote mote) { - moteMem = mote.getMemory(); + moteMem = new VarMemory(mote.getMemory()); - memMonitor = new MemoryMonitor() { - public void memoryChanged(MoteMemory memory, MemoryEventType type, int address) { - if (type != MemoryEventType.WRITE) { + memMonitor = new MemoryInterface.SegmentMonitor() { + @Override + public void memoryChanged(MemoryInterface memory, SegmentMonitor.EventType type, long address) { + if (type != SegmentMonitor.EventType.WRITE) { return; } setChanged(); @@ -76,11 +77,11 @@ public class IPAddress extends MoteInterface { } }; if (isVersion4()) { - moteMem.addMemoryMonitor(moteMem.getVariableAddress("uip_hostaddr"), 4, memMonitor); + moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_hostaddr", memMonitor); } else if (isVersion6()) { - moteMem.addMemoryMonitor(moteMem.getVariableAddress("uip_ds6_netif_addr_list_offset"), 1, memMonitor); - moteMem.addMemoryMonitor(moteMem.getVariableAddress("uip_ds6_addr_size"), 1, memMonitor); - moteMem.addMemoryMonitor(moteMem.getVariableAddress("uip_ds6_if"), MONITORED_SIZE, memMonitor); + moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_ds6_netif_addr_list_offset", memMonitor); + moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_ds6_addr_size", memMonitor); + moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "uip_ds6_if", memMonitor); } } @@ -205,11 +206,11 @@ public class IPAddress extends MoteInterface { super.removed(); if (memMonitor != null) { if (isVersion4()) { - moteMem.removeMemoryMonitor(moteMem.getVariableAddress("rimeaddr_node_addr"), 4, memMonitor); + moteMem.removeVarMonitor("rimeaddr_node_addr", memMonitor); } else if (isVersion6()) { - moteMem.removeMemoryMonitor(moteMem.getVariableAddress("uip_ds6_netif_addr_list_offset"), 1, memMonitor); - moteMem.removeMemoryMonitor(moteMem.getVariableAddress("uip_ds6_addr_size"), 1, memMonitor); - moteMem.removeMemoryMonitor(moteMem.getVariableAddress("uip_ds6_if"), MONITORED_SIZE, memMonitor); + moteMem.removeVarMonitor("uip_ds6_netif_addr_list_offset", memMonitor); + moteMem.removeVarMonitor("uip_ds6_addr_size", memMonitor); + moteMem.removeVarMonitor("uip_ds6_if", memMonitor); } } } diff --git a/tools/cooja/java/org/contikios/cooja/interfaces/RimeAddress.java b/tools/cooja/java/org/contikios/cooja/interfaces/RimeAddress.java index 405aca506..09031b44d 100644 --- a/tools/cooja/java/org/contikios/cooja/interfaces/RimeAddress.java +++ b/tools/cooja/java/org/contikios/cooja/interfaces/RimeAddress.java @@ -43,9 +43,9 @@ import org.jdom.Element; import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; -import org.contikios.cooja.MoteMemory; -import org.contikios.cooja.MoteMemory.MemoryEventType; -import org.contikios.cooja.MoteMemory.MemoryMonitor; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.VarMemory; /** * Read-only interface to Rime address read from Contiki variable: linkaddr_node_addr. @@ -57,18 +57,19 @@ import org.contikios.cooja.MoteMemory.MemoryMonitor; @ClassDescription("Rime address") public class RimeAddress extends MoteInterface { private static Logger logger = Logger.getLogger(RimeAddress.class); - private MoteMemory moteMem; + private VarMemory moteMem; public static final int RIME_ADDR_LENGTH = 2; - private MemoryMonitor memMonitor = null; + private SegmentMonitor memMonitor = null; public RimeAddress(final Mote mote) { - moteMem = mote.getMemory(); + moteMem = new VarMemory(mote.getMemory()); if (hasRimeAddress()) { - memMonitor = new MemoryMonitor() { - public void memoryChanged(MoteMemory memory, MemoryEventType type, int address) { - if (type != MemoryEventType.WRITE) { + memMonitor = new SegmentMonitor() { + @Override + public void memoryChanged(MemoryInterface memory, SegmentMonitor.EventType type, long address) { + if (type != SegmentMonitor.EventType.WRITE) { return; } setChanged(); @@ -76,7 +77,7 @@ public class RimeAddress extends MoteInterface { } }; /* TODO XXX Timeout? */ - moteMem.addMemoryMonitor(moteMem.getVariableAddress("linkaddr_node_addr"), RIME_ADDR_LENGTH, memMonitor); + moteMem.addVarMonitor(SegmentMonitor.EventType.WRITE, "linkaddr_node_addr", memMonitor); } } @@ -131,7 +132,7 @@ public class RimeAddress extends MoteInterface { public void removed() { super.removed(); if (memMonitor != null) { - moteMem.removeMemoryMonitor(moteMem.getVariableAddress("linkaddr_node_addr"), RIME_ADDR_LENGTH, memMonitor); + moteMem.removeVarMonitor("linkaddr_node_addr", memMonitor); } } diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/ArrayMemory.java b/tools/cooja/java/org/contikios/cooja/mote/memory/ArrayMemory.java new file mode 100644 index 000000000..95966e01b --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/ArrayMemory.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013, Enrico Joerns + * 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. + */ + +package org.contikios.cooja.mote.memory; + +import java.util.Arrays; +import java.util.Map; + +/** + * A memory that is backed by an array. + * + * @author Enrico Joerns + */ +public class ArrayMemory implements MemoryInterface { + + private final byte memory[]; + private final long startAddress; + private final MemoryLayout layout; + private final boolean readonly; + private final Map symbols;// XXX Allow to set symbols + + public ArrayMemory(long address, int size, MemoryLayout layout, Map symbols) { + this(address, layout, new byte[size], symbols); + } + + public ArrayMemory(long address, MemoryLayout layout, byte[] memory, Map symbols) { + this(address, layout, memory, false, symbols); + } + + public ArrayMemory(long address, MemoryLayout layout, byte[] memory, boolean readonly, Map symbols) { + this.startAddress = address; + this.layout = layout; + this.memory = memory; + this.readonly = readonly; + this.symbols = symbols; + } + + @Override + public byte[] getMemory() { + return memory; + } + + /** + * XXX Should addr be the relative or the absolute address of this section? + * @param addr + * @param size + * @return + * @throws org.contikios.cooja.mote.memory.MemoryInterface.MoteMemoryException + */ + @Override + public byte[] getMemorySegment(long addr, int size) throws MoteMemoryException { + byte[] ret = new byte[size]; + System.arraycopy(memory, (int) (addr - startAddress), ret, 0, size); + return ret; + } + + @Override + public void setMemorySegment(long addr, byte[] data) throws MoteMemoryException { + if (readonly) { + throw new MoteMemoryException("Invalid write access for readonly memory"); + } + System.arraycopy(data, 0, memory, (int) (addr - startAddress), data.length); + } + + @Override + public void clearMemory() { + Arrays.fill(memory, (byte) 0x00); + } + + @Override + public long getStartAddr() { + return startAddress; + } + + @Override + public int getTotalSize() { + return memory.length; + } + + @Override + public Map getSymbolMap() { + return symbols; + } + + @Override + public MemoryLayout getLayout() { + return layout; + } + + @Override + public boolean addSegmentMonitor(SegmentMonitor.EventType flag, long address, int size, SegmentMonitor monitor) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean removeSegmentMonitor(long address, int size, SegmentMonitor monitor) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java b/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java new file mode 100644 index 000000000..4f405a07c --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/Memory.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2014, TU Braunschweig. + * 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. + * + */ +package org.contikios.cooja.mote.memory; + +import org.contikios.cooja.mote.memory.MemoryLayout.DataType; + +/** + * Represents memory that can be accessed with address and size informations. + * + * @author Enrico Jorns + */ +public abstract class Memory { + + private final MemoryInterface memIntf; + + /** + * Creates new memory for given MemoryLayout. + * + * @param intf + */ + public Memory(MemoryInterface intf) { + memIntf = intf; + } + + // -- Get fixed size types + /** + * Read 8 bit integer from address. + * + * @param addr Address to read from + * @return 8 bit value read from address + */ + public byte getInt8ValueOf(long addr) { + return memIntf.getMemorySegment(addr, DataType.INT8.getSize())[0]; + } + + /** + * Read 16 bit integer from address. + * + * @param addr Address to read from + * @return 16 bit value read from address + */ + public short getInt16ValueOf(long addr) { + return MemoryBuffer.wrap( + memIntf.getLayout(), + memIntf.getMemorySegment(addr, DataType.INT16.getSize())).getInt16(); + } + + /** + * Read 32 bit integer from address. + * + * @param addr Address to read from + * @return 32 bit value read from address + */ + public int getInt32ValueOf(long addr) { + return MemoryBuffer.wrap( + memIntf.getLayout(), + memIntf.getMemorySegment(addr, DataType.INT32.getSize())).getInt32(); + } + + /** + * Read 64 bit integer from address. + * + * @param addr Address to read from + * @return 64 bit value read from address + */ + public long getInt64ValueOf(long addr) { + return MemoryBuffer.wrap( + memIntf.getLayout(), + memIntf.getMemorySegment(addr, DataType.INT64.getSize())).getInt64(); + } + + // -- Get compiler-dependent types + /** + * Read byte from address. + * + * @param addr Address to read from + * @return byte read from address + */ + public byte getByteValueOf(long addr) { + return memIntf.getMemorySegment(addr, DataType.BYTE.getSize())[0]; + } + + /** + * Read short from address. + * + * @param addr Address to read from + * @return short read from address + */ + public short getShortValueOf(long addr) { + return MemoryBuffer.wrap(memIntf.getLayout(), memIntf.getMemorySegment(addr, 2)).getShort(); + } + + /** + * Read integer from address. + *

+ * Note: Size of integer depends on platform type. + * + * @param addr Address to read from + * @return integer read from address + */ + public int getIntValueOf(long addr) { + return MemoryBuffer.wrap(memIntf.getLayout(), memIntf.getMemorySegment(addr, memIntf.getLayout().intSize)).getInt(); + } + + /** + * Read long from address. + * + * @param addr Address to read from + * @return long read from address + */ + public long getLongValueOf(long addr) { + return MemoryBuffer.wrap(memIntf.getLayout(), memIntf.getMemorySegment(addr, 4)).getLong(); + } + + /** + * Read pointer from address. + *

+ * Note: Size of pointer depends on platform type. + * + * @param addr Address to read from + * @return pointer read from address + */ + public long getAddrValueOf(long addr) { + return MemoryBuffer.wrap(memIntf.getLayout(), memIntf.getMemorySegment(addr, memIntf.getLayout().addrSize)).getAddr(); + } + + // -- Set fixed size types + /** + * Write 8 bit integer to address. + * + * @param addr Address to write to + * @param value 8 bit value to write + */ + public void setInt8ValueOf(long addr, byte value) { + memIntf.setMemorySegment(addr, new byte[]{value}); + } + + /** + * Write 16 bit integer to address. + * + * @param addr Address to write to + * @param value 16 bit value to write + */ + public void setInt16ValueOf(long addr, short value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap( + memIntf.getLayout(), + new byte[DataType.INT16.getSize()]).putShort(value).getBytes()); + } + + /** + * Write 32 bit integer to address. + * + * @param addr Address to write to + * @param value 32 bit value to write + */ + public void setInt32ValueOf(long addr, int value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap( + memIntf.getLayout(), + new byte[DataType.INT32.getSize()]).putInt(value).getBytes()); + } + + /** + * Write 64 bit integer to address. + * + * @param addr Address to write to + * @param value 64 bit value to write + */ + public void setInt64ValueOf(long addr, long value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap( + memIntf.getLayout(), + new byte[DataType.INT64.getSize()]).putLong(value).getBytes()); + } + + // -- Set compiler-dependent types + /** + * Write byte to address. + * + * @param addr Address to write to + * @param value byte to write + */ + public void setByteValueOf(long addr, byte value) { + memIntf.setMemorySegment(addr, new byte[]{value}); + } + + /** + * Write short to address. + * + * @param addr Address to write to + * @param value short to write + */ + public void setShortValueOf(long addr, short value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap(memIntf.getLayout(), new byte[2]).putShort(value).getBytes()); + } + + /** + * Write integer to address. + *

+ * Note: Size of integer depends on platform type. + * + * @param addr Address to write to + * @param value integer to write + */ + public void setIntValueOf(long addr, int value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap(memIntf.getLayout(), new byte[memIntf.getLayout().intSize]).putInt(value).getBytes()); + } + + /** + * Write long to address. + * + * @param addr Address to write to + * @param value long to write + */ + public void setLongValueOf(long addr, long value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap(memIntf.getLayout(), new byte[4]).putLong(value).getBytes()); + } + + /** + * Write pointer to address. + *

+ * Note: Size of pointer depends on platform type. + * + * @param addr Address to write to + * @param value pointer to write + */ + public void setAddrValueOf(long addr, long value) { + memIntf.setMemorySegment(addr, MemoryBuffer.wrap(memIntf.getLayout(), new byte[memIntf.getLayout().addrSize]).putAddr(value).getBytes()); + } + +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryBuffer.java b/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryBuffer.java new file mode 100644 index 000000000..4f645a2e0 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryBuffer.java @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2014, TU Braunschweig + * 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. + */ +package org.contikios.cooja.mote.memory; + +import java.nio.ByteBuffer; +import org.contikios.cooja.mote.memory.MemoryLayout.DataType; + +/** + * Basic routines for memory access with multi-arch support. + * + * Handles endianess, integer size and address size. + * + * Supports padding/aligning. + * + * @author Enrico Jorns + */ +public class MemoryBuffer { + + private final MemoryLayout memLayout; + private final ByteBuffer bbuf; + private final DataType[] structure; + private int structIndex; + + private MemoryBuffer(MemoryLayout memLayout, ByteBuffer buffer, DataType[] structure) { + this.memLayout = memLayout; + this.bbuf = buffer; + this.structure = structure; + this.structIndex = 0; + } + + /** + * Wraps a byte array into an unstructered MemoryBuffer with given MemoryLayout. + *

+ * Note that modifications to the buffer are applied to the backed array and vice versa. + * + * @param layout MemoryLayout for memory to access array from + * @param array Byte array that will back this buffer + * @return the new MemroyBuffer + */ + public static MemoryBuffer wrap(MemoryLayout layout, byte[] array) { + return wrap(layout, array, null); + } + + /** + * Wraps a byte array into a structured MemoryBuffer with given MemoryLayout. + *

+ * Note that modifications to the buffer are applied to the backed array and vice versa. + *

+ * A structured MemoryBuffer can be used to simplify reading c struct data + * from the memory as it provides support for data aligning. + *

+ * The structure array elements should be set to exactly the same types and order + * that the corresponding c struct has. + * + * @param layout MemoryLayout for memory to access array from + * @param structure Array of data types representing the structure to read + * @param array Byte array that will back this buffer + * @return the new MemroyBuffer + */ + public static MemoryBuffer wrap(MemoryLayout layout, byte[] array, DataType[] structure) { + ByteBuffer b = ByteBuffer.wrap(array); + b.order(layout.order); // preset endianess + return new MemoryBuffer(layout, b, structure); + } + + /** + * Returns the byte array that backs this buffer + * + * @return byte array that backs this buffer + */ + public byte[] getBytes() { + if (bbuf.hasArray()) { + return bbuf.array(); + } + else { + return null; + } + } + + /** + * Calculates the padding bytes to be added/skipped between current and next + * element. + * + * @param type Current data type + */ + private void skipPaddingBytesFor(DataType type) { + /* Check if we have a structure and not yet reached the last element */ + if (structure != null && structure[structIndex + 1] != null) { + /* get size of next element in structure */ + int nextsize = structure[structIndex + 1].getSize(); + /* limit padding to word size */ + nextsize = nextsize > memLayout.WORD_SIZE ? memLayout.WORD_SIZE : nextsize; + /* calc padding */ + int pad = nextsize - type.getSize(); + /* Skip padding bytes */ + if (pad > 0) { + bbuf.position(bbuf.position() + pad); + } + } + structIndex++; + } + + /** + * Returns current element type. + * + * @return current element type or null if no struct is used + */ + public DataType getType() { + if (structure == null) { + return null; + } + return structure[structIndex]; + } + + // --- fixed size types + + /** + * Reads 8 bit integer from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return 8 bit integer at the buffer's current position + */ + public byte getInt8() { + byte value = bbuf.get(); + skipPaddingBytesFor(DataType.INT8); + return value; + } + + /** + * Reads 16 bit integer from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return 16 bit integer at the buffer's current position + */ + public short getInt16() { + short value = bbuf.getShort(); + skipPaddingBytesFor(DataType.INT16); + return value; + } + + /** + * Reads 32 bit integer from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return 32 bit integer at the buffer's current position + */ + public int getInt32() { + int value = bbuf.getInt(); + skipPaddingBytesFor(DataType.INT32); + return value; + } + + /** + * Reads 64 bit integer from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return 64 bit integer at the buffer's current position + */ + public long getInt64() { + long value = bbuf.getLong(); + skipPaddingBytesFor(DataType.INT64); + return value; + } + + // --- platform-dependent types + + /** + * Reads byte from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return byte at the buffer's current position + */ + public byte getByte() { + byte value = bbuf.get(); + skipPaddingBytesFor(DataType.BYTE); + return value; + } + + /** + * Reads short from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return short at the buffer's current position + */ + public short getShort() { + short value = bbuf.getShort(); + skipPaddingBytesFor(DataType.SHORT); + return value; + } + + /** + * Reads integer from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return integer at the buffer's current position + */ + public int getInt() { + int value; + switch (memLayout.intSize) { + case 2: + value = bbuf.getShort(); + break; + case 4: + default: + value = bbuf.getInt(); + break; + } + skipPaddingBytesFor(DataType.INT); + return value; + } + + /** + * Reads long from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return long at the buffer's current position + */ + public long getLong() { + long value = bbuf.getLong(); + skipPaddingBytesFor(DataType.LONG); + return value; + } + + /** + * Reads pointer from current buffer position, + * and then increments position. + *

+ * Note: If structured reading is enabled, + * additional padding bytes may be skipped automatically. + * + * @return pointer at the buffer's current position + */ + public long getAddr() { + long value; + switch (memLayout.addrSize) { + case 2: + value = bbuf.getShort(); + break; + case 4: + value = bbuf.getInt(); + break; + case 8: + value = bbuf.getLong(); + break; + default: + value = bbuf.getInt(); + break; + } + skipPaddingBytesFor(DataType.POINTER); + return value; + } + + // --- fixed size types + + /** + * Writes 8 bit integer to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value 8 bit integer to write + * @return A reference to this object + */ + public MemoryBuffer putInt8(byte value) { + bbuf.put(value); + skipPaddingBytesFor(DataType.INT8); + return this; + } + + /** + * Writes 16 bit integer to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value 16 bit integer to write + * @return A reference to this object + */ + public MemoryBuffer putInt16(short value) { + bbuf.putShort(value); + skipPaddingBytesFor(DataType.INT16); + return this; + } + + /** + * Writes 32 bit integer to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value 32 bit integer to write + * @return A reference to this object + */ + public MemoryBuffer putInt32(int value) { + bbuf.putInt(value); + skipPaddingBytesFor(DataType.INT32); + return this; + } + + /** + * Writes 64 bit integer to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value 64 bit integer to write + * @return A reference to this object + */ + public MemoryBuffer putInt64(long value) { + bbuf.putLong(value); + skipPaddingBytesFor(DataType.INT64); + return this; + } + + // --- platform-dependent types + + /** + * Writes byte to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value byte to write + * @return A reference to this object + */ + public MemoryBuffer putByte(byte value) { + bbuf.put(value); + skipPaddingBytesFor(DataType.BYTE); + return this; + } + + /** + * Writes short to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value short to write + * @return A reference to this object + */ + public MemoryBuffer putShort(short value) { + bbuf.putShort(value); + skipPaddingBytesFor(DataType.SHORT); + return this; + } + + /** + * Writes integer to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + *

+ * Note: Size of integer depends on platform type + * + * @param value integer to write + * @return A reference to this object + */ + public MemoryBuffer putInt(int value) { + switch (memLayout.intSize) { + case 2: + /** + * @TODO: check for size? + */ + bbuf.putShort((short) value); + break; + case 4: + default: + bbuf.putInt(value); + break; + } + skipPaddingBytesFor(DataType.INT); + return this; + } + + /** + * Writes long to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + * + * @param value long to write + * @return A reference to this object + */ + public MemoryBuffer putLong(long value) { + bbuf.putLong(value); + skipPaddingBytesFor(DataType.LONG); + return this; + } + + /** + * Writes pointer to current buffer position, + * and then increments position. + *

+ * Note: If structured writing is enabled, + * additional padding bytes may be skipped automatically. + *

+ * Note: Size of pointer depends on platform type + * + * @param value pointer to write + * @return A reference to this object + */ + public MemoryBuffer putAddr(long value) { + /** + * @TODO: check for size? + */ + switch (memLayout.addrSize) { + case 2: + bbuf.putShort((short) value); + break; + case 4: + bbuf.putInt((int) value); + break; + case 8: + bbuf.putLong(value); + break; + default: + bbuf.putInt((int) value); + break; + } + skipPaddingBytesFor(DataType.POINTER); + return this; + } +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryInterface.java b/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryInterface.java new file mode 100644 index 000000000..3f7df09ff --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryInterface.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2014, TU Braunschweig + * 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. + */ +package org.contikios.cooja.mote.memory; + +import java.util.Map; + +/** + * A minimal interface to a motes memory. + * + * Allows reading and writing memory, obtaining symbol information + * and provides some basic inforation about size, layout, etc. + * + * @author Enrico Jorns + */ +public interface MemoryInterface { + + /** + * Represents a symbol in memory (variable / function) + */ + public static class Symbol { + + public final Type type; + public final String name; + public final String section; + public final long addr; + public final int size; + + public enum Type { + + VARIABLE, + FUNCTION + } + + public Symbol(Type type, String name, String section, long addr, int size) { + this.type = type; + this.name = name; + this.section = section; + this.addr = addr; + this.size = size; + } + + public Symbol(Type type, String name, long addr, int size) { + this(type, name, null, addr, size); + } + + @Override + public String toString() { + return new StringBuilder("Symbol(").append(type == null ? "N/A" : type.toString()) + .append(") '").append(name) + .append("' in '").append(section == null ? "N/A" : section) + .append("' at 0x").append(addr == -1 ? "N/A" : Long.toHexString(addr)) + .append(" size ").append(size == -1 ? "N/A" : String.valueOf(size)).toString(); + } + } + + /** + * Class represents memory access exceptions. + */ + public class MoteMemoryException extends RuntimeException { + + public MoteMemoryException(String message, Object... args) { + super(String.format(message, args)); + } + } + + /** + * Returns entire mote memory + * @return Memory byte array + * @throws org.contikios.cooja.mote.memory.MemoryInterface.MoteMemoryException + */ + public byte[] getMemory() throws MoteMemoryException; + + /** + * Reads a segment from memory. + * + * @param addr Start address to read from + * @param size Size to read [bytes] + * @return Byte array + */ + public byte[] getMemorySegment(long addr, int size) throws MoteMemoryException; + + /** + * Sets a segment of memory. + * + * @param addr Start address to write to + * @param data Size to write [bytes] + */ + void setMemorySegment(long addr, byte[] data) throws MoteMemoryException; + + /** + * Clears the memory. + */ + void clearMemory(); + + /** + * + * @return + */ + long getStartAddr(); + + /** + * Returns total size of memory. + * + * @return Size [bytes] + */ + int getTotalSize();// XXX getSize(); + + /** + * Returns Map of all variables in memory. + * Map must be of typ name / symbol. + * + * @return Variables + */ + Map getSymbolMap(); + + /** + * Returns the MemoryLayout for this memory. + * + * @return Memory layout for this memory + */ + MemoryLayout getLayout(); + + /** + * Monitor to listen for memory updates. + */ + interface SegmentMonitor { + + public static enum EventType { + + READ, + WRITE, + READWRITE + } + + /** + * Invoked if the monitored segment changed + * + * @param memory Reference to the memory + * @param type XXX ??? + * @param address Address in segment where modification occured + */ + void memoryChanged(MemoryInterface memory, EventType type, long address); + } + + /** + * Adds a SegmentMonitor for the specified address region. + * + * @param flag Select memory operation(s) to listen for + * (read, write, read/write) + * @param address Start address of monitored data region + * @param size Size of monitored data region + * @param monitor SegmentMonitor to add + * @return true if monitor could be added, false if not + */ + boolean addSegmentMonitor(SegmentMonitor.EventType flag, long address, int size, SegmentMonitor monitor); + + /** + * Removes SegmentMonitor assigned to the specified region. + * + * @param address Start address of Monitor data region + * @param size Size of Monitor data region + * @param monitor SegmentMonitor to remove + * @return true if monitor was removed, false if not + */ + boolean removeSegmentMonitor(long address, int size, SegmentMonitor monitor); +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryLayout.java b/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryLayout.java new file mode 100644 index 000000000..aa3f7a743 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/MemoryLayout.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, TU Braunschweig + * 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. + */ + +package org.contikios.cooja.mote.memory; + +import java.nio.ByteOrder; + +/** + * Holds memory layout informations such as endianess, wordsize, C int size. + * + * @author Enrico Jorns + */ +public class MemoryLayout { + + /** 8 bit memory architecture */ + public static final int ARCH_8BIT = 1; + /** 16 bit memory architecture */ + public static final int ARCH_16BIT = 2; + /** 32 bit memory architecture */ + public static final int ARCH_32BIT = 4; + /** 64 bit memory architecture */ + public static final int ARCH_64BIT = 8; + + /** + * Size of data types in bytes. + */ + public enum DataType { + + BYTE(1), + CHAR(1), + SHORT(2), + INT(4), + LONG(8), + LONGLONG(8), + INT8(1), + INT16(2), + INT32(4), + INT64(8), + FLOAT(4), + DOUBLE(8), + POINTER(4); + + private int size; + + DataType(int size) { + this.size = size; + } + + public void setSize(int size) { + this.size = size; + } + + public int getSize() { + return this.size; + } + } + + public final ByteOrder order; + public final int addrSize; + public final int intSize; + public final int WORD_SIZE; + private boolean aligned = true; + + /** + * Creates new MemoryLayout instance. + * + * @param order either ByteOrder.BIG_ENDIAN, or ByteOrder.LITTLE_ENDIAN + * @param wordsize should be one of ARCH_8BIT, ARCH_16BIT, ARCH_32BIT, + * ARCH_64BIT + * @param sizeofInt + */ + public MemoryLayout(ByteOrder order, int wordsize, int sizeofInt) { + this(order, wordsize, sizeofInt, wordsize); + } + + /** + * Creates new MemoryLayout instance. + * + * @param order either ByteOrder.BIG_ENDIAN, or ByteOrder.LITTLE_ENDIAN + * @param wordsize should be one of ARCH_8BIT, ARCH_16BIT, ARCH_32BIT, + * ARCH_64BIT + * @param sizeofPointer + * @param sizeofInt + */ + public MemoryLayout(ByteOrder order, int wordsize, int sizeofInt, int sizeofPointer) { + this.order = order; + this.WORD_SIZE = wordsize; + this.intSize = sizeofInt; + this.addrSize = sizeofPointer; + DataType.INT.setSize(this.intSize); + DataType.POINTER.setSize(this.addrSize); + } + + /** + * Returns the MemoryLayout for the running jvm. + * + * @return MemoryLayout for the running jvm. + */ + public static MemoryLayout getNative() { + return new MemoryLayout( + ByteOrder.nativeOrder(), + Integer.parseInt(System.getProperty("sun.arch.data.model")) / 8, + Integer.SIZE / 8); + } + + /** + * Enable/Disable data alignment. + * + * Determines whether data alignemnt is used for packing structs. + * Default is enabled. + * + * @param aligned true to enable data alignment, false to disable + */ + public void setAligned(boolean aligned) { + this.aligned = aligned; + } + + /** + * Returns true if data is aligned. + * + * @return if aligned + */ + public boolean isAligned() { + return aligned; + } + + /** + * Returns number of padding bytes between two data types. + * + * @param currType + * @param nextType + * @return + */ + public int getPaddingBytesFor(DataType currType, DataType nextType) { + /* No padding bytes for unaligned memory */ + if (!isAligned()) { + return 0; + } + /* get size of next element in structure */ + int nextsize = nextType.getSize(); + /* limit padding to word size */ + nextsize = nextsize > WORD_SIZE ? WORD_SIZE : nextsize; + System.out.println("Nextsize: " + nextsize); + /* calc padding */ + int pad = nextsize - currType.getSize(); + return pad; + } + + /** + * Returns information string for this MemoryLayout. + * + * @return String that shows Endianess and word size. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + return sb.append("MemoryLayout: ") + .append("Endianess: ").append(order) + .append(", WORD_SIZE: ").append(WORD_SIZE) + .toString(); + } +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/SectionMoteMemory.java b/tools/cooja/java/org/contikios/cooja/mote/memory/SectionMoteMemory.java new file mode 100644 index 000000000..0a335b15e --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/SectionMoteMemory.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2014, TU Braunschweig. All rights reserved. + * 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. + */ + +package org.contikios.cooja.mote.memory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +/** + * Represents a mote memory consisting of non-overlapping memory sections with + * symbol addresses. + *

+ * Every section must implement MemoyInterface. + *

+ * 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 Map sections = new HashMap<>(); + + private final Map symbols; + private MemoryLayout memLayout; + private long startAddr = Long.MAX_VALUE; + + /** + * @param symbols Symbol addresses + */ + public SectionMoteMemory(Map symbols) { + this.symbols = symbols; + } + + /** + * 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) { + + if (section == null) { + return false; + } + + /* 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; + } + + /** + * Returns the total number of sections in this memory. + * + * @return Number of sections + */ + public int getNumberOfSections() { + return sections.size(); + } + + /** + * Returns memory section of this memory. + * @param name Name of section + * @return memory section + */ + public MemoryInterface getSection(String name) { + for (String memsec : sections.keySet()) { + if (memsec.equals(name)) { + return sections.get(name); + } + } + + logger.warn("Section '" + name + "' not found"); + return null; + } + + /** + * Return all sections of this memory. + * @return All memory sections + */ + public Map getSections() { + return sections; + } + + /** + * True if given address is part of this memory section. + * + * @param intf + * @param addr + * Address + * @return True if given address is part of this memory section, false + * otherwise + */ + public static boolean includesAddr(MemoryInterface intf, long addr) { + return addr >= intf.getStartAddr() && addr < (intf.getStartAddr() + intf.getTotalSize()); + } + + /** + * 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 + public byte[] getMemory() throws MoteMemoryException { + 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 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 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); + } + + @Override + public long getStartAddr() { + return startAddr; + } + + @Override + public Map getSymbolMap() { + return symbols; + } + + @Override + public MemoryLayout getLayout() { + return memLayout; + } + + @Override + public boolean addSegmentMonitor(SegmentMonitor.EventType flag, long address, int size, SegmentMonitor monitor) { + PolledMemorySegments t = new PolledMemorySegments(monitor, address, size); + polledMemories.add(t); + return true; + } + + @Override + public boolean removeSegmentMonitor(long address, int size, SegmentMonitor monitor) { + for (PolledMemorySegments mcm: polledMemories) { + if (mcm.mm != monitor || mcm.address != address || mcm.size != size) { + continue; + } + polledMemories.remove(mcm); + return true; + } + return false; + } + + /** Copies seciton memory to new (array backed) one + * @return Cloned memory + */ + @Override + public SectionMoteMemory clone() { + + SectionMoteMemory clone = new SectionMoteMemory(symbols); + + 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; + } + + private ArrayList polledMemories = new ArrayList(); + public void pollForMemoryChanges() { + for (PolledMemorySegments mem: polledMemories.toArray(new PolledMemorySegments[0])) { + mem.notifyIfChanged(); + } + } + + private class PolledMemorySegments { + public final SegmentMonitor mm; + public final long address; + public final int size; + private byte[] oldMem; + + public PolledMemorySegments(SegmentMonitor mm, long 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, SegmentMonitor.EventType.WRITE, address); + oldMem = newMem; + } + } + +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/UnknownVariableException.java b/tools/cooja/java/org/contikios/cooja/mote/memory/UnknownVariableException.java new file mode 100644 index 000000000..6f32f3698 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/UnknownVariableException.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, Enrico Joerns + * 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. + */ + +package org.contikios.cooja.mote.memory; + +/** + * Unknown variable name exception. + */ +public class UnknownVariableException extends RuntimeException { + + public UnknownVariableException(String varName) { + super("Unknown variable name: " + varName); + } + +} diff --git a/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java b/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java new file mode 100644 index 000000000..2559fe2f1 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/mote/memory/VarMemory.java @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2014, TU Braunschweig. + * 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. + * + */ +package org.contikios.cooja.mote.memory; + +import java.util.Collection; +import java.util.Set; + +import org.contikios.cooja.mote.memory.MemoryInterface.Symbol; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor.EventType; + +/** + * Represents memory that can be accessed with names of variables. + * + * @author Enrico Jorns + */ +public class VarMemory extends Memory { + + private MemoryInterface memIntf; + + /** + * Creates new VarMemory. + * + * @param intf + */ + public VarMemory(MemoryInterface intf) { + super(intf); + memIntf = intf; + } + + /** + * Allows to change the MemoryInterface associated with this access class. + * + * @param intf Interface to associate with + */ + public void associateMemory(MemoryInterface intf) { + memIntf = intf; + } + + /** + * Generates and returns an array of all variables in this memory + * + * @return All variables located in this memory + */ + public Collection getVariables() { + return memIntf.getSymbolMap().values(); + } + + /** + * Generates an array of all variable names in this memory. + * + * @return All variable names located in this memory + */ + public Set getVariableNames() { + return memIntf.getSymbolMap().keySet(); + } + + /** + * Checks if given variable exists in memory. + * + * @param varName Variable name + * @return True if variable exists, false otherwise + */ + public boolean variableExists(String varName) { + return memIntf.getSymbolMap().containsKey(varName); + } + + /** + * Returns address of variable with given name. + * + * @param varName Variable name + * @return Variable address + */ + public Symbol getVariable(String varName) throws UnknownVariableException { + Symbol sym = memIntf.getSymbolMap().get(varName); + if (sym == null) { + throw new UnknownVariableException(varName); + } + return sym; + } + + /** + * Returns address of variable with given name. + * + * @param varName Variable name + * @return Address of variable + * @throws UnknownVariableException If variable not found + */ + public long getVariableAddress(String varName) throws UnknownVariableException { + return getVariable(varName).addr; + } + + /** + * Return size of variable with given name. + * + * @param varName Variable name + * @return Size of variable, -1 if unknown size + * @throws UnknownVariableException If variable not found + */ + public int getVariableSize(String varName) throws UnknownVariableException { + return getVariable(varName).size; + } + + /** + * Read 8 bit integer from location associated with this variable name. + * + * @param varName Variable name + * @return 8 bit integer value read from location assigned to variable name + */ + public byte getInt8ValueOf(String varName) + throws UnknownVariableException { + return getInt8ValueOf(getVariable(varName).addr); + } + + /** + * Read 16 bit integer from location associated with this variable name. + * + * @param varName Variable name + * @return 16 bit integer value read from location assigned to variable name + */ + public short getInt16ValueOf(String varName) + throws UnknownVariableException { + return getInt16ValueOf(getVariable(varName).addr); + } + + /** + * Read 32 bit integer from location associated with this variable name. + * + * @param varName Variable name + * @return 32 bit integer value read from location assigned to variable name + */ + public int getInt32ValueOf(String varName) + throws UnknownVariableException { + return getInt32ValueOf(getVariable(varName).addr); + } + + /** + * Read 64 bit integer from location associated with this variable name. + * + * @param varName Variable name + * @return 64 bit integer value read from location assigned to variable name + */ + public long getInt64ValueOf(String varName) + throws UnknownVariableException { + return getInt64ValueOf(getVariable(varName).addr); + } + + /** + * Read byte from location associated with this variable name. + * + * @param varName Variable name + * @return byte value read from location assigned to variable name + */ + public byte getByteValueOf(String varName) + throws UnknownVariableException { + return getByteValueOf(getVariable(varName).addr); + } + + /** + * Read short from location associated with this variable name. + * + * @param varName Variable name + * @return short value read from location assigned to variable name + */ + public short getShortValueOf(String varName) + throws UnknownVariableException { + short val = getShortValueOf(getVariable(varName).addr); + return val; + } + + /** + * Read integer from location associated with this variable name. + * + * @param varName Variable name + * @return integer value read from location assigned to variable name + */ + public int getIntValueOf(String varName) + throws UnknownVariableException { + int val = getIntValueOf(getVariable(varName).addr); + return val; + } + + /** + * Read long from location associated with this variable name. + * + * @param varName Variable name + * @return long value read from location assigned to variable name + */ + public long getLongValueOf(String varName) + throws UnknownVariableException { + long val = getLongValueOf(getVariable(varName).addr); + return val; + } + + /** + * Read pointer from location associated with this variable name. + * + * The number of bytes actually read depends on the pointer size + * defined in memory layout. + * + * @param varName Variable name + * @return pointer value read from location assigned to variable name + */ + public long getAddrValueOf(String varName) + throws UnknownVariableException { + long val = getAddrValueOf(getVariable(varName).addr); + return val; + } + + /** + * Read byte array starting at location associated with this variable name. + * + * @param varName Variable name + * @param length Numbe of bytes to read + * @return byte array read from location assigned to variable name + */ + public byte[] getByteArray(String varName, int length) + throws UnknownVariableException { + return memIntf.getMemorySegment(getVariable(varName).addr, length); + } + + /** + * Write 8 bit integer value to location associated with this variable name. + * + * @param varName Variable name + * @param value 8 bit integer value to write + */ + public void setInt8ValueOf(String varName, byte value) + throws UnknownVariableException { + setInt8ValueOf(getVariable(varName).addr, value); + } + + /** + * Write 16 bit integer value to location associated with this variable name. + * + * @param varName Variable name + * @param value 16 bit integer value to write + */ + public void setInt16ValueOf(String varName, byte value) + throws UnknownVariableException { + setInt16ValueOf(getVariable(varName).addr, value); + } + + /** + * Write 32 bit integer value to location associated with this variable name. + * + * @param varName Variable name + * @param value 32 bit integer value to write + */ + public void setInt32ValueOf(String varName, byte value) + throws UnknownVariableException { + setInt32ValueOf(getVariable(varName).addr, value); + } + + /** + * Write 64 bit integer value to location associated with this variable name. + * + * @param varName Variable name + * @param value 64 bit integer value to write + */ + public void setInt64ValueOf(String varName, byte value) + throws UnknownVariableException { + setInt64ValueOf(getVariable(varName).addr, value); + } + + /** + * Write byte value to location associated with this variable name. + * + * @param varName Variable name + * @param value byte value to write + */ + public void setByteValueOf(String varName, byte value) + throws UnknownVariableException { + setByteValueOf(getVariable(varName).addr, value); + } + + /** + * Write short value to location associated with this variable name. + * + * @param varName Variable name + * @param value short value to write + */ + public void setShortValueOf(String varName, short value) + throws UnknownVariableException { + setShortValueOf(getVariable(varName).addr, value); + } + + /** + * Write int value to location associated with this variable name. + * + * @param varName Variable name + * @param value int value to write + */ + public void setIntValueOf(String varName, int value) + throws UnknownVariableException { + setIntValueOf(getVariable(varName).addr, value); + } + + /** + * Write long value to location associated with this variable name. + * + * @param varName Variable name + * @param value long value to write + */ + public void setLongValueOf(String varName, long value) + throws UnknownVariableException { + setLongValueOf(getVariable(varName).addr, value); + } + + /** + * Write pointer value to location associated with this variable name. + * + * The number of bytes actually written depends on the pointer size + * defined in memory layout. + * + * @param varName Variable name + * @param value Value to write + */ + public void setAddrValueOf(String varName, long value) + throws UnknownVariableException { + setAddrValueOf(getVariable(varName).addr, value); + } + + /** + * + * @param varName + * @param data + */ + public void setByteArray(String varName, byte[] data) + throws UnknownVariableException { + memIntf.setMemorySegment(getVariable(varName).addr, data); + } + + /** + * Adds a MemoryMonitor for the specified address region. + * + * @param flag Select memory operation(s) to listen for (read, write, + * read/write) + * @param varName + * @param mm + * @return + */ + public boolean addVarMonitor(EventType flag, final String varName, final SegmentMonitor mm) { + return memIntf.addSegmentMonitor( + flag, + getVariable(varName).addr, + getVariable(varName).size, + mm); + } + + /** + * Removes MemoryMonitor assigned to the specified region. + * + * @param varName + * @param mm MemoryMonitor to remove + */ + public void removeVarMonitor(String varName, SegmentMonitor mm) { + memIntf.removeSegmentMonitor(getVariable(varName).addr, getVariable(varName).size, mm); + } +} diff --git a/tools/cooja/java/org/contikios/cooja/motes/AbstractApplicationMote.java b/tools/cooja/java/org/contikios/cooja/motes/AbstractApplicationMote.java index ec381e163..98de78327 100644 --- a/tools/cooja/java/org/contikios/cooja/motes/AbstractApplicationMote.java +++ b/tools/cooja/java/org/contikios/cooja/motes/AbstractApplicationMote.java @@ -33,21 +33,22 @@ import java.util.Collection; import java.util.HashMap; import java.util.Observable; import java.util.Observer; -import java.util.Properties; import org.apache.log4j.Logger; import org.jdom.Element; import org.contikios.cooja.Mote; import org.contikios.cooja.MoteInterface; import org.contikios.cooja.MoteInterfaceHandler; -import org.contikios.cooja.MoteMemory; import org.contikios.cooja.MoteType; import org.contikios.cooja.RadioPacket; -import org.contikios.cooja.SectionMoteMemory; +import org.contikios.cooja.mote.memory.SectionMoteMemory; import org.contikios.cooja.Simulation; 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; /** * Abstract application mote. @@ -67,6 +68,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme /* Observe our own radio for incoming radio packets */ private Observer radioDataObserver = new Observer() { + @Override public void update(Observable obs, Object obj) { ApplicationRadio radio = (ApplicationRadio) obs; if (radio.getLastEvent() == Radio.RadioEvent.RECEPTION_FINISHED) { @@ -89,7 +91,8 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme public AbstractApplicationMote(MoteType moteType, Simulation sim) { setSimulation(sim); this.moteType = moteType; - this.memory = new SectionMoteMemory(new HashMap(), 0); + MemoryLayout.getNative(); + this.memory = new SectionMoteMemory(new HashMap()); this.moteInterfaces = new MoteInterfaceHandler(this, moteType.getMoteInterfaceClasses()); this.moteInterfaces.getRadio().addObserver(radioDataObserver); requestImmediateWakeup(); @@ -99,6 +102,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme ((ApplicationSerialPort)moteInterfaces.getLog()).triggerLog(msg); } + @Override public MoteInterfaceHandler getInterfaces() { return moteInterfaces; } @@ -107,14 +111,16 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme moteInterfaces = moteInterfaceHandler; } - public MoteMemory getMemory() { + @Override + public MemoryInterface getMemory() { return memory; } - public void setMemory(MoteMemory memory) { + public void setMemory(SectionMoteMemory memory) { this.memory = (SectionMoteMemory) memory; } + @Override public MoteType getType() { return moteType; } @@ -123,6 +129,7 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme moteType = type; } + @Override public Collection getConfigXML() { ArrayList config = new ArrayList(); Element element; @@ -141,10 +148,11 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme return config; } + @Override public boolean setConfigXML(Simulation simulation, Collection configXML, boolean visAvailable) { setSimulation(simulation); - this.memory = new SectionMoteMemory(new HashMap(), 0); + this.memory = new SectionMoteMemory(new HashMap()); moteInterfaces.getRadio().addObserver(radioDataObserver); for (Element element : configXML) { @@ -176,10 +184,12 @@ public abstract class AbstractApplicationMote extends AbstractWakeupMote impleme return true; } + @Override public int getID() { return moteInterfaces.getMoteID().getMoteID(); } + @Override public String toString() { return "AppMote " + getID(); } diff --git a/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java b/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java index cf6562d8f..aa668b66b 100644 --- a/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java +++ b/tools/cooja/java/org/contikios/cooja/plugins/BufferListener.java @@ -89,8 +89,6 @@ import org.jdom.Element; import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Cooja; import org.contikios.cooja.Mote; -import org.contikios.cooja.MoteMemory; -import org.contikios.cooja.MoteMemory.MemoryEventType; import org.contikios.cooja.Plugin; import org.contikios.cooja.PluginType; import org.contikios.cooja.SimEventCentral.MoteCountListener; @@ -100,6 +98,10 @@ import org.contikios.cooja.VisPlugin; import org.contikios.cooja.dialogs.TableColumnAdjuster; import org.contikios.cooja.dialogs.UpdateAggregator; import org.contikios.cooja.interfaces.IPAddress; +import org.contikios.cooja.mote.memory.MemoryBuffer; +import org.contikios.cooja.mote.memory.MemoryInterface; +import org.contikios.cooja.mote.memory.MemoryInterface.SegmentMonitor; +import org.contikios.cooja.mote.memory.VarMemory; import org.contikios.cooja.motes.AbstractEmulatedMote; import org.contikios.cooja.util.ArrayQueue; import org.contikios.cooja.util.StringUtils; @@ -163,6 +165,7 @@ public class BufferListener extends VisPlugin { private Parser parser = null; private Buffer buffer = null; + @Override public void startPlugin() { super.startPlugin(); if (parser == null) { @@ -214,6 +217,7 @@ public class BufferListener extends VisPlugin { private ArrayList memoryMonitors = new ArrayList(); private TimeEvent hourTimeEvent = new TimeEvent(0) { + @Override public void execute(long t) { hasHours = true; repaintTimeColumn(); @@ -224,11 +228,13 @@ public class BufferListener extends VisPlugin { private static final int UPDATE_INTERVAL = 250; private UpdateAggregator logUpdateAggregator = new UpdateAggregator(UPDATE_INTERVAL) { private Runnable scroll = new Runnable() { + @Override public void run() { logTable.scrollRectToVisible( new Rectangle(0, logTable.getHeight() - 2, 1, logTable.getHeight())); } }; + @Override protected void handle(List ls) { boolean isVisible = true; if (logTable.getRowCount() > 0) { @@ -276,18 +282,22 @@ public class BufferListener extends VisPlugin { model = new AbstractTableModel() { private static final long serialVersionUID = 3065150390849332924L; + @Override public String getColumnName(int col) { if (col == COLUMN_TIME && formatTimeString) { return "Time"; } return COLUMN_NAMES[col]; } + @Override public int getRowCount() { return logs.size(); } + @Override public int getColumnCount() { return COLUMN_NAMES.length; } + @Override public Object getValueAt(int row, int col) { BufferAccess log = logs.get(row); if (col == COLUMN_TIME) { @@ -307,6 +317,7 @@ public class BufferListener extends VisPlugin { logTable = new JTable(model) { private static final long serialVersionUID = -930616018336483196L; + @Override public String getToolTipText(MouseEvent e) { java.awt.Point p = e.getPoint(); int rowIndex = rowAtPoint(p); @@ -356,6 +367,7 @@ public class BufferListener extends VisPlugin { new Color(220, 255, 220), new Color(255, 200, 255), }; + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { @@ -405,6 +417,7 @@ public class BufferListener extends VisPlugin { logTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); logTable.setFont(new Font("Monospaced", Font.PLAIN, 12)); logTable.addKeyListener(new KeyAdapter() { + @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { showInAllAction.actionPerformed(null); @@ -419,6 +432,7 @@ public class BufferListener extends VisPlugin { /* Toggle time format */ logTable.getTableHeader().addMouseListener(new MouseAdapter() { + @Override public void mouseClicked(MouseEvent e) { int colIndex = logTable.columnAtPoint(e.getPoint()); int columnIndex = logTable.convertColumnIndexToModel(colIndex); @@ -432,6 +446,7 @@ public class BufferListener extends VisPlugin { }); logTable.addMouseListener(new MouseAdapter() { private Parser lastParser = null; + @Override public void mousePressed(MouseEvent e) { if (e.getButton() != MouseEvent.BUTTON2) { return; @@ -444,6 +459,7 @@ public class BufferListener extends VisPlugin { setParser(ByteArrayParser.class); } } + @Override public void mouseExited(MouseEvent e) { if (lastParser != null) { /* Switch back to previous parser */ @@ -451,6 +467,7 @@ public class BufferListener extends VisPlugin { lastParser = null; } } + @Override public void mouseReleased(MouseEvent e) { if (lastParser != null) { /* Switch back to previous parser */ @@ -458,6 +475,7 @@ public class BufferListener extends VisPlugin { lastParser = null; } } + @Override public void mouseClicked(MouseEvent e) { int colIndex = logTable.columnAtPoint(e.getPoint()); int columnIndex = logTable.convertColumnIndexToModel(colIndex); @@ -482,21 +500,27 @@ public class BufferListener extends VisPlugin { /* Popup menu */ JPopupMenu popupMenu = new JPopupMenu(); bufferMenu.addMenuListener(new MenuListener() { + @Override public void menuSelected(MenuEvent e) { updateBufferMenu(); } + @Override public void menuDeselected(MenuEvent e) { } + @Override public void menuCanceled(MenuEvent e) { } }); popupMenu.add(bufferMenu); parserMenu.addMenuListener(new MenuListener() { + @Override public void menuSelected(MenuEvent e) { updateParserMenu(); } + @Override public void menuDeselected(MenuEvent e) { } + @Override public void menuCanceled(MenuEvent e) { } }); @@ -521,6 +545,7 @@ public class BufferListener extends VisPlugin { colorCheckbox = new JCheckBoxMenuItem("Mote-specific coloring"); popupMenu.add(colorCheckbox); colorCheckbox.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { backgroundColors = colorCheckbox.isSelected(); repaint(); @@ -529,6 +554,7 @@ public class BufferListener extends VisPlugin { inverseFilterCheckbox = new JCheckBoxMenuItem("Inverse filter"); popupMenu.add(inverseFilterCheckbox); inverseFilterCheckbox.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { inverseFilter = inverseFilterCheckbox.isSelected(); if (inverseFilter) { @@ -543,6 +569,7 @@ public class BufferListener extends VisPlugin { hideReadsCheckbox = new JCheckBoxMenuItem("Hide READs", hideReads); popupMenu.add(hideReadsCheckbox); hideReadsCheckbox.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { hideReads = hideReadsCheckbox.isSelected(); setFilter(getFilter()); @@ -553,6 +580,7 @@ public class BufferListener extends VisPlugin { withStackTraceCheckbox = new JCheckBoxMenuItem("Capture stack traces", withStackTrace); popupMenu.add(withStackTraceCheckbox); withStackTraceCheckbox.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { withStackTrace = withStackTraceCheckbox.isSelected(); setFilter(getFilter()); @@ -564,6 +592,7 @@ public class BufferListener extends VisPlugin { /* Column width adjustment */ java.awt.EventQueue.invokeLater(new Runnable() { + @Override public void run() { /* Make sure this happens *after* adding history */ adjuster.setDynamicAdjustment(true); @@ -573,6 +602,7 @@ public class BufferListener extends VisPlugin { logUpdateAggregator.start(); simulation.getEventCentral().addMoteCountListener(logOutputListener = new MoteCountListener() { + @Override public void moteWasAdded(Mote mote) { /* Update title */ try { @@ -581,6 +611,7 @@ public class BufferListener extends VisPlugin { logger.warn("Could not monitor buffer on: " + mote, e); } } + @Override public void moteWasRemoved(Mote mote) { /* Update title */ stopObserving(mote); @@ -596,12 +627,14 @@ public class BufferListener extends VisPlugin { filterPanel.add(filterLabel); filterPanel.add(filterTextField); filterTextField.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { String str = filterTextField.getText(); setFilter(str); /* Autoscroll */ SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { int s = logTable.getSelectedRow(); if (s < 0) { @@ -664,23 +697,24 @@ public class BufferListener extends VisPlugin { private void registerSegmentMonitor(int size, boolean notify) throws Exception { byte[] pointerValue = mote.getMemory().getMemorySegment(pointerAddress, pointerSize); - int segmentAddress = mote.getMemory().parseInt(pointerValue); + int segmentAddress = MemoryBuffer.wrap(mote.getMemory().getLayout(), pointerValue).getInt(); segmentMonitor = new SegmentMemoryMonitor(bl, mote, segmentAddress, size); if (notify) { - segmentMonitor.memoryChanged(mote.getMemory(), MemoryEventType.WRITE, -1); + segmentMonitor.memoryChanged(mote.getMemory(), EventType.WRITE, -1); } lastSegmentAddress = segmentAddress; } - final public void memoryChanged(MoteMemory memory, - org.contikios.cooja.MoteMemory.MemoryEventType type, int address) { - if (type == MemoryEventType.READ) { + @Override + final public void memoryChanged(MemoryInterface memory, + EventType type, long address) { + if (type == EventType.READ) { return; } byte[] pointerValue = mote.getMemory().getMemorySegment(pointerAddress, pointerSize); - int segmentAddress = mote.getMemory().parseInt(pointerValue); + int segmentAddress = MemoryBuffer.wrap(mote.getMemory().getLayout(), pointerValue).getInt(); if (segmentAddress == lastSegmentAddress) { return; } @@ -694,17 +728,19 @@ public class BufferListener extends VisPlugin { } } + @Override public MemoryMonitorType getType() { return MemoryMonitorType.POINTER; } + @Override public void dispose() { super.dispose(); segmentMonitor.dispose(); } } - static class SegmentMemoryMonitor implements org.contikios.cooja.MoteMemory.MemoryMonitor { + static class SegmentMemoryMonitor implements SegmentMonitor { protected final BufferListener bl; protected final Mote mote; @@ -721,7 +757,7 @@ public class BufferListener extends VisPlugin { this.size = size; if (address != 0) { - if (!mote.getMemory().addMemoryMonitor(address, size, this)) { + if (!mote.getMemory().addSegmentMonitor(SegmentMonitor.EventType.WRITE, address, size, this)) { throw new Exception("Could not register memory monitor on: " + mote); } } @@ -742,17 +778,18 @@ public class BufferListener extends VisPlugin { public void dispose() { if (address != 0) { - mote.getMemory().removeMemoryMonitor(address, size, this); + mote.getMemory().removeSegmentMonitor(address, size, this); } } - public void memoryChanged(MoteMemory memory, MemoryEventType type, int address) { + @Override + public void memoryChanged(MemoryInterface memory, EventType type, long address) { byte[] newData = getAddress()==0?null:mote.getMemory().getMemorySegment(getAddress(), getSize()); addBufferAccess(bl, mote, oldData, newData, type, this.address); oldData = newData; } - void addBufferAccess(BufferListener bl, Mote mote, byte[] oldData, byte[] newData, MemoryEventType type, int address) { + void addBufferAccess(BufferListener bl, Mote mote, byte[] oldData, byte[] newData, EventType type, int address) { BufferAccess ba = new BufferAccess( mote, mote.getSimulation().getSimulationTime(), @@ -793,6 +830,7 @@ public class BufferListener extends VisPlugin { } } + @Override public void closePlugin() { if (hourTimeEvent != null) hourTimeEvent.remove(); @@ -805,6 +843,7 @@ public class BufferListener extends VisPlugin { } } + @Override public Collection getConfigXML() { ArrayList config = new ArrayList(); Element element; @@ -845,12 +884,14 @@ public class BufferListener extends VisPlugin { return config; } + @Override public boolean setConfigXML(Collection configXML, boolean visAvailable) { for (Element element : configXML) { String name = element.getName(); if ("filter".equals(name)) { final String str = element.getText(); EventQueue.invokeLater(new Runnable() { + @Override public void run() { setFilter(str); } @@ -914,10 +955,11 @@ public class BufferListener extends VisPlugin { regexp = null; } RowFilter wrapped = new RowFilter() { + @Override public boolean include(RowFilter.Entry entry) { if (hideReads) { int row = (Integer) entry.getIdentifier(); - if (logs.get(row).type == MemoryEventType.READ) { + if (logs.get(row).type == SegmentMonitor.EventType.READ) { return false; } } @@ -945,6 +987,7 @@ public class BufferListener extends VisPlugin { public void trySelectTime(final long time) { java.awt.EventQueue.invokeLater(new Runnable() { + @Override public void run() { for (int i=0; i < logs.size(); i++) { if (logs.get(i).time < time) { @@ -972,13 +1015,13 @@ public class BufferListener extends VisPlugin { public final byte[] mem; private boolean[] accessedBitpattern = null; - public final MemoryEventType type; + public final SegmentMonitor.EventType type; public final String sourceStr; public final String stackTrace; public final int address; public BufferAccess( - Mote mote, long time, int address, byte[] newData, byte[] oldData, MemoryEventType type, boolean withStackTrace) { + Mote mote, long time, int address, byte[] newData, byte[] oldData, SegmentMonitor.EventType type, boolean withStackTrace) { this.mote = mote; this.time = time; this.mem = newData==null?NULL_DATA:newData; @@ -1054,6 +1097,7 @@ public class BufferListener extends VisPlugin { private Action saveAction = new AbstractAction("Save to file") { private static final long serialVersionUID = -4140706275748686944L; + @Override public void actionPerformed(ActionEvent e) { JFileChooser fc = new JFileChooser(); File suggest = new File(Cooja.getExternalToolsSetting("BUFFER_LISTENER_SAVEFILE", "BufferAccessLogger.txt")); @@ -1116,6 +1160,7 @@ public class BufferListener extends VisPlugin { private Action bufferListenerAction = new AbstractAction("in Buffer Listener") { private static final long serialVersionUID = -6358463434933029699L; + @Override public void actionPerformed(ActionEvent e) { int view = logTable.getSelectedRow(); if (view < 0) { @@ -1139,6 +1184,7 @@ public class BufferListener extends VisPlugin { private Action timeLineAction = new AbstractAction("in Timeline") { private static final long serialVersionUID = -6358463434933029699L; + @Override public void actionPerformed(ActionEvent e) { int view = logTable.getSelectedRow(); if (view < 0) { @@ -1162,6 +1208,7 @@ public class BufferListener extends VisPlugin { private Action radioLoggerAction = new AbstractAction("in Radio Logger") { private static final long serialVersionUID = -3041714249257346688L; + @Override public void actionPerformed(ActionEvent e) { int view = logTable.getSelectedRow(); if (view < 0) { @@ -1189,6 +1236,7 @@ public class BufferListener extends VisPlugin { putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true)); } + @Override public void actionPerformed(ActionEvent e) { timeLineAction.actionPerformed(null); radioLoggerAction.actionPerformed(null); @@ -1197,6 +1245,7 @@ public class BufferListener extends VisPlugin { private Action clearAction = new AbstractAction("Clear") { private static final long serialVersionUID = -2115620313183440224L; + @Override public void actionPerformed(ActionEvent e) { int size = logs.size(); if (size > 0) { @@ -1208,6 +1257,7 @@ public class BufferListener extends VisPlugin { private Action copyAction = new AbstractAction("Selected") { private static final long serialVersionUID = -8433490108577001803L; + @Override public void actionPerformed(ActionEvent e) { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -1240,6 +1290,7 @@ public class BufferListener extends VisPlugin { private Action copyAllAction = new AbstractAction("All") { private static final long serialVersionUID = -5038884975254178373L; + @Override public void actionPerformed(ActionEvent e) { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -1269,6 +1320,7 @@ public class BufferListener extends VisPlugin { private final ActionListener parserSelectedListener = new ActionListener() { @SuppressWarnings("unchecked") + @Override public void actionPerformed(ActionEvent e) { Class bpClass = (Class) @@ -1289,6 +1341,7 @@ public class BufferListener extends VisPlugin { private final ActionListener bufferSelectedListener = new ActionListener() { @SuppressWarnings("unchecked") + @Override public void actionPerformed(ActionEvent e) { Class btClass = (Class) @@ -1421,6 +1474,7 @@ public class BufferListener extends VisPlugin { } public static abstract class GraphicalParser implements Parser { BufferAccess ba = null; + @Override public Object parse(BufferAccess ba) { this.ba = ba; return ba; @@ -1430,6 +1484,7 @@ public class BufferListener extends VisPlugin { } public static abstract class StringParser implements Parser { + @Override public Object parse(BufferAccess ba) { return parseString(ba); } @@ -1459,13 +1514,17 @@ public class BufferListener extends VisPlugin { public void writeConfig(Element element); } public static abstract class AbstractBuffer implements Buffer { + @Override public String getStatusString() { return null; } + @Override public void writeConfig(Element element) { } + @Override public void applyConfig(Element element) { } + @Override public boolean configure(BufferListener bl) { return true; } @@ -1474,18 +1533,20 @@ public class BufferListener extends VisPlugin { public static abstract class PointerBuffer extends AbstractBuffer { public abstract int getPointerAddress(Mote mote); + @Override public SegmentMemoryMonitor createMemoryMonitor(BufferListener bl, Mote mote) throws Exception { return new PointerMemoryMonitor( bl, mote, getPointerAddress(mote), - mote.getMemory().getIntegerLength(), + mote.getMemory().getLayout().intSize, getSize(mote) ); } } public static abstract class SegmentBuffer extends AbstractBuffer { + @Override public SegmentMemoryMonitor createMemoryMonitor(BufferListener bl, Mote mote) throws Exception { return new SegmentMemoryMonitor( @@ -1521,6 +1582,7 @@ public class BufferListener extends VisPlugin { @ClassDescription("Byte array") public static class ByteArrayParser extends StringParser { + @Override public String parseString(BufferAccess ba) { boolean[] diff = ba.getAccessedBitpattern(); if (diff == null) { @@ -1562,15 +1624,18 @@ public class BufferListener extends VisPlugin { @ClassDescription("Integer array") public static class IntegerParser extends StringParser { + private VarMemory varMem = new VarMemory(null); + @Override public String parseString(BufferAccess ba) { StringBuilder sb = new StringBuilder(); + varMem.associateMemory(ba.mote.getMemory()); - int intLen = ba.mote.getMemory().getIntegerLength(); + int intLen = ba.mote.getMemory().getLayout().intSize; sb.append(""); for (int i=0; i < ba.mem.length/intLen; i++) { byte[] mem = Arrays.copyOfRange(ba.mem, i*intLen,(i+1)*intLen); boolean[] diff = Arrays.copyOfRange(ba.getAccessedBitpattern(), i*intLen,(i+1)*intLen); - int val = ba.mote.getMemory().parseInt(mem); + int val = MemoryBuffer.wrap(ba.mote.getMemory().getLayout(), mem).getInt(); boolean red = false; for (boolean changed: diff) { @@ -1592,6 +1657,7 @@ public class BufferListener extends VisPlugin { @ClassDescription("Terminated string") public static class TerminatedStringParser extends StringParser { + @Override public String parseString(BufferAccess ba) { /* TODO Diff? */ int i; @@ -1608,6 +1674,7 @@ public class BufferListener extends VisPlugin { @ClassDescription("Printable characters") public static class PrintableCharactersParser extends StringParser { + @Override public String parseString(BufferAccess ba) { /* TODO Diff? */ return new String(ba.mem).replaceAll("[^\\p{Print}]", ""); @@ -1616,6 +1683,7 @@ public class BufferListener extends VisPlugin { @ClassDescription("IPv6 address") public static class IPv6AddressParser extends StringParser { + @Override public String parseString(BufferAccess ba) { /* TODO Diff? */ if (ba.mem.length < 16) { @@ -1634,6 +1702,7 @@ public class BufferListener extends VisPlugin { @ClassDescription("IPv4 address") public static class IPv4AddressParser extends StringParser { + @Override public String parseString(BufferAccess ba) { /* TODO Diff? */ if (ba.mem.length < 4) { @@ -1664,6 +1733,7 @@ public class BufferListener extends VisPlugin { parser.ba = ba; setPreferredSize(new Dimension(parser.getUnscaledWidth() + 2*XOFFSET, HEIGHT)); } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.translate(XOFFSET, 0); @@ -1681,9 +1751,11 @@ public class BufferListener extends VisPlugin { @ClassDescription("Graphical: Height") public static class GraphicalHeight4BitsParser extends GraphicalParser { + @Override public int getUnscaledWidth() { return ba.mem.length*2; } + @Override public void paintComponent(Graphics g, JComponent c) { g.setColor(Color.GRAY); boolean[] diff = ba.getAccessedBitpattern(); @@ -1707,9 +1779,11 @@ public class BufferListener extends VisPlugin { @ClassDescription("Graphical: Grayscale") public static class GraphicalGrayscale4BitsParser extends GraphicalParser { + @Override public int getUnscaledWidth() { return ba.mem.length*2; } + @Override public void paintComponent(Graphics g, JComponent c) { boolean[] diff = ba.getAccessedBitpattern(); for (int x=0; x < ba.mem.length; x++) { @@ -1730,27 +1804,31 @@ public class BufferListener extends VisPlugin { @ClassDescription("Variable: node_id") public static class NodeIDBuffer extends SegmentBuffer { + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists("node_id")) { + if (!mote.getMemory().getSymbolMap().containsKey("node_id")) { return -1; } - return mote.getMemory().getVariableAddress("node_id"); + return (int) mote.getMemory().getSymbolMap().get("node_id").addr; } + @Override public int getSize(Mote mote) { - return mote.getMemory().getIntegerLength(); + return mote.getMemory().getLayout().intSize; } } @ClassDescription("Queuebuf 0 RAM") public static class Queuebuf0Buffer extends SegmentBuffer { + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists("buframmem")) { + if (!mote.getMemory().getSymbolMap().containsKey("buframmem")) { return -1; } int offset = 0; - return mote.getMemory().getVariableAddress("buframmem") + offset; + return (int) mote.getMemory().getSymbolMap().get("buframmem").addr + offset; } + @Override public int getSize(Mote mote) { return 128; } @@ -1758,12 +1836,14 @@ public class BufferListener extends VisPlugin { @ClassDescription("packetbuf_aligned") public static class PacketbufBuffer extends SegmentBuffer { + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists("packetbuf_aligned")) { + if (!mote.getMemory().getSymbolMap().containsKey("packetbuf_aligned")) { return -1; } - return mote.getMemory().getVariableAddress("packetbuf_aligned"); + return (int) mote.getMemory().getSymbolMap().get("packetbuf_aligned").addr; } + @Override public int getSize(Mote mote) { return 128; } @@ -1771,18 +1851,23 @@ public class BufferListener extends VisPlugin { @ClassDescription("*packetbufptr") public static class PacketbufPointerBuffer extends PointerBuffer { + VarMemory varMem = new VarMemory(null); + @Override public int getPointerAddress(Mote mote) { - if (!mote.getMemory().variableExists("packetbufptr")) { + if (!mote.getMemory().getSymbolMap().containsKey("packetbufptr")) { return -1; } - return mote.getMemory().getVariableAddress("packetbufptr"); + return (int) mote.getMemory().getSymbolMap().get("packetbufptr").addr; } + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists("packetbufptr")) { + if (!mote.getMemory().getSymbolMap().containsKey("packetbufptr")) { return -1; } - return mote.getMemory().getIntValueOf("packetbufptr"); + varMem.associateMemory(mote.getMemory()); + return varMem.getIntValueOf("packetbufptr"); } + @Override public int getSize(Mote mote) { return 128; } @@ -1793,25 +1878,31 @@ public class BufferListener extends VisPlugin { public String variable; public int size; public int offset; + VarMemory varMem = new VarMemory(null); + @Override public int getPointerAddress(Mote mote) { - if (!mote.getMemory().variableExists(variable)) { + if (!mote.getMemory().getSymbolMap().containsKey(variable)) { return -1; } - return mote.getMemory().getVariableAddress(variable); + return (int) mote.getMemory().getSymbolMap().get(variable).addr; } + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists(variable)) { + if (!mote.getMemory().getSymbolMap().containsKey(variable)) { return -1; } - return mote.getMemory().getIntValueOf(variable)+offset; + varMem.associateMemory(mote.getMemory()); + return varMem.getIntValueOf(variable)+offset; } + @Override public int getSize(Mote mote) { - if (!mote.getMemory().variableExists(variable)) { + if (!mote.getMemory().getSymbolMap().containsKey(variable)) { return -1; } return size; } + @Override public String getStatusString() { if (offset > 0) { return "Pointer *" + variable + "[" + offset + "] (" + size + ")"; @@ -1820,16 +1911,19 @@ public class BufferListener extends VisPlugin { } } + @Override public void writeConfig(Element element) { element.setAttribute("variable", variable); element.setAttribute("size", "" + size); element.setAttribute("offset", "" + offset); } + @Override public void applyConfig(Element element) { variable = element.getAttributeValue("variable"); size = Integer.parseInt(element.getAttributeValue("size")); offset = Integer.parseInt(element.getAttributeValue("offset")); } + @Override public boolean configure(BufferListener bl) { String suggestName = Cooja.getExternalToolsSetting("BUFFER_LISTENER_VARNAME", "node_id"); String suggestSize = Cooja.getExternalToolsSetting("BUFFER_LISTENER_VARSIZE", "2"); @@ -1880,19 +1974,22 @@ public class BufferListener extends VisPlugin { public String variable; public int size; public int offset; + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists(variable)) { + if (!mote.getMemory().getSymbolMap().containsKey(variable)) { return -1; } - return mote.getMemory().getVariableAddress(variable)+offset; + return (int) mote.getMemory().getSymbolMap().get(variable).addr+offset; } + @Override public int getSize(Mote mote) { - if (!mote.getMemory().variableExists(variable)) { + if (!mote.getMemory().getSymbolMap().containsKey(variable)) { return -1; } return size; } + @Override public String getStatusString() { if (offset > 0) { return "Symbol &" + variable + "[" + offset + "] (" + size + ")"; @@ -1901,16 +1998,19 @@ public class BufferListener extends VisPlugin { } } + @Override public void writeConfig(Element element) { element.setAttribute("variable", variable); element.setAttribute("size", "" + size); element.setAttribute("offset", "" + offset); } + @Override public void applyConfig(Element element) { variable = element.getAttributeValue("variable"); size = Integer.parseInt(element.getAttributeValue("size")); offset = Integer.parseInt(element.getAttributeValue("offset")); } + @Override public boolean configure(BufferListener bl) { String suggestName = Cooja.getExternalToolsSetting("BUFFER_LISTENER_VARNAME", "node_id"); String suggestSize = Cooja.getExternalToolsSetting("BUFFER_LISTENER_VARSIZE", "2"); @@ -1958,26 +2058,32 @@ public class BufferListener extends VisPlugin { @ClassDescription("Integer...") public static class CustomIntegerBuffer extends SegmentBuffer { public String variable; + @Override public int getAddress(Mote mote) { - if (!mote.getMemory().variableExists(variable)) { + if (!mote.getMemory().getSymbolMap().containsKey(variable)) { return -1; } - return mote.getMemory().getVariableAddress(variable); + return (int) mote.getMemory().getSymbolMap().get(variable).addr; } + @Override public int getSize(Mote mote) { - return mote.getMemory().getIntegerLength(); + return mote.getMemory().getLayout().intSize; } + @Override public String getStatusString() { return "Integer " + variable; } + @Override public void writeConfig(Element element) { element.setAttribute("variable", variable); } + @Override public void applyConfig(Element element) { variable = element.getAttributeValue("variable"); } + @Override public boolean configure(BufferListener bl) { String suggestName = Cooja.getExternalToolsSetting("BUFFER_LISTENER_VARNAME", "node_id"); BufferInput infoComponent = diff --git a/tools/cooja/java/org/contikios/cooja/plugins/VariableWatcher.java b/tools/cooja/java/org/contikios/cooja/plugins/VariableWatcher.java index b6dc2061c..6c8c82ea9 100644 --- a/tools/cooja/java/org/contikios/cooja/plugins/VariableWatcher.java +++ b/tools/cooja/java/org/contikios/cooja/plugins/VariableWatcher.java @@ -44,8 +44,10 @@ import java.awt.event.KeyListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.NumberFormat; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Vector; import javax.swing.BorderFactory; @@ -64,7 +66,6 @@ import javax.swing.text.PlainDocument; import org.jdom.Element; -import org.contikios.cooja.AddressMemory; import org.contikios.cooja.ClassDescription; import org.contikios.cooja.Cooja; import org.contikios.cooja.Mote; @@ -72,7 +73,8 @@ import org.contikios.cooja.MotePlugin; import org.contikios.cooja.PluginType; import org.contikios.cooja.Simulation; import org.contikios.cooja.VisPlugin; -import org.contikios.cooja.AddressMemory.UnknownVariableException; +import org.contikios.cooja.mote.memory.UnknownVariableException; +import org.contikios.cooja.mote.memory.VarMemory; /** * Variable Watcher enables a user to watch mote variables during a simulation. @@ -87,7 +89,7 @@ import org.contikios.cooja.AddressMemory.UnknownVariableException; public class VariableWatcher extends VisPlugin implements MotePlugin { private static final long serialVersionUID = 1L; - private AddressMemory moteMemory; + private VarMemory moteMemory; private final static int LABEL_WIDTH = 170; private final static int LABEL_HEIGHT = 15; @@ -124,7 +126,7 @@ public class VariableWatcher extends VisPlugin implements MotePlugin { public VariableWatcher(Mote moteToView, Simulation simulation, Cooja gui) { super("Variable Watcher (" + moteToView + ")", gui); this.mote = moteToView; - moteMemory = (AddressMemory) moteToView.getMemory(); + moteMemory = new VarMemory(moteToView.getMemory()); JLabel label; integerFormat = NumberFormat.getIntegerInstance(); @@ -143,8 +145,8 @@ public class VariableWatcher extends VisPlugin implements MotePlugin { varName.setEditable(true); varName.setSelectedItem("[enter or pick name]"); - String[] allPotentialVarNames = moteMemory.getVariableNames(); - Arrays.sort(allPotentialVarNames); + List allPotentialVarNames = new ArrayList<>(moteMemory.getVariableNames()); + Collections.sort(allPotentialVarNames); for (String aVarName: allPotentialVarNames) { varName.addItem(aVarName); } @@ -172,7 +174,7 @@ public class VariableWatcher extends VisPlugin implements MotePlugin { varType = new JComboBox(); varType.addItem("Byte (1 byte)"); // BYTE_INDEX = 0 - varType.addItem("Integer (" + moteMemory.getIntegerLength() + " bytes)"); // INT_INDEX = 1 + varType.addItem("Integer (" + moteToView.getMemory().getLayout().intSize + " bytes)"); // INT_INDEX = 1 varType.addItem("Byte array (x bytes)"); // ARRAY_INDEX = 2 varType.addItem("Char array (x bytes)"); // CHAR_ARRAY_INDEX = 3

Identifier") - .append(getIdentifier()).append("
Description") - .append(getDescription()).append("
Contiki application") - .append(getContikiSourceFile().getAbsolutePath()).append("
Contiki firmware") - .append(getContikiFirmwareFile().getAbsolutePath()).append("
JNI library") - .append(this.javaClassName).append("
Contiki sensors"); - for (String sensor: sensors) { + for (String sensor : sensors) { sb.append(sensor).append("
"); } sb.append("
Mote interface"); - for (Class moteInterface: moteInterfacesClasses) { + for (Class moteInterface : moteInterfacesClasses) { sb.append(moteInterface.getSimpleName()).append("
"); } sb.append("
Contiki's mote interface"); - for (String coreInterface: getCoreInterfaces()) { + for (String coreInterface : getCoreInterfaces()) { sb.append(coreInterface).append("
"); } sb.append("