package org.opentrafficsim.remotecontrol; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; import java.awt.event.ActionEvent; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Serializable; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.rmi.RemoteException; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import javax.naming.NamingException; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.xml.bind.JAXBException; import javax.xml.parsers.ParserConfigurationException; import org.djunits.value.ValueRuntimeException; import org.djunits.value.vdouble.scalar.Duration; import org.djunits.value.vdouble.scalar.Length; import org.djunits.value.vdouble.scalar.Time; import org.djutils.cli.Checkable; import org.djutils.cli.CliUtil; import org.djutils.decoderdumper.HexDumper; import org.djutils.event.EventInterface; import org.djutils.event.EventListenerInterface; import org.djutils.event.EventTypeInterface; import org.djutils.immutablecollections.ImmutableMap; import org.djutils.logger.CategoryLogger; import org.djutils.logger.LogCategory; import org.djutils.serialization.SerializationException; import org.opentrafficsim.base.parameters.ParameterException; import org.opentrafficsim.core.animation.gtu.colorer.DefaultSwitchableGTUColorer; import org.opentrafficsim.core.dsol.AbstractOTSModel; import org.opentrafficsim.core.dsol.OTSAnimator; import org.opentrafficsim.core.dsol.OTSModelInterface; import org.opentrafficsim.core.dsol.OTSSimulatorInterface; import org.opentrafficsim.core.geometry.DirectedPoint; import org.opentrafficsim.core.geometry.OTSGeometryException; import org.opentrafficsim.core.gtu.GTU; import org.opentrafficsim.core.gtu.GTUException; import org.opentrafficsim.core.gtu.GTUType; import org.opentrafficsim.core.network.Network; import org.opentrafficsim.core.network.NetworkException; import org.opentrafficsim.core.network.OTSNetwork; import org.opentrafficsim.core.object.InvisibleObjectInterface; import org.opentrafficsim.draw.core.OTSDrawingException; import org.opentrafficsim.draw.factory.DefaultAnimationFactory; import org.opentrafficsim.road.network.OTSRoadNetwork; import org.opentrafficsim.road.network.factory.xml.XmlParserException; import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser; import org.opentrafficsim.road.network.lane.conflict.ConflictBuilder; import org.opentrafficsim.road.network.lane.conflict.LaneCombinationList; import org.opentrafficsim.swing.gui.OTSAnimationPanel; import org.opentrafficsim.swing.gui.OTSSimulationApplication; import org.opentrafficsim.swing.gui.OTSSwingApplication; import org.opentrafficsim.trafficcontrol.TrafficControlException; import org.opentrafficsim.trafficcontrol.TrafficController; import org.opentrafficsim.trafficcontrol.trafcod.TrafCOD; import org.pmw.tinylog.Level; import org.sim0mq.Sim0MQException; import org.sim0mq.message.Sim0MQMessage; import org.xml.sax.SAXException; import org.zeromq.SocketType; import org.zeromq.ZContext; import org.zeromq.ZMQ; import nl.tudelft.simulation.dsol.SimRuntimeException; import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface; import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit; import nl.tudelft.simulation.dsol.simulators.DEVSRealTimeAnimator; import nl.tudelft.simulation.dsol.simulators.SimulatorInterface; import nl.tudelft.simulation.dsol.swing.gui.TabbedContentPane; import nl.tudelft.simulation.jstats.streams.MersenneTwister; import nl.tudelft.simulation.jstats.streams.StreamInterface; import picocli.CommandLine.Command; import picocli.CommandLine.Option; /** * Sim0MQ controlled OTS *
* Copyright (c) 2013-2022 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 class Sim0MQControlledOTS implements EventListenerInterface
{
/** ... */
private static final long serialVersionUID = 20200317L;
/** Currently active model. */
private Sim0MQOTSModel model = null;
/** The ZContext of all the sockets. */
private final ZContext zContext;
/** The port number of the listening socket. */
private final int port;
/** Communication channel to the master. */
private final MasterCommunication masterCommunication = new MasterCommunication();
/**
* Construct a new Sim0MQ controlled OTS.
* @param zContext ZContext; the context of ZMQ
* @param port int; the port number of the listening socket
*/
public Sim0MQControlledOTS(final ZContext zContext, final int port)
{
this.zContext = zContext;
this.port = port;
this.masterCommunication.start();
}
/**
* Thread that handles ALL reads and writes on the socket to the master.
*/
class MasterCommunication extends Thread
{
@Override
public void run()
{
System.err.println("MasterCommunication thread id is " + Thread.currentThread().getId());
ZMQ.Socket remoteControllerSocket = Sim0MQControlledOTS.this.zContext.createSocket(SocketType.PAIR);
remoteControllerSocket.setHWM(100000);
remoteControllerSocket.bind("tcp://*:" + Sim0MQControlledOTS.this.port);
ZMQ.Socket resultQueue = Sim0MQControlledOTS.this.zContext.createSocket(SocketType.PULL);
resultQueue.bind("inproc://results");
ZMQ.Socket toCommandLoop = Sim0MQControlledOTS.this.zContext.createSocket(SocketType.PUSH);
toCommandLoop.setHWM(1000);
toCommandLoop.connect("inproc://commands");
/*-
while (!Thread.interrupted())
{
byte[] data;
data = remoteControllerSocket.recv(ZMQ.DONTWAIT);
if (null != data)
{
System.err.println("Got incoming command");
toCommandLoop.send(data, 0);
System.err.println("Incoming command handed over to toCommandLoop socket");
continue;
}
data = resultQueue.recv(ZMQ.DONTWAIT);
if (null != data)
{
System.err.println("Got outgoing result");
remoteControllerSocket.send(data, 0);
System.err.println("Outgoing result handed over to remoteControllerSocket");
}
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
//e.printStackTrace();
}
}
*/
///*-
ZMQ.Poller poller = Sim0MQControlledOTS.this.zContext.createPoller(2);
poller.register(remoteControllerSocket, ZMQ.Poller.POLLIN);
poller.register(resultQueue, ZMQ.Poller.POLLIN);
while (!Thread.currentThread().isInterrupted())
{
poller.poll();
if (poller.pollin(0))
{
System.err.println("Got incoming command");
byte[] data = remoteControllerSocket.recv();
toCommandLoop.send(data, 0);
System.err.println("Incoming command handed over to toCommandLoop socket");
}
else if (poller.pollin(1))
{
System.err.println("Got outgoing result");
byte[] data = resultQueue.recv();
remoteControllerSocket.send(data, 0);
System.err.println("Outgoing result handed over to remoteControllerSocket");
}
}
//*/
}
}
/**
* The command line options.
*/
@Command(description = "Sim0MQ Remotely Controlled OTS", name = "Sim0MQOTS", mixinStandardHelpOptions = true,
version = "1.0")
public static class Options implements Checkable
{
/** The IP port. */
@Option(names = { "-p", "--port" }, description = "Internet port to use", defaultValue = "8888")
private int port;
/**
* Retrieve the port.
* @return int; the port
*/
public final int getPort()
{
return this.port;
}
@Override
public final void check() throws Exception
{
if (this.port <= 0 || this.port > 65535)
{
throw new Exception("Port should be between 1 and 65535");
}
}
}
/**
* Program entry point.
* @param args String[]; the command line arguments
* @throws OTSGeometryException on error
* @throws NetworkException on error
* @throws NamingException on error
* @throws ValueRuntimeException on error
* @throws SimRuntimeException on error
* @throws ParameterException on error
* @throws SerializationException on error
* @throws Sim0MQException on error
* @throws IOException on error
*/
public static void main(final String[] args) throws NetworkException, OTSGeometryException, NamingException,
ValueRuntimeException, ParameterException, SimRuntimeException, Sim0MQException, SerializationException, IOException
{
CategoryLogger.setAllLogLevel(Level.WARNING);
CategoryLogger.setLogCategories(LogCategory.ALL);
Options options = new Options();
CliUtil.execute(options, args); // register Unit converters, parse the command line, etc..
int port = options.getPort();
System.out.println("Creating OTS server listening on port " + port);
ZContext context = new ZContext(10);
Sim0MQControlledOTS slave = new Sim0MQControlledOTS(context, port);
slave.commandLoop();
// Currently, there is no shutdown command; so the following code is never executed
context.destroy();
context.close();
}
/**
* Construct an OTS simulation experiment from an XML description.
* @param xml String; the XML encoded network
* @param simulationDuration Duration; total duration of the simulation
* @param warmupTime Duration; warm up time of the simulation
* @param seed Long; seed for the experiment
* @return String; null on success, description of the problem on error
*/
private String loadNetwork(final String xml, final Duration simulationDuration, final Duration warmupTime, final Long seed)
{
if (null != this.model)
{
return "Cannot create another network (yet)";
}
else
{
try
{
OTSAnimator animator = new OTSAnimator("OTS Animator");
this.model = new Sim0MQOTSModel(animator, "OTS model", "Remotely controlled OTS model", xml);
Map