1 package org.opentrafficsim.aimsun;
2
3 import java.awt.Dimension;
4 import java.io.ByteArrayInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8 import java.io.PrintWriter;
9 import java.net.ServerSocket;
10 import java.net.Socket;
11 import java.net.URISyntaxException;
12 import java.nio.charset.StandardCharsets;
13 import java.rmi.RemoteException;
14
15 import javax.naming.NamingException;
16 import javax.xml.bind.JAXBException;
17 import javax.xml.parsers.ParserConfigurationException;
18
19 import org.djunits.unit.DurationUnit;
20 import org.djunits.unit.TimeUnit;
21 import org.djunits.value.ValueException;
22 import org.djunits.value.vdouble.scalar.Duration;
23 import org.djunits.value.vdouble.scalar.Length;
24 import org.djunits.value.vdouble.scalar.Time;
25 import org.djutils.logger.LogCategory;
26 import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf;
27 import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf.GTUPositions;
28 import org.opentrafficsim.base.parameters.ParameterException;
29 import org.opentrafficsim.core.animation.gtu.colorer.DefaultSwitchableGTUColorer;
30 import org.opentrafficsim.core.dsol.AbstractOTSModel;
31 import org.opentrafficsim.core.dsol.OTSAnimator;
32 import org.opentrafficsim.core.dsol.OTSModelInterface;
33 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
34 import org.opentrafficsim.core.geometry.OTSGeometryException;
35 import org.opentrafficsim.core.gtu.GTU;
36 import org.opentrafficsim.core.gtu.GTUException;
37 import org.opentrafficsim.core.gtu.GTUType;
38 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
39 import org.opentrafficsim.core.network.NetworkException;
40 import org.opentrafficsim.core.network.OTSNetwork;
41 import org.opentrafficsim.draw.core.OTSDrawingException;
42 import org.opentrafficsim.draw.factory.DefaultAnimationFactory;
43 import org.opentrafficsim.road.network.OTSRoadNetwork;
44 import org.opentrafficsim.road.network.factory.xml.XmlParserException;
45 import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
46 import org.opentrafficsim.road.network.lane.conflict.ConflictBuilder;
47 import org.opentrafficsim.swing.gui.OTSAnimationPanel;
48 import org.opentrafficsim.swing.gui.OTSSimulationApplication;
49 import org.opentrafficsim.swing.gui.OTSSwingApplication;
50 import org.pmw.tinylog.Level;
51 import org.xml.sax.SAXException;
52
53 import nl.tudelft.simulation.dsol.SimRuntimeException;
54 import nl.tudelft.simulation.dsol.logger.SimLogger;
55 import nl.tudelft.simulation.dsol.simulators.DEVSRealTimeClock;
56 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
57 import nl.tudelft.simulation.event.EventInterface;
58 import nl.tudelft.simulation.event.EventListenerInterface;
59 import nl.tudelft.simulation.language.d3.DirectedPoint;
60
61
62
63
64
65
66
67
68
69
70
71 public class AimsunControl
72 {
73
74 private AimsunModel model = null;
75
76
77
78
79
80
81
82
83
84
85
86 public static void main(final String[] args) throws NetworkException, OTSGeometryException, NamingException, ValueException,
87 ParameterException, SimRuntimeException
88 {
89 SimLogger.setAllLogLevel(Level.WARNING);
90 SimLogger.setLogCategories(LogCategory.ALL);
91
92 String ip = null;
93 Integer port = null;
94
95 for (String arg : args)
96 {
97 int equalsPos = arg.indexOf("=");
98 if (equalsPos < 0)
99 {
100 System.err.println("Unhandled argument \"" + arg + "\"");
101 }
102 String key = arg.substring(0, equalsPos);
103 String value = arg.substring(equalsPos + 1);
104 switch (key.toUpperCase())
105 {
106 case "IP":
107 ip = value;
108 break;
109 case "PORT":
110 try
111 {
112 port = Integer.parseInt(value);
113 }
114 catch (NumberFormatException exception)
115 {
116 System.err.println("Bad port number \"" + value + "\"");
117 System.exit(1);
118 }
119 break;
120 default:
121 System.err.println("Unhandled argument \"" + arg + "\"");
122 }
123 }
124 if (null == ip || null == port)
125 {
126 System.err.println("Missing required argument(s) ip=<ip-number_or_hostname> port=<port-number>");
127 System.exit(1);
128 }
129 try
130 {
131 System.out.println("Creating server socket for port " + port);
132 ServerSocket serverSocket = new ServerSocket(port);
133 serverSocket.setReuseAddress(true);
134 System.out.println("Waiting for client to connect");
135 Socket clientSocket = serverSocket.accept();
136 System.out.println("Client connected; closing server socket");
137 serverSocket.close();
138 System.out.println("Socket time out is " + clientSocket.getSoTimeout());
139 clientSocket.setSoTimeout(0);
140 System.out.println("Constructing animation/simulation");
141 AimsunControl aimsunControl = new AimsunControl();
142 aimsunControl.commandLoop(clientSocket);
143 }
144 catch (IOException exception)
145 {
146 exception.printStackTrace();
147 }
148 System.exit(0);
149 }
150
151
152 private Time simulateUntil = null;
153
154
155
156
157
158
159 protected void sendGTUPositionsToAimsun(final OutputStream outputStream)
160 {
161 OTSSimulatorInterface simulator = this.model.getSimulator();
162 System.out.println("Simulator has stopped at time " + simulator.getSimulatorTime());
163 Time stopTime = simulator.getSimulatorTime();
164 AimsunControlProtoBuf.GTUPositions.Builder builder = AimsunControlProtoBuf.GTUPositions.newBuilder();
165 for (GTU gtu : this.model.getNetwork().getGTUs())
166 {
167 AimsunControlProtoBuf.GTUPositions.GTUPosition.Builder gpb =
168 AimsunControlProtoBuf.GTUPositions.GTUPosition.newBuilder();
169 gpb.setGtuId(gtu.getId());
170 DirectedPoint dp;
171 try
172 {
173 dp = gtu.getOperationalPlan().getLocation(stopTime);
174 gpb.setX(dp.x);
175 gpb.setY(dp.y);
176 gpb.setZ(dp.z);
177 gpb.setAngle(dp.getRotZ());
178 gpb.setLength(gtu.getLength().si);
179 gpb.setWidth(gtu.getWidth().si);
180 gpb.setGtuTypeId(Integer.parseInt(gtu.getGTUType().getId().split("\\.")[1]));
181 gpb.setSpeed(gtu.getSpeed().si);
182 builder.addGtuPos(gpb.build());
183 }
184 catch (OperationalPlanException exception)
185 {
186 exception.printStackTrace();
187 }
188 }
189 builder.setStatus("OK");
190 GTUPositions gtuPositions = builder.build();
191 AimsunControlProtoBuf.OTSMessage.Builder resultBuilder = AimsunControlProtoBuf.OTSMessage.newBuilder();
192 resultBuilder.setGtuPositions(gtuPositions);
193 AimsunControlProtoBuf.OTSMessage result = resultBuilder.build();
194 this.simulateUntil = null;
195 try
196 {
197 transmitMessage(result, outputStream);
198 }
199 catch (IOException exception)
200 {
201 exception.printStackTrace();
202 }
203 System.out.println("Simulator waiting for new simulateUntil value");
204 while (this.simulateUntil == null)
205 {
206 try
207 {
208 Thread.sleep(1);
209 }
210 catch (InterruptedException exception)
211 {
212
213 }
214 }
215 try
216 {
217 simulator.scheduleEventAbs(this.simulateUntil, this, this, "sendGTUPositionsToAimsun",
218 new Object[] { outputStream });
219 }
220 catch (SimRuntimeException exception)
221 {
222 exception.printStackTrace();
223 }
224 System.out.println("Simulator resuming");
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238 private void commandLoop(final Socket socket) throws IOException, NetworkException, OTSGeometryException, NamingException,
239 ValueException, ParameterException, SimRuntimeException
240 {
241 System.out.println("Entering command loop");
242 InputStream inputStream = socket.getInputStream();
243 OutputStream outputStream = socket.getOutputStream();
244 String error = null;
245 boolean simulatorStarted = false;
246 while (null == error)
247 {
248 try
249 {
250 byte[] sizeBytes = new byte[4];
251 fillBuffer(inputStream, sizeBytes);
252 int size = ((sizeBytes[0] & 0xff) << 24) + ((sizeBytes[1] & 0xff) << 16) + ((sizeBytes[2] & 0xff) << 8)
253 + (sizeBytes[3] & 0xff);
254 System.out.println("expecting message of " + size + " bytes");
255 byte[] buffer = new byte[size];
256 fillBuffer(inputStream, buffer);
257 AimsunControlProtoBuf.OTSMessage message = AimsunControlProtoBuf.OTSMessage.parseFrom(buffer);
258
259 if (null == message)
260 {
261 System.out.println("Connection terminated; exiting");
262 break;
263 }
264 switch (message.getMsgCase())
265 {
266 case CREATESIMULATION:
267 System.out.println("Received CREATESIMULATION message");
268 AimsunControlProtoBuf.CreateSimulation createSimulation = message.getCreateSimulation();
269 String networkXML = createSimulation.getNetworkXML();
270 try (PrintWriter pw = new PrintWriter("c:/Temp/AimsunOtsNetwork.xml"))
271 {
272 pw.print(networkXML);
273 }
274 Duration runDuration = new Duration(3600, DurationUnit.SECOND);
275 System.out.println("runDuration " + runDuration);
276 Duration warmupDuration = new Duration(0, DurationUnit.SECOND);
277 try
278 {
279 OTSAnimator animator = new OTSAnimator();
280 this.model = new AimsunModel(animator, "Aimsun generated model", "Aimsun model", networkXML);
281 animator.initialize(Time.ZERO, warmupDuration, runDuration, this.model);
282 OTSAnimationPanel animationPanel =
283 new OTSAnimationPanel(this.model.getNetwork().getExtent(), new Dimension(800, 600),
284 animator, this.model, OTSSwingApplication.DEFAULT_COLORER, this.model.getNetwork());
285 DefaultAnimationFactory.animateXmlNetwork(this.model.getNetwork(), animator,
286 new DefaultSwitchableGTUColorer());
287 new AimsunSwingApplication(this.model, animationPanel);
288 animator.setSpeedFactor(Double.MAX_VALUE, true);
289 animator.setSpeedFactor(1000.0, true);
290 }
291 catch (SimRuntimeException | NamingException | OTSDrawingException exception1)
292 {
293 exception1.printStackTrace();
294
295 error = "XML ERROR";
296 }
297 break;
298
299 case SIMULATEUNTIL:
300 {
301 System.out.println("Received SIMULATEUNTIL message");
302 AimsunControlProtoBuf.SimulateUntil simulateUntilThing = message.getSimulateUntil();
303 Time stopTime = new Time(simulateUntilThing.getTime(), TimeUnit.BASE_SECOND);
304 System.out.println("Simulate until " + stopTime + " ");
305 OTSSimulatorInterface simulator = this.model.getSimulator();
306 if (!simulatorStarted)
307 {
308 simulatorStarted = true;
309 simulator.scheduleEventAbs(stopTime, this, this, "sendGTUPositionsToAimsun",
310 new Object[] { outputStream });
311 System.out.println("Starting simulator");
312 this.simulateUntil = stopTime;
313 simulator.start();
314 }
315 else if (!simulator.isRunning())
316 {
317
318 error = "HMM Simulator stopped";
319 }
320 else
321 {
322 System.out.println("Resuming simulator");
323 this.simulateUntil = stopTime;
324 }
325 break;
326 }
327
328 case GTUPOSITIONS:
329 System.out.println("Received GTUPOSITIONS message SHOULD NOT HAPPEN");
330 socket.close();
331 return;
332
333 case MSG_NOT_SET:
334 System.out.println("Received MSG_NOT_SET message SHOULD NOT HAPPEN");
335 socket.close();
336 return;
337
338 default:
339 System.out.println("Received unknown message SHOULD NOT HAPPEN");
340 socket.close();
341 break;
342 }
343 }
344 catch (IOException exception)
345 {
346 exception.printStackTrace();
347 break;
348 }
349 }
350 }
351
352
353
354
355
356
357
358 private void transmitMessage(final AimsunControlProtoBuf.OTSMessage message, final OutputStream outputStream)
359 throws IOException
360 {
361 int size = message.getSerializedSize();
362 System.out.print("Transmitting " + message.getGtuPositions().getGtuPosCount() + " GTU positions and status \""
363 + message.getGtuPositions().getStatus() + "\" encoded in " + size + " bytes ... ");
364 byte[] sizeBytes = new byte[4];
365 sizeBytes[0] = (byte) ((size >> 24) & 0xff);
366 sizeBytes[1] = (byte) ((size >> 16) & 0xff);
367 sizeBytes[2] = (byte) ((size >> 8) & 0xff);
368 sizeBytes[3] = (byte) (size & 0xff);
369 outputStream.write(sizeBytes);
370 byte[] buffer = new byte[size];
371 buffer = message.toByteArray();
372 outputStream.write(buffer);
373 System.out.println("Message sent");
374 }
375
376
377
378
379
380
381
382 static void fillBuffer(final InputStream in, final byte[] buffer) throws IOException
383 {
384 System.out.print("Need to read " + buffer.length + " bytes ... ");
385 int offset = 0;
386 while (true)
387 {
388 int bytesRead = in.read(buffer, offset, buffer.length - offset);
389 if (-1 == bytesRead)
390 {
391 break;
392 }
393 offset += bytesRead;
394 if (buffer.length == offset)
395 {
396 System.out.println("got all " + buffer.length + " requested bytes");
397 break;
398 }
399 if (buffer.length < offset)
400 {
401 System.out.println("Oops: Got more than " + buffer.length + " requested bytes");
402 break;
403 }
404 System.out.print("now got " + offset + " bytes; need to read " + (buffer.length - offset) + " more bytes ... ");
405 }
406 if (offset != buffer.length)
407 {
408 throw new IOException("Got only " + offset + " of expected " + buffer.length + " bytes");
409 }
410 }
411
412
413
414
415 class AimsunSwingApplication extends OTSSimulationApplication<OTSModelInterface>
416 {
417
418 private static final long serialVersionUID = 1L;
419
420
421
422
423
424
425 public AimsunSwingApplication(final OTSModelInterface model, final OTSAnimationPanel panel) throws OTSDrawingException
426 {
427 super(model, panel);
428 }
429 }
430
431
432
433
434 class AimsunModel extends AbstractOTSModel implements EventListenerInterface
435 {
436
437 private static final long serialVersionUID = 20170419L;
438
439
440 private OTSRoadNetwork network;
441
442
443 private final String xml;
444
445
446
447
448
449
450
451 public AimsunModel(OTSSimulatorInterface simulator, String shortName, String description, final String xml)
452 {
453 super(simulator, shortName, description);
454 this.xml = xml;
455 }
456
457
458 @Override
459 public void notify(EventInterface event) throws RemoteException
460 {
461 System.out.println("Received event " + event);
462 }
463
464
465 @Override
466 public void constructModel() throws SimRuntimeException
467 {
468 try
469 {
470 this.simulator.addListener(this, DEVSRealTimeClock.CHANGE_SPEED_FACTOR_EVENT);
471 this.simulator.addListener(this, SimulatorInterface.TIME_CHANGED_EVENT);
472 }
473 catch (RemoteException exception1)
474 {
475 exception1.printStackTrace();
476 }
477 this.network = new OTSRoadNetwork(getShortName(), true);
478 try
479 {
480 XmlNetworkLaneParser.build(new ByteArrayInputStream(this.xml.getBytes(StandardCharsets.UTF_8)),
481 this.network, getSimulator());
482 ConflictBuilder.buildConflicts(this.network, this.network.getGtuType(GTUType.DEFAULTS.VEHICLE), getSimulator(),
483 new ConflictBuilder.FixedWidthGenerator(Length.createSI(2.0)));
484 }
485 catch (NetworkException | OTSGeometryException | JAXBException | URISyntaxException | XmlParserException
486 | SAXException | ParserConfigurationException | GTUException exception)
487 {
488 exception.printStackTrace();
489
490
491 throw new SimRuntimeException(exception);
492 }
493 }
494
495
496 @Override
497 public OTSNetwork getNetwork()
498 {
499 return this.network;
500 }
501
502 }
503
504 }