package org.opentrafficsim.demo; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; import java.util.stream.Collectors; import org.djutils.io.URLResource; import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf; import com.google.protobuf.CodedOutputStream; /** * Test client for AimsunController. *

* Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version Apr 18, 2017
* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel */ public final class TestController { /** * Cannot be instantiated. */ private TestController() { // Do not instantiate. } /** * Test client for AimsunControl. *

* (c) copyright 2002-2018 Delft University of Technology.
* BSD-style license. See DSOL License.
* @author Alexander Verbraeck * @version Oct 21, 2016 */ /** * @param args String[]; command line arguments * @throws IOException when communication fails */ public static void main(final String[] args) throws IOException { String ip = null; Integer port = null; for (String arg : args) { int equalsPos = arg.indexOf("="); if (equalsPos < 0) { System.err.println("Unhandled argument \"" + arg + "\""); } String key = arg.substring(0, equalsPos); String value = arg.substring(equalsPos + 1); switch (key.toUpperCase()) { case "IP": ip = value; break; case "PORT": try { port = Integer.parseInt(value); } catch (NumberFormatException exception) { System.err.println("Bad port number \"" + value + "\""); System.exit(1); } break; default: System.err.println("Unhandled argument \"" + arg + "\""); } } if (null == ip || null == port) { System.err.println("Missing required argument(s) ip= port="); System.exit(1); } // Construct the create simulation command (including the network description in XML AimsunControlProtoBuf.CreateSimulation.Builder createSimulationBuilder = AimsunControlProtoBuf.CreateSimulation.newBuilder(); // createSimulationBuilder.setRunTime(3600d); // createSimulationBuilder.setWarmUpTime(0d); // String network = URLResource.getResource("/aimsun/singleRoad.xml").toString(); // wrong; fix later // String networkResource = "/aimsun/singleRoad.xml"; String networkResource = "C:/Temp/AimsunOtsNetwork.xml"; String network = null; // IOUtils.toString(URLResource.getResource(networkResource)); URL networkURL = URLResource.getResource(networkResource); if (null == networkURL) { throw new Error("Could not load network from resource " + networkResource); } URLConnection conn = networkURL.openConnection(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { network = reader.lines().collect(Collectors.joining("\n")); } // Socket to talk to server System.out.println("Connecting to server..."); Socket socket = new Socket(ip, port); System.out.println("Connected"); OutputStream outputStream = socket.getOutputStream(); InputStream inputStream = socket.getInputStream(); // Send a create simulation command createSimulationBuilder.setNetworkXML(network); System.out.println("Sending CREATESIMULATION message"); sendProtoMessage(outputStream, AimsunControlProtoBuf.OTSMessage.newBuilder().setCreateSimulation(createSimulationBuilder.build()).build()); // Simulate 3600 seconds in 1 second steps for (int step = 1; step <= 3600; step++) { AimsunControlProtoBuf.SimulateUntil simulateUntil = AimsunControlProtoBuf.SimulateUntil.newBuilder().setTime(1d * step).build(); System.out.println("Sending simulate up to step " + step + " command"); sendProtoMessage(outputStream, AimsunControlProtoBuf.OTSMessage.newBuilder().setSimulateUntil(simulateUntil).build()); System.out.println("Receive reply"); AimsunControlProtoBuf.OTSMessage reply = receiveProtoMessage(inputStream); // System.out.println("Received " + reply); if (!reply.getGtuPositions().getStatus().contains("OK")) { System.out.println("status is " + reply.getGtuPositions().getStatus()); break; } } System.out.println("Simulation stopped. Press return to exit"); System.in.read(); socket.close(); } /** * Transit one message to the OTS server. * @param outputStream OutputStream; output stream to the OTS server * @param message AimsunControlProtoBuf.OTSMessage; the message * @throws IOException when communication fails in any way */ public static void sendProtoMessage(final OutputStream outputStream, final AimsunControlProtoBuf.OTSMessage message) throws IOException { int size = message.getSerializedSize(); // System.out.println("About to transmit message of " + size + " bytes"); byte[] sizeBytes = new byte[4]; sizeBytes[0] = (byte) ((size >> 24) & 0xff); sizeBytes[1] = (byte) ((size >> 16) & 0xff); sizeBytes[2] = (byte) ((size >> 8) & 0xff); sizeBytes[3] = (byte) (size & 0xff); outputStream.write(sizeBytes); ByteArrayOutputStream baos = new ByteArrayOutputStream(); message.writeTo(CodedOutputStream.newInstance(baos)); byte[] buffer = new byte[size]; buffer = message.toByteArray(); outputStream.write(buffer); // System.out.println("Done"); } /** * Read one OTSMessage. * @param inputStream InputStream; input stream to read from * @return OTSMessage; the OTSMessage that was constructed from the read bytes * @throws IOException when communication fails */ public static AimsunControlProtoBuf.OTSMessage receiveProtoMessage(final InputStream inputStream) throws IOException { byte[] sizeBytes = receiveBytes(inputStream, 4); // for (int i = 0; i < 4; i++) // { // System.out.print(String.format("%d ", sizeBytes[i])); // } int size = ((sizeBytes[0] & 0xff) << 24) + ((sizeBytes[1] & 0xff) << 16) + ((sizeBytes[2] & 0xff) << 8) + (sizeBytes[3] & 0xff); // System.out.println(String.format("-> %d", size)); byte[] messageBytes = receiveBytes(inputStream, size); return AimsunControlProtoBuf.OTSMessage.parseFrom(messageBytes); } /** * Read a specified number of bytes. * @param inputStream InputStream; input stream to read from * @param size int; number of bytes to read * @return byte[]; byte array filled with the read bytes * @throws IOException when communication fails */ public static byte[] receiveBytes(final InputStream inputStream, final int size) throws IOException { System.out.print("Need to read " + size + " bytes ... "); int offset = 0; byte[] buffer = new byte[size]; while (true) { int bytesRead = inputStream.read(buffer, offset, buffer.length - offset); if (-1 == bytesRead) { break; } offset += bytesRead; if (buffer.length == offset) { System.out.println("Got all " + buffer.length + " requested bytes"); break; } if (buffer.length < offset) { System.out.println("Oops: Got more than " + buffer.length + " requested bytes"); break; } System.out.print("Now got " + offset + " bytes; need to read " + (buffer.length - offset) + " more bytes "); } if (offset != buffer.length) { throw new IOException("Got only " + offset + " of expected " + buffer.length + " bytes"); } return buffer; } }