Commit e90ee419 authored by Jean Meurice's avatar Jean Meurice

Make Computer/VCG 'Inspectable'

parent 5ef5454e
Pipeline #371754 passed with stage
in 1 minute and 4 seconds
......@@ -10,12 +10,12 @@
<groupId>montisim</groupId>
<artifactId>hardware_emulator</artifactId>
<version>2.0.1</version>
<version>2.0.3</version>
<properties>
<commons.version>2.0.6</commons.version>
<simulation.version>3.0.1</simulation.version>
<commons.version>2.0.10</commons.version>
<simulation.version>3.1.1</simulation.version>
<wagon.provider.version>2.6</wagon.provider.version>
......
......@@ -41,7 +41,7 @@ public class CppBridge {
static public void init(String config) throws Exception{
String version = getVersion();
if (!HardwareEmulatorVersion.version.equals(version))
throw new Exception("Wrong native HardwareEmulator library version: "+version+", expected: "+HardwareEmulatorVersion.version+". Make sure to match versions in 'software_simulator_manager.h' and recompile the C++ project.");
System.out.println("WARNING: Wrong native HardwareEmulator library version: "+version+", expected: "+HardwareEmulatorVersion.version+". Make sure to match versions in 'software_simulator_manager.h' and recompile the C++ project.");
initManager(config);
loaded = true;
}
......
......@@ -6,7 +6,9 @@ package de.rwth.montisim.hardware_emulator.computer;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;
import de.rwth.montisim.commons.dynamicinterface.PortInformation;
......@@ -14,6 +16,9 @@ import de.rwth.montisim.commons.dynamicinterface.ProgramInterface;
import de.rwth.montisim.commons.dynamicinterface.PortInformation.PortDirection;
import de.rwth.montisim.commons.eventsimulation.DiscreteEvent;
import de.rwth.montisim.commons.eventsimulation.exceptions.UnexpectedEventException;
import de.rwth.montisim.commons.simulation.Destroyable;
import de.rwth.montisim.commons.simulation.Destroyer;
import de.rwth.montisim.commons.simulation.Inspectable;
import de.rwth.montisim.commons.utils.Time;
import de.rwth.montisim.commons.utils.json.Json;
import de.rwth.montisim.commons.utils.json.JsonTraverser;
......@@ -28,7 +33,7 @@ import de.rwth.montisim.simulation.eesimulator.exceptions.EEMessageTypeException
import de.rwth.montisim.simulation.eesimulator.message.Message;
import de.rwth.montisim.simulation.eesimulator.message.MessageInformation;
public class Computer extends EEComponent {
public class Computer extends EEComponent implements Inspectable, Destroyable {
transient final ComputerProperties properties;
......@@ -38,21 +43,24 @@ public class Computer extends EEComponent {
transient HashMap<String, Integer> portIdByName = new HashMap<>();
transient JsonWriter writer = new JsonWriter(false);
transient JsonTraverser traverser = new JsonTraverser();
transient Instant lastExec = null;
transient Instant lastExec = null;
Object buffer[]; // Buffer for incoming inputs / Last output values
public Computer(ComputerProperties properties) throws HardwareEmulatorException, SerializationException {
public Computer(ComputerProperties properties, Destroyer destroyer) throws HardwareEmulatorException, SerializationException {
super(properties);
this.properties = properties;
this.id = CppBridge.allocSimulator(Json.toJson(properties));
System.out.println("Allocated SoftwareSimulator (id: " + this.id + ")");
String interface_description = CppBridge.getInterface(id);
program = Json.instantiateFromJson(interface_description, ProgramInterface.class);
destroyer.addDestroyable(this);
}
@Override
protected void init() throws EEMessageTypeException {
int i = 0;
msgInfos = new MessageInformation[program.ports.size()];
buffer = new Object[program.ports.size()];
for (PortInformation p : program.ports) {
if (p.direction == PortDirection.INPUT) {
msgInfos[i] = addInput(p.name, p.type, p.allows_multiple_inputs, p.optional);
......@@ -98,6 +106,7 @@ public class Computer extends EEComponent {
}
writer.init();
try {
buffer[i] = msg.message;
msg.msgInfo.type.toJson(writer, msg.message, null);
CppBridge.setPort(id, i, writer.getString());
} catch (SerializationException | HardwareEmulatorException e) {
......@@ -131,6 +140,7 @@ public class Computer extends EEComponent {
String data = CppBridge.getPort(id, i);
traverser.init(data);
Object msg = p.type.fromJson(traverser, null);
buffer[i] = msg;
sendMessage(sendTime, msgInfos[i], msg);
}
++i;
......@@ -141,12 +151,60 @@ public class Computer extends EEComponent {
eesystem.simulator.addEvent(new ExecuteEvent(this, newExecTime));
}
@Override
public String getType() {
return "autopilot";
}
@Override
public String getName() {
return properties.name;
}
@Override
public List<String> getEntries() {
List<String> entries = new ArrayList<>();
int i = 0;
for (PortInformation p : program.ports) {
String res = p.direction == PortDirection.INPUT ? "input: " : "output: ";
res += p.name + ": ";
Object val = buffer[i];
if (val == null) entries.add(res + "null");
else {
List<String> toStr = p.type.toString(val);
if (toStr.size() == 0) entries.add(res + "No toString()");
if (toStr.size() == 1) entries.add(res + toStr.get(0));
else {
entries.add(res);
for (String s : toStr) {
entries.add(" "+s);
}
}
}
++i;
}
return entries;
}
@Override
public void destroy() {
if (id < 0) throw new IllegalStateException("Calling Computer.destroy() on uninitialized/already destroyed component.");
clean();
}
protected void finalize() {
clean();
}
void clean() {
if (id < 0) return;
System.out.println("Freed SoftwareSimulator (id: " + this.id + ")");
try {
CppBridge.freeSimulator(id);
id = -1;
} catch (HardwareEmulatorException e) {
e.printStackTrace();
}
}
}
\ No newline at end of file
......@@ -132,7 +132,7 @@ public class ComputerProperties extends BusUserProperties {
@Override
public EEEventProcessor build(ComponentBuildContext context) {
try {
return new Computer(this);
return new Computer(this, context.componentDestroyer);
} catch (HardwareEmulatorException | SerializationException e) {
e.printStackTrace();
throw new IllegalArgumentException(e.getMessage());
......
......@@ -12,5 +12,6 @@ import de.rwth.montisim.hardware_emulator.vcg.VCGProperties.TimeMode;
public interface CommunicationInterface {
ProgramInterface init(TimeMode timeMode, int ref_id) throws Exception;
boolean isAlive();
Duration measuredCycle(Object portData[], double deltaSec) throws IOException ;
Duration measuredCycle(Object portData[], double deltaSec) throws IOException;
void close();
}
......@@ -48,42 +48,37 @@ public class TCPClient implements CommunicationInterface {
TCPClient client = new TCPClient(tcp);
ProgramInterface interf = client.init(TimeMode.MEASURED, 4000);
Object[] data = new Object[interf.ports.size()];
data[0] = 0.0;
data[1] = new Vec2(0,0);
data[1] = new Vec2(0, 0);
data[2] = 0.0;
data[3] = 3;
data[4] = new double[] {1.0, 2.0, 3.0};
data[5] = new double[] {0.0, 1.0, 1.0};
data[4] = new double[] { 1.0, 2.0, 3.0 };
data[5] = new double[] { 0.0, 1.0, 1.0 };
data[6] = 0.0;
data[7] = 0.0;
data[8] = 0.0;
System.out.println("Initialized VCG");
Duration dur = client.measuredCycle(data, 0.1);
System.out.println("Ran cycle in " + dur + " secs.");
System.out.println("steering="+data[9]+ " gas="+data[10]+ " braking="+data[11]);
System.out.println("steering=" + data[9] + " gas=" + data[10] + " braking=" + data[11]);
// Test PING
for (int i = 0; i < 10; ++i) {
long start = System.nanoTime();
client.sendPacket(PACKET_PING);
//client.sendPacket(PACKET_PING, 42);
// client.sendPacket(PACKET_PING, 42);
Packet p = client.getPacket();
long end = System.nanoTime();
//System.out.println("PING: " + Double.toString((end-start)*0.000001)+ "ms (Packet: "+p.id+", payload: "+p.data.length+")");
System.out.println("PING: " + Long.toString((end-start)/1000000)+ "ms");
// System.out.println("PING: " + Double.toString((end-start)*0.000001)+ "ms
// (Packet: "+p.id+", payload: "+p.data.length+")");
System.out.println("PING: " + Long.toString((end - start) / 1000000) + "ms");
}
client.sendPacket(PACKET_END);
}
Socket cs;
TCP tcpProperties;
BufferedReader in;
......@@ -92,34 +87,35 @@ public class TCPClient implements CommunicationInterface {
ProgramInterface interf;
public TCPClient(TCP tcpProperties){
public TCPClient(TCP tcpProperties) {
this.tcpProperties = tcpProperties;
}
@Override
public ProgramInterface init(TimeMode timeMode, int ref_id) throws Exception {
cs = new Socket(tcpProperties.host, tcpProperties.port);
System.out.println("VCG: started TCPClient with host " + tcpProperties.host + " on port " + Integer.toString(tcpProperties.port));
System.out.println("VCG: started TCPClient with host " + tcpProperties.host + " on port "
+ Integer.toString(tcpProperties.port));
in = new BufferedReader(new InputStreamReader(cs.getInputStream()));
din = new DataInputStream(cs.getInputStream());
out = new DataOutputStream(cs.getOutputStream());
// Send Init packet
//System.out.println("Sending INIT packet");
// System.out.println("Sending INIT packet");
sendPacket(PACKET_INIT, timeMode.name().toLowerCase());
sendPacket(PACKET_REF_ID, ref_id);
// Get "ProgramInterface" packet
//System.out.println("Waiting for INTERFACE packet");
// System.out.println("Waiting for INTERFACE packet");
Packet p = getPacket();
switch (p.id) {
case PACKET_ERROR:
throw new Exception("Error on VCG: "+new String(p.data));
throw new Exception("Error on VCG: " + new String(p.data));
case PACKET_INTERFACE:
this.interf = Json.instantiateFromJson(new String(p.data), ProgramInterface.class);
return this.interf;
this.interf = Json.instantiateFromJson(new String(p.data), ProgramInterface.class);
return this.interf;
default:
throw new Exception("Unexpected packet with id="+p.id);
throw new Exception("Unexpected packet with id=" + p.id);
}
}
......@@ -131,6 +127,7 @@ public class TCPClient implements CommunicationInterface {
out.write(bytes);
out.flush();
}
private void sendPacket(int packetId, byte[] bytes) throws IOException {
out.writeByte(packetId);
int payloadLength = bytes.length;
......@@ -138,20 +135,23 @@ public class TCPClient implements CommunicationInterface {
out.write(bytes);
out.flush();
}
private void sendPacket(int packetId, int val) throws IOException {
out.writeByte(packetId);
out.writeShort(4);
out.writeInt(val);
out.flush();
}
private void sendPacket(int packetId, String str) throws IOException {
out.writeByte(packetId);
int payloadLength = str.length()+1;
int payloadLength = str.length() + 1;
out.writeShort(payloadLength);
out.write(str.getBytes());
out.writeByte('\0');
out.flush();
}
// No payload
private void sendPacket(int packetId) throws IOException {
out.writeByte(packetId);
......@@ -163,17 +163,17 @@ public class TCPClient implements CommunicationInterface {
private Packet getPacket() throws IOException {
int id = din.readByte();
int length = din.readShort();
//byte[] data = din.readNBytes(length);
// byte[] data = din.readNBytes(length);
// Apparently readNBytes() is only in new versions => Emulate
byte[] data = new byte[length];
for (int i = 0; i < length; ++i) {
data[i] = din.readByte();
}
//System.out.println("Received packet: id="+id + ", length="+length+", bytes="+new String(data));
//System.out.println("Received packet: id="+id + ", length="+length);
// System.out.println("Received packet: id="+id + ", length="+length+",
// bytes="+new String(data));
// System.out.println("Received packet: id="+id + ", length="+length);
return new Packet(id, data);
}
@Override
public boolean isAlive() {
......@@ -187,7 +187,7 @@ public class TCPClient implements CommunicationInterface {
int i = 0;
for (PortInformation port : interf.ports) {
if (port.direction == PortDirection.INPUT && portData[i] != null) {
//System.out.println("Sending INPUT for "+port.name +": "+portData[i]);
// System.out.println("Sending INPUT for "+port.name +": "+portData[i]);
ByteArrayOutputStream os = new ByteArrayOutputStream();
DataOutputStream os2 = new DataOutputStream(os);
port.type.toBinary(os2, portData[i]);
......@@ -196,37 +196,40 @@ public class TCPClient implements CommunicationInterface {
++i;
}
// Request execution
//System.out.println("Sending RUN_CYCLE");
// System.out.println("Sending RUN_CYCLE");
out.writeByte(PACKET_RUN_CYCLE);
out.writeShort(8);
out.writeDouble(deltaSec);
out.flush();
// Receive outputs & exec time
//System.out.println("Waiting for responses");
// System.out.println("Waiting for responses");
Packet p = getPacket();
while (true) {
switch (p.id) {
case PACKET_ERROR:
throw new IllegalStateException("Error on VCG: "+new String(p.data));
throw new IllegalStateException("Error on VCG: " + new String(p.data));
case PACKET_TIME:
return Time.durationFromSeconds(new DataInputStream(new ByteArrayInputStream(p.data)).readDouble());
case PACKET_OUTPUT:
DataInputStream is = new DataInputStream(new ByteArrayInputStream(p.data));
int portId = is.readShort();
PortInformation port = interf.ports.elementAt(portId);
if (port.direction != PortDirection.OUTPUT) throw new IllegalArgumentException("Received output packet for port "+ port.name + " (but it is an INPUT port)");
if (port.direction != PortDirection.OUTPUT)
throw new IllegalArgumentException(
"Received output packet for port " + port.name + " (but it is an INPUT port)");
portData[portId] = port.type.fromBinary(is);
break;
break;
default:
throw new IllegalArgumentException("Unexpected packet with id="+p.id);
throw new IllegalArgumentException("Unexpected packet with id=" + p.id);
}
p = getPacket();
}
}
@Override
protected void finalize() throws Throwable {
if (cs != null) cs.close();
if (cs != null)
cs.close();
}
static class Packet {
......@@ -238,4 +241,15 @@ public class TCPClient implements CommunicationInterface {
this.data = data;
}
}
@Override
public void close() {
try {
sendPacket(PACKET_END);
if (cs != null) cs.close();
cs = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
......@@ -6,12 +6,17 @@ package de.rwth.montisim.hardware_emulator.vcg;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import de.rwth.montisim.commons.dynamicinterface.*;
import de.rwth.montisim.commons.dynamicinterface.PortInformation.PortDirection;
import de.rwth.montisim.commons.eventsimulation.DiscreteEvent;
import de.rwth.montisim.commons.eventsimulation.exceptions.UnexpectedEventException;
import de.rwth.montisim.commons.simulation.Destroyable;
import de.rwth.montisim.commons.simulation.Destroyer;
import de.rwth.montisim.commons.simulation.Inspectable;
import de.rwth.montisim.commons.utils.Time;
import de.rwth.montisim.commons.utils.json.*;
import de.rwth.montisim.hardware_emulator.vcg.VCGProperties.*;
......@@ -23,7 +28,7 @@ import de.rwth.montisim.simulation.eesimulator.message.*;
/**
* Assumes DDC communication ("DDC interface")
*/
public class VCG extends EEComponent {
public class VCG extends EEComponent implements Inspectable, Destroyable {
// To generate the "basic interface" string
public static void main(String[] args) throws Exception {
......@@ -66,7 +71,7 @@ public class VCG extends EEComponent {
Object buffer[]; // Buffer for incoming inputs / Last output values
//Object currentValues[]; // Buffer the state of the Program Ports
public VCG(VCGProperties properties) throws Exception {
public VCG(VCGProperties properties, Destroyer destroyer) throws Exception {
super(properties);
this.properties = properties;
......@@ -83,6 +88,7 @@ public class VCG extends EEComponent {
//currentValues = new Object[program.ports.size()];
if (properties.time == TimeMode.REALTIME) throw new IllegalArgumentException("Unimplemented: TimeMode.REALTIME");
destroyer.addDestroyable(this);
}
@Override
......@@ -130,10 +136,11 @@ public class VCG extends EEComponent {
}
if (properties.time == TimeMode.MEASURED) {
//System.out.println("VCG received MsgEvent: " + msg.msgInfo.name + " Payload: "+msg.message);
buffer[i] = msg.message;
} else if (properties.time == TimeMode.REALTIME) {
// TODO directly send input ? or scheduled task ?
throw new IllegalStateException("Unimplemented");
throw new IllegalStateException("REALTIME TimeMode is Unimplemented");
}
}
......@@ -157,6 +164,7 @@ public class VCG extends EEComponent {
for (PortInformation port : program.ports) {
if (port.direction == PortDirection.OUTPUT) {
if (buffer[i] != null) {
//System.out.println("VCG sending MsgEvent: " + msgInfos[i].name + " Payload: "+buffer[i]);
sendMessage(sendTime, msgInfos[i], buffer[i]);
}
}
......@@ -177,4 +185,44 @@ public class VCG extends EEComponent {
// Set "simulation running" to false
}
@Override
public String getType() {
return "autopilot";
}
@Override
public String getName() {
return properties.name;
}
@Override
public List<String> getEntries() {
List<String> entries = new ArrayList<>();
int i = 0;
for (PortInformation p : program.ports) {
String res = p.direction == PortDirection.INPUT ? "input: " : "output: ";
res += p.name + ": ";
Object val = buffer[i];
if (val == null) entries.add(res + "null");
else {
List<String> toStr = p.type.toString(val);
if (toStr.size() == 0) entries.add(res + "No toString()");
if (toStr.size() == 1) entries.add(res + toStr.get(0));
else {
entries.add(res);
for (String s : toStr) {
entries.add(" "+s);
}
}
}
++i;
}
return entries;
}
@Override
public void destroy() {
comm.close();
}
}
\ No newline at end of file
......@@ -53,7 +53,7 @@ public class VCGProperties extends BusUserProperties {
@Override
public EEEventProcessor build(ComponentBuildContext context) {
try {
return new VCG(this);
return new VCG(this, context.componentDestroyer);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException("Could not build VCG component.");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment