1 package org.opentrafficsim.aimsun;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.net.ServerSocket;
8 import java.net.Socket;
9 import java.nio.charset.StandardCharsets;
10 import java.rmi.RemoteException;
11 import java.util.ArrayList;
12
13 import javax.naming.NamingException;
14
15 import org.djunits.unit.DurationUnit;
16 import org.djunits.unit.TimeUnit;
17 import org.djunits.value.vdouble.scalar.Duration;
18 import org.djunits.value.vdouble.scalar.Time;
19 import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf;
20 import org.opentrafficsim.base.modelproperties.Property;
21 import org.opentrafficsim.base.modelproperties.PropertyException;
22 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
23 import org.opentrafficsim.core.dsol.OTSModelInterface;
24 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
25 import org.opentrafficsim.core.gtu.GTU;
26 import org.opentrafficsim.core.gtu.animation.GTUColorer;
27 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
28 import org.opentrafficsim.core.network.OTSNetwork;
29 import org.opentrafficsim.road.network.factory.xml.XmlNetworkLaneParser;
30 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
31 import org.opentrafficsim.simulationengine.OTSSimulationException;
32 import org.opentrafficsim.simulationengine.SimpleAnimator;
33
34 import nl.tudelft.simulation.dsol.SimRuntimeException;
35 import nl.tudelft.simulation.dsol.simulators.DEVSSimulator;
36 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
37 import nl.tudelft.simulation.event.EventInterface;
38 import nl.tudelft.simulation.event.EventListenerInterface;
39 import nl.tudelft.simulation.event.EventProducer;
40 import nl.tudelft.simulation.language.d3.DirectedPoint;
41
42
43
44
45
46
47
48
49
50
51
52 public class AimsunControl extends AbstractWrappableAnimation
53 {
54
55
56 private static final long serialVersionUID = 20160418L;
57
58
59 private String networkXML = null;
60
61
62 private AimsunModel model = null;
63
64
65
66
67
68 public static void main(final String[] args)
69 {
70 String ip = null;
71 Integer port = null;
72
73 for (String arg : args)
74 {
75 int equalsPos = arg.indexOf("=");
76 if (equalsPos < 0)
77 {
78 System.err.println("Unhandled argument \"" + arg + "\"");
79 }
80 String key = arg.substring(0, equalsPos);
81 String value = arg.substring(equalsPos + 1);
82 switch (key.toUpperCase())
83 {
84 case "IP":
85 ip = value;
86 break;
87 case "PORT":
88 try
89 {
90 port = Integer.parseInt(value);
91 }
92 catch (NumberFormatException exception)
93 {
94 System.err.println("Bad port number \"" + value + "\"");
95 System.exit(1);
96 }
97 break;
98 default:
99 System.err.println("Unhandled argument \"" + arg + "\"");
100 }
101 }
102 if (null == ip || null == port)
103 {
104 System.err.println("Missing required argument(s) ip=<ip-number_or_hostname> port=<port-number>");
105 System.exit(1);
106 }
107 try
108 {
109 System.out.println("Creating server socket for port " + port);
110 ServerSocket serverSocket = new ServerSocket(port);
111 serverSocket.setReuseAddress(true);
112 System.out.println("Waiting for client to connect");
113 Socket clientSocket = serverSocket.accept();
114 System.out.println("Client connected; closing server socket");
115 serverSocket.close();
116 System.out.println("Socket time out is " + clientSocket.getSoTimeout());
117 clientSocket.setSoTimeout(0);
118 System.out.println("Entering command loop");
119 AimsunControl aimsunControl = new AimsunControl();
120 aimsunControl.commandLoop(clientSocket);
121 }
122 catch (IOException exception)
123 {
124 exception.printStackTrace();
125 }
126 System.exit(0);
127 }
128
129
130
131
132
133
134 public static String hexDump(final byte[] bytes)
135 {
136 StringBuilder result = new StringBuilder();
137 int pos = 0;
138 for (byte b : bytes)
139 {
140 result.append(String.format("%02x", b));
141 if (pos % 16 == 0)
142 {
143 result.append("\r\n");
144 }
145 else if (pos % 8 == 0)
146 {
147 result.append(" ");
148 }
149 else
150 {
151 result.append(" ");
152 }
153 }
154 return result.toString();
155 }
156
157
158
159
160
161
162 private void commandLoop(final Socket socket) throws IOException
163 {
164 InputStream inputStream = socket.getInputStream();
165 OutputStream outputStream = socket.getOutputStream();
166 while (true)
167 {
168
169
170
171 try
172 {
173 byte[] sizeBytes = new byte[4];
174
175 fillBuffer(inputStream, sizeBytes);
176 int size =
177 ((sizeBytes[0] & 0xff) << 24) + ((sizeBytes[1] & 0xff) << 16) + ((sizeBytes[2] & 0xff) << 8)
178 + (sizeBytes[3] & 0xff);
179 System.out.println("expecting " + size + " bytes");
180 byte[] buffer = new byte[size];
181
182 fillBuffer(inputStream, buffer);
183 AimsunControlProtoBuf.OTSMessage message = AimsunControlProtoBuf.OTSMessage.parseFrom(buffer);
184
185
186 if (null == message)
187 {
188 System.out.println("Connection terminated; exiting");
189 break;
190 }
191 switch (message.getMsgCase())
192 {
193 case CREATESIMULATION:
194 System.out.println("Received CREATESIMULATION message");
195 AimsunControlProtoBuf.CreateSimulation createSimulation = message.getCreateSimulation();
196 this.networkXML = createSimulation.getNetworkXML();
197
198
199
200
201
202
203
204
205 Duration runDuration = new Duration(createSimulation.getRunTime(), DurationUnit.SECOND);
206 Duration warmupDuration = new Duration(createSimulation.getWarmUpTime(), DurationUnit.SECOND);
207 try
208 {
209 SimpleAnimator animator =
210 buildAnimator(Time.ZERO, warmupDuration, runDuration, new ArrayList<Property<?>>(), null,
211 true);
212 animator.setSpeedFactor(Double.MAX_VALUE, true);
213 }
214 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception1)
215 {
216 exception1.printStackTrace();
217 }
218 break;
219
220 case SIMULATEUNTIL:
221 System.out.println("Received SIMULATEUNTIL message");
222 if (null == this.model)
223 {
224 System.err.println("No model active");
225 socket.close();
226 break;
227 }
228 AimsunControlProtoBuf.SimulateUntil simulateUntil = message.getSimulateUntil();
229 Time stopTime = new Time(simulateUntil.getTime(), TimeUnit.BASE_SECOND);
230 System.out.println("Simulate until " + stopTime);
231 DEVSSimulator<Time, ?, ?> simulator = (DEVSSimulator<Time, ?, ?>) this.model.getSimulator();
232 try
233 {
234 simulator.runUpTo(stopTime);
235 while (simulator.isRunning())
236 {
237 try
238 {
239 Thread.sleep(10);
240 }
241 catch (InterruptedException ie)
242 {
243 ie = null;
244 }
245 }
246 AimsunControlProtoBuf.GTUPositions.Builder builder =
247 AimsunControlProtoBuf.GTUPositions.newBuilder();
248 for (GTU gtu : this.model.getNetwork().getGTUs())
249 {
250 AimsunControlProtoBuf.GTUPositions.GTUPosition.Builder gpb =
251 AimsunControlProtoBuf.GTUPositions.GTUPosition.newBuilder();
252 gpb.setGtuId(gtu.getId());
253 DirectedPoint dp = gtu.getOperationalPlan().getLocation(stopTime);
254 gpb.setX(dp.x);
255 gpb.setY(dp.y);
256 gpb.setZ(dp.z);
257 gpb.setAngle(dp.getRotZ());
258 builder.addGtuPos(gpb.build());
259 }
260 AimsunControlProtoBuf.GTUPositions gtuPositions = builder.build();
261 AimsunControlProtoBuf.OTSMessage.Builder resultBuilder =
262 AimsunControlProtoBuf.OTSMessage.newBuilder();
263 resultBuilder.setGtuPositions(gtuPositions);
264 AimsunControlProtoBuf.OTSMessage result = resultBuilder.build();
265 System.out.println("About to transmit " + result.toString());
266 size = result.getSerializedSize();
267 sizeBytes[0] = (byte) ((size >> 24) & 0xff);
268 sizeBytes[1] = (byte) ((size >> 16) & 0xff);
269 sizeBytes[2] = (byte) ((size >> 8) & 0xff);
270 sizeBytes[3] = (byte) (size & 0xff);
271 outputStream.write(sizeBytes);
272 buffer = new byte[size];
273 buffer = result.toByteArray();
274 outputStream.write(buffer);
275
276 }
277 catch (SimRuntimeException | OperationalPlanException exception)
278 {
279 System.out.println("Error in runUpTo");
280 exception.printStackTrace();
281 }
282 break;
283
284 case GTUPOSITIONS:
285 System.out.println("Received GTUPOSITIONS message SHOULD NOT HAPPEN");
286 socket.close();
287 return;
288
289 case MSG_NOT_SET:
290 System.out.println("Received MSG_NOT_SET message SHOULD NOT HAPPEN");
291 socket.close();
292 return;
293
294 default:
295 System.out.println("Received unknown message SHOULD NOT HAPPEN");
296 socket.close();
297 break;
298 }
299 }
300 catch (IOException exception)
301 {
302 exception.printStackTrace();
303 break;
304 }
305 }
306 }
307
308
309
310
311
312
313 static void fillBuffer(final InputStream in, final byte[] buffer)
314 {
315 System.out.println("Need to read " + buffer.length + " bytes");
316 int offset = 0;
317 while (true)
318 {
319 try
320 {
321 int bytesRead = in.read(buffer, offset, buffer.length - offset);
322 if (-1 == bytesRead)
323 {
324 break;
325 }
326 offset += bytesRead;
327 if (offset >= buffer.length)
328 {
329 System.out.println("Got all " + buffer.length + " requested bytes");
330 break;
331 }
332 System.out.println("Now got " + offset + " bytes; need to read " + (buffer.length - offset) + " more bytes");
333 }
334 catch (Exception exception)
335 {
336 exception.printStackTrace();
337 }
338 }
339 }
340
341
342 @Override
343 public final String shortName()
344 {
345 return "AimsunControlledOTS";
346 }
347
348
349 @Override
350 public final String description()
351 {
352 return "Aimsun controlled OTS engine";
353 }
354
355
356 @Override
357 protected final OTSModelInterface makeModel(final GTUColorer colorer) throws OTSSimulationException
358 {
359 this.model = new AimsunModel();
360 return this.model;
361 }
362
363
364
365
366 class AimsunModel extends EventProducer implements OTSModelInterface, EventListenerInterface
367 {
368
369
370 private static final long serialVersionUID = 20170419L;
371
372
373 private OTSNetwork network;
374
375
376 private SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator;
377
378
379 @Override
380 public void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
381 throws SimRuntimeException, RemoteException
382 {
383 try
384 {
385 this.simulator = theSimulator;
386
387 XmlNetworkLaneParser nlp = new XmlNetworkLaneParser((OTSDEVSSimulatorInterface) theSimulator);
388 String xml = AimsunControl.this.networkXML;
389 this.network = nlp.build(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
390 }
391 catch (Exception exception)
392 {
393 exception.printStackTrace();
394 }
395 }
396
397
398 @Override
399 public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
400 {
401 return this.simulator;
402 }
403
404
405 @Override
406 public void notify(final EventInterface event) throws RemoteException
407 {
408
409 }
410
411
412 @Override
413 public OTSNetwork getNetwork()
414 {
415 return this.network;
416 }
417
418 }
419
420 }