#include <config.h>
#ifdef HAVE_VERSION_H
#include <version.h>
#endif
#include <string>
#include <cmath>
#include <map>
#include <iostream>
#include <algorithm>
#include <foreign/tcpip/socket.h>
#include <foreign/tcpip/storage.h>
#include <utils/common/SUMOTime.h>
#include <utils/router/DijkstraRouter.h>
#include <utils/common/NamedObjectCont.h>
#include <utils/common/RandHelper.h>
#include <utils/common/MsgHandler.h>
#include <utils/vehicle/SUMOVehicleParameter.h>
#include <utils/shapes/PointOfInterest.h>
#include <utils/shapes/ShapeContainer.h>
#include <utils/xml/XMLSubSys.h>
#include <microsim/MSNet.h>
#include <microsim/MSVehicle.h>
#include <microsim/MSEdge.h>
#include <microsim/MSJunctionControl.h>
#include <microsim/transportables/MSTransportableControl.h>
#include <microsim/MSJunction.h>
#include <microsim/MSEdgeControl.h>
#include <microsim/MSLane.h>
#include <microsim/MSGlobals.h>
#include <microsim/traffic_lights/MSTLLogicControl.h>
#include <libsumo/Helper.h>
#include <libsumo/StorageHelper.h>
#include <libsumo/Simulation.h>
#include <libsumo/Subscription.h>
#include <libsumo/TraCIConstants.h>
#include "TraCIServer.h"
#include "TraCIServerAPI_InductionLoop.h"
#include "TraCIServerAPI_Junction.h"
#include "TraCIServerAPI_Lane.h"
#include "TraCIServerAPI_MultiEntryExit.h"
#include "TraCIServerAPI_LaneArea.h"
#include "TraCIServerAPI_TrafficLight.h"
#include "TraCIServerAPI_Vehicle.h"
#include "TraCIServerAPI_VehicleType.h"
#include "TraCIServerAPI_Route.h"
#include "TraCIServerAPI_POI.h"
#include "TraCIServerAPI_Polygon.h"
#include "TraCIServerAPI_Edge.h"
#include "TraCIServerAPI_Simulation.h"
#include "TraCIServerAPI_Person.h"
#include "TraCIServerAPI_Calibrator.h"
#include "TraCIServerAPI_BusStop.h"
#include "TraCIServerAPI_ParkingArea.h"
#include "TraCIServerAPI_ChargingStation.h"
#include "TraCIServerAPI_RouteProbe.h"
#include "TraCIServerAPI_Rerouter.h"
#include "TraCIServerAPI_VariableSpeedSign.h"
#include "TraCIServerAPI_MeanData.h"
#include "TraCIServerAPI_OverheadWire.h"
TraCIServer* TraCIServer::myInstance = nullptr;
bool TraCIServer::myDoCloseConnection = false;
void
TraCIServer::initWrapper(const int domainID, const int variable, const std::string& objID) {
myWrapperStorage.reset();
myWrapperStorage.writeUnsignedByte(domainID);
myWrapperStorage.writeUnsignedByte(variable);
myWrapperStorage.writeString(objID);
}
bool
TraCIServer::wrapConnectionVector(const std::string& , const int , const std::vector<libsumo::TraCIConnection>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 8);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const libsumo::TraCIConnection& c : value) {
StoHelp::writeTypedString(myWrapperStorage, c.approachedLane);
StoHelp::writeTypedString(myWrapperStorage, c.approachedInternal);
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.hasPrio);
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.isOpen);
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.hasFoe);
StoHelp::writeTypedString(myWrapperStorage, c.state);
StoHelp::writeTypedString(myWrapperStorage, c.direction);
StoHelp::writeTypedDouble(myWrapperStorage, c.length);
}
return true;
}
bool
TraCIServer::wrapDouble(const std::string& , const int , const double value) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
myWrapperStorage.writeDouble(value);
return true;
}
bool
TraCIServer::wrapInt(const std::string& , const int , const int value) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_INTEGER);
myWrapperStorage.writeInt(value);
return true;
}
bool
TraCIServer::wrapString(const std::string& , const int , const std::string& value) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
myWrapperStorage.writeString(value);
return true;
}
bool
TraCIServer::wrapStringList(const std::string& , const int , const std::vector<std::string>& value) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
myWrapperStorage.writeStringList(value);
return true;
}
bool
TraCIServer::wrapDoubleList(const std::string& , const int , const std::vector<double>& value) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLELIST);
myWrapperStorage.writeDoubleList(value);
return true;
}
bool
TraCIServer::wrapPosition(const std::string& , const int variable, const libsumo::TraCIPosition& value) {
const bool includeZ = variable == libsumo::VAR_POSITION3D;
myWrapperStorage.writeUnsignedByte(includeZ ? libsumo::POSITION_3D : libsumo::POSITION_2D);
myWrapperStorage.writeDouble(value.x);
myWrapperStorage.writeDouble(value.y);
if (includeZ) {
myWrapperStorage.writeDouble(value.z);
}
return true;
}
bool
TraCIServer::wrapPositionVector(const std::string& , const int , const libsumo::TraCIPositionVector& shape) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
if (shape.value.size() < 256) {
myWrapperStorage.writeUnsignedByte((int)shape.value.size());
} else {
myWrapperStorage.writeUnsignedByte(0);
myWrapperStorage.writeInt((int)shape.value.size());
}
for (const libsumo::TraCIPosition& pos : shape.value) {
myWrapperStorage.writeDouble(pos.x);
myWrapperStorage.writeDouble(pos.y);
}
return true;
}
bool
TraCIServer::wrapColor(const std::string& , const int , const libsumo::TraCIColor& value) {
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COLOR);
myWrapperStorage.writeUnsignedByte(value.r);
myWrapperStorage.writeUnsignedByte(value.g);
myWrapperStorage.writeUnsignedByte(value.b);
myWrapperStorage.writeUnsignedByte(value.a);
return true;
}
bool
TraCIServer::wrapStringDoublePair(const std::string& , const int , const std::pair<std::string, double>& value) {
StoHelp::writeCompound(myWrapperStorage, 2);
StoHelp::writeTypedString(myWrapperStorage, value.first);
StoHelp::writeTypedDouble(myWrapperStorage, value.second);
return true;
}
bool
TraCIServer::wrapStringDoublePairList(const std::string& , const int , const std::vector<std::pair<std::string, double> >& value) {
StoHelp::writeCompound(myWrapperStorage, (int)value.size());
for (const auto& p : value) {
myWrapperStorage.writeString(p.first);
myWrapperStorage.writeDouble(p.second);
}
return true;
}
bool
TraCIServer::wrapStringPair(const std::string& , const int , const std::pair<std::string, std::string>& value) {
StoHelp::writeCompound(myWrapperStorage, 2);
StoHelp::writeTypedString(myWrapperStorage, value.first);
StoHelp::writeTypedString(myWrapperStorage, value.second);
return true;
}
bool
TraCIServer::wrapIntPair(const std::string& , const int , const std::pair<int, int>& value) {
StoHelp::writeCompound(myWrapperStorage, 2);
StoHelp::writeTypedInt(myWrapperStorage, value.first);
StoHelp::writeTypedInt(myWrapperStorage, value.second);
return true;
}
bool
TraCIServer::wrapStage(const std::string& , const int , const libsumo::TraCIStage& value) {
StoHelp::writeStage(myWrapperStorage, value);
return true;
}
bool
TraCIServer::wrapReservationVector(const std::string& , const int , const std::vector<libsumo::TraCIReservation>& value) {
StoHelp::writeCompound(myWrapperStorage, (int)value.size());
for (const libsumo::TraCIReservation& r : value) {
StoHelp::writeCompound(myWrapperStorage, 10);
StoHelp::writeTypedString(myWrapperStorage, r.id);
StoHelp::writeTypedStringList(myWrapperStorage, r.persons);
StoHelp::writeTypedString(myWrapperStorage, r.group);
StoHelp::writeTypedString(myWrapperStorage, r.fromEdge);
StoHelp::writeTypedString(myWrapperStorage, r.toEdge);
StoHelp::writeTypedDouble(myWrapperStorage, r.departPos);
StoHelp::writeTypedDouble(myWrapperStorage, r.arrivalPos);
StoHelp::writeTypedDouble(myWrapperStorage, r.depart);
StoHelp::writeTypedDouble(myWrapperStorage, r.reservationTime);
StoHelp::writeTypedInt(myWrapperStorage, r.state);
}
return true;
}
bool
TraCIServer::wrapLogicVector(const std::string& , const int , const std::vector<libsumo::TraCILogic>& value) {
StoHelp::writeCompound(myWrapperStorage, (int)value.size());
for (const libsumo::TraCILogic& logic : value) {
StoHelp::writeCompound(myWrapperStorage, 5);
StoHelp::writeTypedString(myWrapperStorage, logic.programID);
StoHelp::writeTypedInt(myWrapperStorage, logic.type);
StoHelp::writeTypedInt(myWrapperStorage, logic.currentPhaseIndex);
StoHelp::writeCompound(myWrapperStorage, (int)logic.phases.size());
for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
StoHelp::writeCompound(myWrapperStorage, 6);
StoHelp::writeTypedDouble(myWrapperStorage, phase->duration);
StoHelp::writeTypedString(myWrapperStorage, phase->state);
StoHelp::writeTypedDouble(myWrapperStorage, phase->minDur);
StoHelp::writeTypedDouble(myWrapperStorage, phase->maxDur);
StoHelp::writeCompound(myWrapperStorage, (int)phase->next.size());
for (int n : phase->next) {
StoHelp::writeTypedInt(myWrapperStorage, n);
}
StoHelp::writeTypedString(myWrapperStorage, phase->name);
}
StoHelp::writeCompound(myWrapperStorage, (int)logic.subParameter.size());
for (const auto& item : logic.subParameter) {
StoHelp::writeTypedStringList(myWrapperStorage, std::vector<std::string> {item.first, item.second});
}
}
return true;
}
bool
TraCIServer::wrapLinkVectorVector(const std::string& , const int , const std::vector<std::vector<libsumo::TraCILink> >& value) {
int cnt = 1;
for (const std::vector<libsumo::TraCILink>& sublinks : value) {
cnt += (int)sublinks.size() + 1;
}
StoHelp::writeCompound(myWrapperStorage, cnt);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const std::vector<libsumo::TraCILink>& sublinks : value) {
StoHelp::writeTypedInt(myWrapperStorage, (int)sublinks.size());
for (const libsumo::TraCILink& link : sublinks) {
StoHelp::writeTypedStringList(myWrapperStorage, std::vector<std::string>({ link.fromLane, link.toLane, link.viaLane }));
}
}
return true;
}
bool
TraCIServer::wrapSignalConstraintVector(const std::string& , const int , const std::vector<libsumo::TraCISignalConstraint>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 5);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const auto& c : value) {
StoHelp::writeConstraint(myWrapperStorage, c);
}
return true;
}
bool
TraCIServer::wrapJunctionFoeVector(const std::string& , const int , const std::vector<libsumo::TraCIJunctionFoe>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 9);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const auto& c : value) {
StoHelp::writeTypedString(myWrapperStorage, c.foeId);
StoHelp::writeTypedDouble(myWrapperStorage, c.egoDist);
StoHelp::writeTypedDouble(myWrapperStorage, c.foeDist);
StoHelp::writeTypedDouble(myWrapperStorage, c.egoExitDist);
StoHelp::writeTypedDouble(myWrapperStorage, c.foeExitDist);
StoHelp::writeTypedString(myWrapperStorage, c.egoLane);
StoHelp::writeTypedString(myWrapperStorage, c.foeLane);
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.egoResponse);
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.foeResponse);
}
return true;
}
bool
TraCIServer::wrapNextStopDataVector(const std::string& , const int variable, const std::vector<libsumo::TraCINextStopData>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 4);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
const bool full = variable == libsumo::VAR_NEXT_STOPS2;
for (const auto& s : value) {
const int legacyStopFlags = (s.stopFlags << 1) + (s.arrival >= 0 ? 1 : 0);
StoHelp::writeTypedString(myWrapperStorage, s.lane);
StoHelp::writeTypedDouble(myWrapperStorage, s.endPos);
StoHelp::writeTypedString(myWrapperStorage, s.stoppingPlaceID);
StoHelp::writeTypedInt(myWrapperStorage, full ? s.stopFlags : legacyStopFlags);
StoHelp::writeTypedDouble(myWrapperStorage, s.duration);
StoHelp::writeTypedDouble(myWrapperStorage, s.until);
if (full) {
StoHelp::writeTypedDouble(myWrapperStorage, s.startPos);
StoHelp::writeTypedDouble(myWrapperStorage, s.intendedArrival);
StoHelp::writeTypedDouble(myWrapperStorage, s.arrival);
StoHelp::writeTypedDouble(myWrapperStorage, s.depart);
StoHelp::writeTypedString(myWrapperStorage, s.split);
StoHelp::writeTypedString(myWrapperStorage, s.join);
StoHelp::writeTypedString(myWrapperStorage, s.actType);
StoHelp::writeTypedString(myWrapperStorage, s.tripId);
StoHelp::writeTypedString(myWrapperStorage, s.line);
StoHelp::writeTypedDouble(myWrapperStorage, s.speed);
}
}
return true;
}
bool
TraCIServer::wrapVehicleDataVector(const std::string& , const int , const std::vector<libsumo::TraCIVehicleData>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 5);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const libsumo::TraCIVehicleData& vd : value) {
StoHelp::writeTypedString(myWrapperStorage, vd.id);
StoHelp::writeTypedDouble(myWrapperStorage, vd.length);
StoHelp::writeTypedDouble(myWrapperStorage, vd.entryTime);
StoHelp::writeTypedDouble(myWrapperStorage, vd.leaveTime);
StoHelp::writeTypedString(myWrapperStorage, vd.typeID);
}
return true;
}
bool
TraCIServer::wrapBestLanesDataVector(const std::string& , const int , const std::vector<libsumo::TraCIBestLanesData>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 6);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const libsumo::TraCIBestLanesData& bld : value) {
StoHelp::writeTypedString(myWrapperStorage, bld.laneID);
StoHelp::writeTypedDouble(myWrapperStorage, bld.length);
StoHelp::writeTypedDouble(myWrapperStorage, bld.occupation);
StoHelp::writeTypedByte(myWrapperStorage, bld.bestLaneOffset);
StoHelp::writeTypedUnsignedByte(myWrapperStorage, bld.allowsContinuation ? 1 : 0);
StoHelp::writeTypedStringList(myWrapperStorage, bld.continuationLanes);
}
return true;
}
bool
TraCIServer::wrapNextTLSDataVector(const std::string& , const int , const std::vector<libsumo::TraCINextTLSData>& value) {
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 4);
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
for (const libsumo::TraCINextTLSData& tlsd : value) {
StoHelp::writeTypedString(myWrapperStorage, tlsd.id);
StoHelp::writeTypedInt(myWrapperStorage, tlsd.tlIndex);
StoHelp::writeTypedDouble(myWrapperStorage, tlsd.dist);
StoHelp::writeTypedByte(myWrapperStorage, tlsd.state);
}
return true;
}
tcpip::Storage&
TraCIServer::getWrapperStorage() {
return myWrapperStorage;
}
TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
: myTargetTime(begin), myLastContextSubscription(nullptr) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
#endif
myVehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
myVehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
myTransportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
myTransportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
myTransportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
myTransportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
myExecutors[libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processGet;
myExecutors[libsumo::CMD_SET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processSet;
myExecutors[libsumo::CMD_GET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processGet;
myExecutors[libsumo::CMD_SET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processSet;
myExecutors[libsumo::CMD_GET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processGet;
myExecutors[libsumo::CMD_SET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processSet;
myExecutors[libsumo::CMD_GET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processGet;
myExecutors[libsumo::CMD_SET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processSet;
myExecutors[libsumo::CMD_GET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processGet;
myExecutors[libsumo::CMD_SET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processSet;
myExecutors[libsumo::CMD_GET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processGet;
myExecutors[libsumo::CMD_SET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processSet;
myExecutors[libsumo::CMD_GET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processGet;
myExecutors[libsumo::CMD_SET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processSet;
myExecutors[libsumo::CMD_GET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processGet;
myExecutors[libsumo::CMD_SET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processSet;
myExecutors[libsumo::CMD_GET_POI_VARIABLE] = &TraCIServerAPI_POI::processGet;
myExecutors[libsumo::CMD_SET_POI_VARIABLE] = &TraCIServerAPI_POI::processSet;
myExecutors[libsumo::CMD_GET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processGet;
myExecutors[libsumo::CMD_SET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processSet;
myExecutors[libsumo::CMD_GET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processGet;
myExecutors[libsumo::CMD_SET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processSet;
myExecutors[libsumo::CMD_GET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processGet;
myExecutors[libsumo::CMD_SET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processSet;
myExecutors[libsumo::CMD_GET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processGet;
myExecutors[libsumo::CMD_SET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processSet;
myExecutors[libsumo::CMD_GET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processGet;
myExecutors[libsumo::CMD_SET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processSet;
myExecutors[libsumo::CMD_GET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processGet;
myExecutors[libsumo::CMD_SET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processSet;
myExecutors[libsumo::CMD_GET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processGet;
myExecutors[libsumo::CMD_SET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processSet;
myExecutors[libsumo::CMD_GET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processGet;
myExecutors[libsumo::CMD_SET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processSet;
myExecutors[libsumo::CMD_GET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processGet;
myExecutors[libsumo::CMD_SET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processSet;
myExecutors[libsumo::CMD_GET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processGet;
myExecutors[libsumo::CMD_SET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processSet;
myExecutors[libsumo::CMD_GET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processGet;
myExecutors[libsumo::CMD_SET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processSet;
myExecutors[libsumo::CMD_GET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processGet;
myExecutors[libsumo::CMD_SET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processSet;
myExecutors[libsumo::CMD_GET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processGet;
myExecutors[libsumo::CMD_GET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processGet;
myExecutors[libsumo::CMD_SET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processSet;
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_EDGE_TRAVELTIME));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_EDGE_EFFORT));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_ANGLE));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::VAR_ANGLE));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::LANE_CHANGES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::VAR_FOES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::DISTANCE_REQUEST));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_EDGES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_STAGE));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_TAXI_RESERVATIONS));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::SPLIT_TAXI_RESERVATIONS));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_BLOCKING_VEHICLES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_RIVAL_VEHICLES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_PRIORITY_VEHICLES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_CONSTRAINT));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_CONSTRAINT_BYFOE));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::VAR_PERSON_NUMBER));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::DISTANCE_REQUEST));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_EDGE_TRAVELTIME));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_EDGE_EFFORT));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOW_SPEED));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_SECURE_GAP));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_STOP_SPEED));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOES));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::CMD_CHANGELANE));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_LEADER));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOWER));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEIGHBORS));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_STOP_PARAMETER));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEXT_STOPS));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEXT_STOPS2));
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_TAXI_FLEET));
myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER));
myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER_WITH_KEY));
myDoCloseConnection = false;
if (!MSGlobals::gUsingInternalLanes && !MSGlobals::gUseMesoSim) {
WRITE_WARNING(TL("Starting TraCI without using internal lanes!"));
MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
}
try {
WRITE_MESSAGEF(TL("***Starting server on port % ***"), toString(port));
tcpip::Socket serverSocket(port);
if (numClients > 1) {
WRITE_MESSAGEF(TL(" waiting for % clients..."), toString(numClients));
}
while ((int)mySockets.size() < numClients) {
int index = (int)mySockets.size() + libsumo::MAX_ORDER + 1;
mySockets[index] = new SocketInfo(serverSocket.accept(true), begin);
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
if (numClients > 1) {
WRITE_MESSAGE(TL(" client connected"));
}
}
if (numClients > 1) {
checkClientOrdering();
}
myCurrentSocket = mySockets.begin();
} catch (tcpip::SocketException& e) {
throw ProcessError(e.what());
}
}
TraCIServer::~TraCIServer() {
for (const auto& socket : mySockets) {
delete socket.second;
}
}
void
TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
if (myInstance == nullptr && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0)) {
myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
OptionsCont::getOptions().getInt("remote-port"),
OptionsCont::getOptions().getInt("num-clients"));
for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
myInstance->myExecutors[i->first] = i->second;
}
}
if (myInstance != nullptr) {
MSNet::getInstance()->addVehicleStateListener(myInstance);
MSNet::getInstance()->addTransportableStateListener(myInstance);
myInstance->mySubscriptionCache.writeInt(0);
}
}
void
TraCIServer::close() {
if (myInstance == nullptr) {
return;
}
delete myInstance;
myInstance = nullptr;
myDoCloseConnection = true;
}
bool
TraCIServer::wasClosed() {
return myDoCloseConnection;
}
void
TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& ) {
if (!myDoCloseConnection) {
myVehicleStateChanges[to].push_back(vehicle->getID());
for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
i->second->vehicleStateChanges[to].push_back(vehicle->getID());
}
}
}
void
TraCIServer::transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& ) {
if (!myDoCloseConnection) {
myTransportableStateChanges[to].push_back(transportable->getID());
for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
i->second->transportableStateChanges[to].push_back(transportable->getID());
}
}
}
void
TraCIServer::checkClientOrdering() {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << "Checking client order requests." << std::endl;
#endif
myCurrentSocket = mySockets.begin();
while (myCurrentSocket != mySockets.end()) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Socket " << myCurrentSocket->second->socket << ":" << std::endl;
#endif
while (true) {
myInputStorage.reset();
myCurrentSocket->second->socket->receiveExact(myInputStorage);
int commandStart, commandLength;
int commandId = readCommandID(commandStart, commandLength);
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " received command " << commandId << std::endl;
#endif
bool initCommand = commandId == libsumo::CMD_SETORDER || commandId == libsumo::CMD_GETVERSION;
if (initCommand) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Init command. Sending response." << std::endl;
#endif
tcpip::Storage tmp;
tmp.writeStorage(myInputStorage);
myInputStorage.reset();
myInputStorage.writeUnsignedByte(commandId == libsumo::CMD_SETORDER ? 6 : 2);
myInputStorage.writeUnsignedByte(commandId);
myInputStorage.writeStorage(tmp);
dispatchCommand();
myCurrentSocket->second->socket->sendExact(myOutputStorage);
myOutputStorage.reset();
} else {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
#endif
throw ProcessError(TL("Execution order (libsumo::CMD_SETORDER) was not set for all TraCI clients in pre-execution phase."));
}
if (commandId == libsumo::CMD_SETORDER) {
break;
}
}
++myCurrentSocket;
}
}
void
TraCIServer::processReorderingRequests() {
if (mySocketReorderRequests.size() > 0) {
std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
std::map<int, SocketInfo*>::iterator j;
#ifdef DEBUG_MULTI_CLIENTS
std::cout << SIMTIME << " Current socket ordering:\n";
for (j = mySockets.begin(); j != mySockets.end(); ++j) {
std::cout << " " << j->first << ": " << j->second->socket << "\n";
}
std::cout << "Reordering requests:\n";
for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
std::cout << " Socket " << i->second->socket << " -> " << i->first << "\n";
}
i = mySocketReorderRequests.begin();
#endif
while (i != mySocketReorderRequests.end()) {
j = mySockets.begin();
while (j != mySockets.end()) {
if (j->second->socket == i->second->socket) {
break;
} else {
j++;
}
}
assert(j != mySockets.end());
mySockets.erase(j);
mySockets[i->first] = i->second;
++i;
}
mySocketReorderRequests.clear();
#ifdef DEBUG_MULTI_CLIENTS
std::cout << "New socket ordering:\n";
for (j = mySockets.begin(); j != mySockets.end(); ++j) {
std::cout << " " << j->first << ": " << j->second->socket << "\n";
}
std::cout << std::endl;
#endif
}
}
SUMOTime
TraCIServer::nextTargetTime() const {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << "\n Determining new target time..." << std::endl;
if (mySockets.size() == 0) {
std::cout << " All clients have disconnected." << std::endl;
}
#endif
std::map<int, SocketInfo*>::const_iterator i;
SUMOTime targetTime = std::numeric_limits<SUMOTime>::max();
for (i = mySockets.begin(); i != mySockets.end(); ++i) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
#endif
targetTime = MIN2(targetTime, i->second->targetTime);
}
#ifdef DEBUG_MULTI_CLIENTS
std::cout << std::endl;
#endif
return targetTime;
}
void
TraCIServer::sendOutputToAll() const {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << "\n Sending subscription results to clients:\n";
#endif
std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
while (i != mySockets.end()) {
if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
i->second->socket->sendExact(myOutputStorage);
#ifdef DEBUG_MULTI_CLIENTS
std::cout << i->second->socket << "\n";
#endif
}
++i;
}
#ifdef DEBUG_MULTI_CLIENTS
std::cout << std::endl;
#endif
}
int
TraCIServer::processCommands(const SUMOTime step, const bool afterMove) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << SIMTIME << " processCommands(step = " << step << "):\n" << std::endl;
#endif
try {
int finalCmd = 0;
const bool firstStep = myCurrentSocket != mySockets.end();
processReorderingRequests();
if (!firstStep && !afterMove) {
postProcessSimulationStep();
sendOutputToAll();
myOutputStorage.reset();
}
myTargetTime = nextTargetTime();
if (step < myTargetTime) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " next target time is larger than next SUMO simstep (" << step << "). Returning from processCommands()." << std::endl;
#endif
return finalCmd;
}
while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep()) && finalCmd != libsumo::CMD_EXECUTEMOVE) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Next target time: " << myTargetTime << std::endl;
#endif
myCurrentSocket = mySockets.begin();
while (myCurrentSocket != mySockets.end()) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " current socket: " << myCurrentSocket->second->socket
<< " with target time=" << myCurrentSocket->second->targetTime
<< std::endl;
#endif
if (myCurrentSocket->second->targetTime > myTargetTime || (afterMove && !myCurrentSocket->second->executeMove)) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " skipping client " << myCurrentSocket->second->socket
<< " with target time=" << myCurrentSocket->second->targetTime << std::endl;
#endif
myCurrentSocket++;
continue;
}
finalCmd = 0;
while (finalCmd == 0) {
if (!myInputStorage.valid_pos()) {
if (myOutputStorage.size() > 0) {
myCurrentSocket->second->socket->sendExact(myOutputStorage);
myOutputStorage.reset();
}
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " resetting input storage and reading next command..." << std::endl;
#endif
myInputStorage.reset();
myCurrentSocket->second->socket->receiveExact(myInputStorage);
}
while (myInputStorage.valid_pos() && !myDoCloseConnection) {
const int cmd = dispatchCommand();
if (cmd == libsumo::CMD_SIMSTEP || cmd == libsumo::CMD_LOAD || cmd == libsumo::CMD_EXECUTEMOVE || cmd == libsumo::CMD_CLOSE) {
finalCmd = cmd;
}
}
}
}
if (!myLoadArgs.empty()) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Breaking loop to load new simulation." << std::endl;
#endif
break;
} else if (myDoCloseConnection) {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Breaking loop because last client closed connection." << std::endl;
#endif
break;
}
SUMOTime nextT = nextTargetTime();
myTargetTime = nextT;
}
for (auto& item : myVehicleStateChanges) {
item.second.clear();
}
for (auto& item : myTransportableStateChanges) {
item.second.clear();
}
return finalCmd;
} catch (std::invalid_argument& e) {
throw ProcessError(e.what());
} catch (libsumo::TraCIException& e) {
throw ProcessError(e.what());
} catch (tcpip::SocketException& e) {
throw ProcessError(e.what());
}
}
void
TraCIServer::cleanup() {
mySubscriptions.clear();
myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
myCurrentSocket->second->targetTime = myTargetTime;
myCurrentSocket->second->executeMove = false;
}
myOutputStorage.reset();
myInputStorage.reset();
mySubscriptionCache.reset();
for (auto& i : myVehicleStateChanges) {
i.second.clear();
}
for (auto& i : myTransportableStateChanges) {
i.second.clear();
}
myCurrentSocket = mySockets.begin();
}
std::map<int, TraCIServer::SocketInfo*>::iterator
TraCIServer::removeCurrentSocket() {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Removing socket " << myCurrentSocket->second->socket
<< " (order " << myCurrentSocket->first << ")" << std::endl;
#endif
delete myCurrentSocket->second;
myCurrentSocket = mySockets.erase(myCurrentSocket);
return myCurrentSocket;
}
int
TraCIServer::readCommandID(int& commandStart, int& commandLength) {
commandStart = myInputStorage.position();
commandLength = myInputStorage.readUnsignedByte();
if (commandLength == 0) {
commandLength = myInputStorage.readInt();
}
#ifdef DEBUG_RAW_INPUT
std::cout << " commandStart=" << commandStart << " commandLength=" << commandLength << " pos=" << myInputStorage.position() << " raw=";
for (auto it = myInputStorage.begin(); it != myInputStorage.end(); ++it) {
std::cout << (int)*it << " ";
}
std::cout << "\n";
#endif
return myInputStorage.readUnsignedByte();
}
int
TraCIServer::dispatchCommand() {
int commandStart, commandLength;
int commandId = readCommandID(commandStart, commandLength);
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " dispatchCommand() called for client " << myCurrentSocket->second->socket
<< ", commandId = " << commandId << std::endl;
#endif
bool success = false;
if (myExecutors.find(commandId) != myExecutors.end()) {
success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
} else {
switch (commandId) {
case libsumo::CMD_GETVERSION:
success = commandGetVersion();
break;
case libsumo::CMD_LOAD: {
std::vector<std::string> args;
if (!readTypeCheckingStringList(myInputStorage, args)) {
return writeErrorStatusCmd(libsumo::CMD_LOAD, "A load command needs a list of string arguments.", myOutputStorage);
}
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " commandId == libsumo::CMD_LOAD"
<< ", args = " << toString(args) << std::endl;
#endif
try {
myLoadArgs = args;
success = true;
writeStatusCmd(libsumo::CMD_LOAD, libsumo::RTYPE_OK, "");
myCurrentSocket->second->socket->sendExact(myOutputStorage);
myCurrentSocket = mySockets.end();
myOutputStorage.reset();
} catch (libsumo::TraCIException& e) {
return writeErrorStatusCmd(libsumo::CMD_LOAD, e.what(), myOutputStorage);
}
break;
}
case libsumo::CMD_EXECUTEMOVE:
myCurrentSocket->second->executeMove = true;
myCurrentSocket++;
success = true;
writeStatusCmd(libsumo::CMD_EXECUTEMOVE, libsumo::RTYPE_OK, "");
break;
case libsumo::CMD_SIMSTEP: {
const double nextT = myInputStorage.readDouble();
if (nextT == 0.) {
myCurrentSocket->second->targetTime += DELTA_T;
} else {
myCurrentSocket->second->targetTime = TIME2STEPS(nextT);
}
myCurrentSocket->second->executeMove = false;
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " commandId == libsumo::CMD_SIMSTEP"
<< ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
#endif
if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
sendSingleSimStepResponse();
}
for (auto& item : myCurrentSocket->second->vehicleStateChanges) {
item.second.clear();
}
for (auto& item : myCurrentSocket->second->transportableStateChanges) {
item.second.clear();
}
myCurrentSocket++;
return commandId;
}
case libsumo::CMD_CLOSE:
writeStatusCmd(libsumo::CMD_CLOSE, libsumo::RTYPE_OK, "");
myCurrentSocket->second->socket->sendExact(myOutputStorage);
myOutputStorage.reset();
if (mySockets.size() == 1) {
myDoCloseConnection = true;
}
myCurrentSocket = removeCurrentSocket();
success = true;
break;
case libsumo::CMD_SETORDER: {
const int order = myInputStorage.readInt();
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " commandId == libsumo::CMD_SETORDER"
<< ", order index is " << order << std::endl;
#endif
if (order > libsumo::MAX_ORDER) {
return writeErrorStatusCmd(libsumo::CMD_SETORDER, "A set order command needs an int argument below " + toString(libsumo::MAX_ORDER) + ".", myOutputStorage);
}
if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
return writeErrorStatusCmd(libsumo::CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
}
mySocketReorderRequests[order] = myCurrentSocket->second;
success = true;
writeStatusCmd(libsumo::CMD_SETORDER, libsumo::RTYPE_OK, "");
break;
}
case libsumo::CMD_SUBSCRIBE_BUSSTOP_VARIABLE:
case libsumo::CMD_SUBSCRIBE_CALIBRATOR_VARIABLE:
case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_VARIABLE:
case libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE:
case libsumo::CMD_SUBSCRIBE_GUI_VARIABLE:
case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE:
case libsumo::CMD_SUBSCRIBE_JUNCTION_VARIABLE:
case libsumo::CMD_SUBSCRIBE_LANE_VARIABLE:
case libsumo::CMD_SUBSCRIBE_LANEAREA_VARIABLE:
case libsumo::CMD_SUBSCRIBE_MEANDATA_VARIABLE:
case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE:
case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_VARIABLE:
case libsumo::CMD_SUBSCRIBE_PARKINGAREA_VARIABLE:
case libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE:
case libsumo::CMD_SUBSCRIBE_POI_VARIABLE:
case libsumo::CMD_SUBSCRIBE_POLYGON_VARIABLE:
case libsumo::CMD_SUBSCRIBE_REROUTER_VARIABLE:
case libsumo::CMD_SUBSCRIBE_ROUTE_VARIABLE:
case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_VARIABLE:
case libsumo::CMD_SUBSCRIBE_SIM_VARIABLE:
case libsumo::CMD_SUBSCRIBE_TL_VARIABLE:
case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_VARIABLE:
case libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE:
case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE:
success = addObjectVariableSubscription(commandId, false);
break;
case libsumo::CMD_SUBSCRIBE_BUSSTOP_CONTEXT:
case libsumo::CMD_SUBSCRIBE_CALIBRATOR_CONTEXT:
case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_CONTEXT:
case libsumo::CMD_SUBSCRIBE_EDGE_CONTEXT:
case libsumo::CMD_SUBSCRIBE_GUI_CONTEXT:
case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT:
case libsumo::CMD_SUBSCRIBE_JUNCTION_CONTEXT:
case libsumo::CMD_SUBSCRIBE_LANE_CONTEXT:
case libsumo::CMD_SUBSCRIBE_LANEAREA_CONTEXT:
case libsumo::CMD_SUBSCRIBE_MEANDATA_CONTEXT:
case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT:
case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_CONTEXT:
case libsumo::CMD_SUBSCRIBE_PARKINGAREA_CONTEXT:
case libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT:
case libsumo::CMD_SUBSCRIBE_POI_CONTEXT:
case libsumo::CMD_SUBSCRIBE_POLYGON_CONTEXT:
case libsumo::CMD_SUBSCRIBE_REROUTER_CONTEXT:
case libsumo::CMD_SUBSCRIBE_ROUTE_CONTEXT:
case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_CONTEXT:
case libsumo::CMD_SUBSCRIBE_SIM_CONTEXT:
case libsumo::CMD_SUBSCRIBE_TL_CONTEXT:
case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_CONTEXT:
case libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT:
case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_CONTEXT:
success = addObjectVariableSubscription(commandId, true);
break;
case libsumo::CMD_ADD_SUBSCRIPTION_FILTER:
success = addSubscriptionFilter();
break;
default:
if (commandId == libsumo::CMD_GET_GUI_VARIABLE || commandId == libsumo::CMD_SET_GUI_VARIABLE) {
writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo");
} else {
writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
}
}
}
if (!success) {
while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
myInputStorage.readChar();
}
}
if ((int)myInputStorage.position() != commandStart + commandLength) {
std::ostringstream msg;
msg << "Wrong position in requestMessage after dispatching command " << commandId << ".";
msg << " Expected command length was " << commandLength;
msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
writeStatusCmd(commandId, libsumo::RTYPE_ERR, msg.str());
myDoCloseConnection = true;
}
return commandId;
}
bool
TraCIServer::commandGetVersion() {
tcpip::Storage answerTmp;
answerTmp.writeInt(libsumo::TRACI_VERSION);
answerTmp.writeString("SUMO " VERSION_STRING);
writeStatusCmd(libsumo::CMD_GETVERSION, libsumo::RTYPE_OK, "");
myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
myOutputStorage.writeUnsignedByte(libsumo::CMD_GETVERSION);
myOutputStorage.writeStorage(answerTmp);
return true;
}
void
TraCIServer::postProcessSimulationStep() {
SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " postProcessSimulationStep() at time=" << t << std::endl;
#endif
writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
int noActive = 0;
for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
const libsumo::Subscription& s = *i;
bool isArrivedVehicle = (s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT)
&& (find(myVehicleStateChanges[MSNet::VehicleState::ARRIVED].begin(), myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end(), s.id) != myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end());
bool isArrivedPerson = (s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT) && MSNet::getInstance()->getPersonControl().get(s.id) == nullptr;
if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
i = mySubscriptions.erase(i);
continue;
}
++i;
if (s.beginTime > t) {
continue;
}
++noActive;
}
mySubscriptionCache.reset();
#ifdef DEBUG_SUBSCRIPTIONS
std::cout << " Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
<< "\n Nr. of active subscriptions = " << noActive << std::endl;
#endif
mySubscriptionCache.writeInt(noActive);
#ifdef DEBUG_SUBSCRIPTIONS
std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
#endif
for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
const libsumo::Subscription& s = *i;
if (s.beginTime > t) {
++i;
continue;
}
tcpip::Storage into;
std::string errors;
bool ok = processSingleSubscription(s, into, errors);
#ifdef DEBUG_SUBSCRIPTIONS
std::cout << " Size of into-store for subscription " << s.id
<< ": " << into.size() << std::endl;
#endif
mySubscriptionCache.writeStorage(into);
if (ok) {
++i;
} else {
i = mySubscriptions.erase(i);
}
}
myOutputStorage.writeStorage(mySubscriptionCache);
#ifdef DEBUG_SUBSCRIPTIONS
std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
#endif
}
void
TraCIServer::sendSingleSimStepResponse() {
#ifdef DEBUG_MULTI_CLIENTS
std::cout << " Sending cached simstep response to current client " << myCurrentSocket->second->socket
<< " (-> intermediate TraCI step)."
<< "\n Size of mySubscriptionCache is " << mySubscriptionCache.size()
<< std::endl;
#endif
writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
myOutputStorage.writeStorage(mySubscriptionCache);
myCurrentSocket->second->socket->sendExact(myOutputStorage);
myOutputStorage.reset();
}
void
TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
writeStatusCmd(commandId, status, description, myOutputStorage);
}
void
TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
if (status == libsumo::RTYPE_ERR) {
WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
} else if (status == libsumo::RTYPE_NOTIMPLEMENTED) {
WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
}
outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length()));
outputStorage.writeUnsignedByte(commandId);
outputStorage.writeUnsignedByte(status);
outputStorage.writeString(description);
}
bool
TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
writeStatusCmd(commandId, libsumo::RTYPE_ERR, description, outputStorage);
return false;
}
void
TraCIServer::initialiseSubscription(libsumo::Subscription& s) {
tcpip::Storage writeInto;
std::string errors;
libsumo::Subscription* modifiedSubscription = nullptr;
try {
if (processSingleSubscription(s, writeInto, errors)) {
if (s.endTime < MSNet::getInstance()->getCurrentTimeStep()) {
writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Subscription has ended.");
} else {
if (libsumo::Helper::needNewSubscription(s, mySubscriptions, modifiedSubscription)) {
if (s.beginTime < MSNet::getInstance()->getCurrentTimeStep()) {
int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
tcpip::Storage tmp;
tmp.writeInt(noActive);
while (mySubscriptionCache.valid_pos()) {
tmp.writeByte(mySubscriptionCache.readByte());
}
tmp.writeStorage(writeInto);
mySubscriptionCache.reset();
mySubscriptionCache.writeStorage(tmp);
}
}
writeStatusCmd(s.commandId, libsumo::RTYPE_OK, "");
}
if (modifiedSubscription != nullptr && (
modifiedSubscription->isVehicleToVehicleContextSubscription()
|| modifiedSubscription->isVehicleToPersonContextSubscription())) {
myLastContextSubscription = modifiedSubscription;
} else {
myLastContextSubscription = nullptr;
}
} else {
writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Could not add subscription. " + errors);
}
} catch (libsumo::TraCIException& e) {
writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, e.what());
}
myOutputStorage.writeStorage(writeInto);
}
void
TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
bool found = false;
std::vector<libsumo::Subscription>::iterator j;
for (j = mySubscriptions.begin(); j != mySubscriptions.end();) {
if (j->id == id && j->commandId == commandId && j->contextDomain == domain) {
j = mySubscriptions.erase(j);
if (j != mySubscriptions.end() && myLastContextSubscription == &(*j)) {
myLastContextSubscription = nullptr;
}
found = true;
continue;
}
++j;
}
if (found) {
writeStatusCmd(commandId, libsumo::RTYPE_OK, "");
} else {
writeStatusCmd(commandId, libsumo::RTYPE_ERR, "The subscription to remove was not found.");
}
}
bool
TraCIServer::processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
std::string& errors) {
bool ok = true;
tcpip::Storage outputStorage;
const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
std::set<std::string> objIDs;
if (s.contextDomain > 0) {
if ((s.activeFilters & libsumo::SUBS_FILTER_NO_RTREE) == 0) {
PositionVector shape;
libsumo::Helper::findObjectShape(s.commandId, s.id, shape);
libsumo::Helper::collectObjectIDsInRange(s.contextDomain, shape, s.range, objIDs);
}
libsumo::Helper::applySubscriptionFilters(s, objIDs);
} else {
objIDs.insert(s.id);
}
const int numVars = s.contextDomain > 0 && s.variables.size() == 1 && s.variables[0] == libsumo::TRACI_ID_LIST ? 0 : (int)s.variables.size();
int skipped = 0;
for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
if (s.contextDomain > 0) {
outputStorage.writeString(*j);
}
if (numVars > 0) {
std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
tcpip::Storage message;
message.writeUnsignedByte(*i);
message.writeString(*j);
for (const auto& v :** k) {
message.writeChar(v);
}
tcpip::Storage tmpOutput;
try {
if (myExecutors.find(getCommandId) != myExecutors.end()) {
ok &= myExecutors[getCommandId](*this, message, tmpOutput);
} else {
writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
ok = false;
}
} catch (const std::invalid_argument&) {
writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
ok = false;
}
if (ok) {
int length = tmpOutput.readUnsignedByte();
while (--length > 0) {
tmpOutput.readUnsignedByte();
}
int lengthLength = 1;
length = tmpOutput.readUnsignedByte();
if (length == 0) {
lengthLength = 5;
length = tmpOutput.readInt();
}
tmpOutput.readUnsignedByte();
int variable = tmpOutput.readUnsignedByte();
std::string id = tmpOutput.readString();
outputStorage.writeUnsignedByte(variable);
outputStorage.writeUnsignedByte(libsumo::RTYPE_OK);
length -= (lengthLength + 1 + 4 + (int)id.length());
while (--length > 0) {
outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
}
} else {
tmpOutput.readUnsignedByte();
tmpOutput.readUnsignedByte();
tmpOutput.readUnsignedByte();
std::string msg = tmpOutput.readString();
outputStorage.writeUnsignedByte(*i);
outputStorage.writeUnsignedByte(libsumo::RTYPE_ERR);
outputStorage.writeUnsignedByte(libsumo::TYPE_STRING);
outputStorage.writeString(msg);
errors = errors + msg;
}
}
}
}
int length = (1 + 4) + 1 + (4 + (int)s.id.length()) + 1 + (int)outputStorage.size();
if (s.contextDomain > 0) {
length += 1 + 4;
}
writeInto.writeUnsignedByte(0);
writeInto.writeInt(length);
writeInto.writeUnsignedByte(s.commandId + 0x10);
writeInto.writeString(s.id);
if (s.contextDomain > 0) {
writeInto.writeUnsignedByte(s.contextDomain);
}
writeInto.writeUnsignedByte(numVars);
if (s.contextDomain > 0) {
writeInto.writeInt((int)objIDs.size() - skipped);
}
if (s.contextDomain == 0 || objIDs.size() != 0) {
writeInto.writeStorage(outputStorage);
}
return ok;
}
bool
TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
const double beginTime = myInputStorage.readDouble();
const double endTime = myInputStorage.readDouble();
const SUMOTime begin = beginTime == libsumo::INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
const SUMOTime end = endTime == libsumo::INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
const std::string id = myInputStorage.readString();
const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
double range = hasContext ? myInputStorage.readDouble() : 0.;
if (commandId == libsumo::CMD_SUBSCRIBE_SIM_CONTEXT) {
range = std::numeric_limits<double>::max();
}
const int num = myInputStorage.readUnsignedByte();
std::vector<int> variables;
std::vector<std::shared_ptr<tcpip::Storage> > parameters;
for (int i = 0; i < num; ++i) {
const int varID = myInputStorage.readUnsignedByte();
variables.push_back(varID);
parameters.push_back(std::make_shared<tcpip::Storage>());
if ((myParameterized.count(std::make_pair(0, varID)) > 0) || (myParameterized.count(std::make_pair(commandId, varID)) > 0)) {
if (!myInputStorage.valid_pos()) {
writeStatusCmd(commandId, libsumo::RTYPE_ERR, "Missing parameter for subscription " + toHex(commandId, 2));
return false;
}
int count = 1;
while (count-- > 0) {
const int parType = myInputStorage.readUnsignedByte();
parameters.back()->writeUnsignedByte(parType);
if (parType == libsumo::TYPE_DOUBLE) {
parameters.back()->writeDouble(myInputStorage.readDouble());
} else if (parType == libsumo::TYPE_INTEGER) {
parameters.back()->writeInt(myInputStorage.readInt());
} else if (parType == libsumo::TYPE_STRING) {
parameters.back()->writeString(myInputStorage.readString());
} else if (parType == libsumo::TYPE_BYTE) {
parameters.back()->writeByte(myInputStorage.readByte());
} else if (parType == libsumo::TYPE_UBYTE) {
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
} else if (parType == libsumo::POSITION_2D) {
parameters.back()->writeDouble(myInputStorage.readDouble());
parameters.back()->writeDouble(myInputStorage.readDouble());
if (varID == libsumo::DISTANCE_REQUEST) {
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
break;
}
} else if (parType == libsumo::POSITION_3D) {
parameters.back()->writeDouble(myInputStorage.readDouble());
parameters.back()->writeDouble(myInputStorage.readDouble());
parameters.back()->writeDouble(myInputStorage.readDouble());
if (varID == libsumo::DISTANCE_REQUEST) {
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
break;
}
} else if (parType == libsumo::POSITION_ROADMAP) {
parameters.back()->writeString(myInputStorage.readString());
parameters.back()->writeDouble(myInputStorage.readDouble());
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
if (varID == libsumo::DISTANCE_REQUEST) {
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
break;
}
} else if (parType == libsumo::TYPE_COMPOUND) {
count = myInputStorage.readInt();
parameters.back()->writeInt(count);
} else {
writeStatusCmd(commandId, libsumo::RTYPE_ERR, "Invalid parameter for subscription " + toHex(commandId, 2));
return false;
}
}
}
}
if (variables.empty()) {
removeSubscription(commandId, id, domain);
return true;
}
libsumo::Subscription s(commandId, id, variables, parameters, begin, end, domain, range);
initialiseSubscription(s);
return true;
}
bool
TraCIServer::addSubscriptionFilter() {
bool success = true;
int filterType = myInputStorage.readUnsignedByte();
if (myLastContextSubscription == nullptr) {
writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_ERR,
"No previous vehicle context subscription exists to apply filter type " + toHex(filterType, 2));
return false;
}
switch (filterType) {
case libsumo::FILTER_TYPE_NONE:
removeFilters();
break;
case libsumo::FILTER_TYPE_LANES: {
int nrLanes = (int)myInputStorage.readByte();
std::vector<int> lanes;
for (int i = 0; i < nrLanes; ++i) {
lanes.push_back((int) myInputStorage.readByte());
}
addSubscriptionFilterLanes(lanes);
}
break;
case libsumo::FILTER_TYPE_NOOPPOSITE:
addSubscriptionFilterNoOpposite();
break;
case libsumo::FILTER_TYPE_DOWNSTREAM_DIST: {
myInputStorage.readByte();
double dist = myInputStorage.readDouble();
addSubscriptionFilterDownstreamDistance(dist);
}
break;
case libsumo::FILTER_TYPE_UPSTREAM_DIST: {
myInputStorage.readByte();
double dist = myInputStorage.readDouble();
addSubscriptionFilterUpstreamDistance(dist);
}
break;
case libsumo::FILTER_TYPE_LEAD_FOLLOW: {
addSubscriptionFilterLeadFollow();
}
break;
case libsumo::FILTER_TYPE_TURN: {
myInputStorage.readByte();
double dist = myInputStorage.readDouble();
addSubscriptionFilterTurn(dist);
}
break;
case libsumo::FILTER_TYPE_VCLASS: {
myInputStorage.readByte();
SVCPermissions vClasses = parseVehicleClasses(myInputStorage.readStringList());
addSubscriptionFilterVClass(vClasses);
}
break;
case libsumo::FILTER_TYPE_VTYPE: {
myInputStorage.readByte();
std::vector<std::string> vTypesVector = myInputStorage.readStringList();
std::set<std::string> vTypesSet;
vTypesSet.insert(vTypesVector.begin(), vTypesVector.end());
addSubscriptionFilterVType(vTypesSet);
}
break;
case libsumo::FILTER_TYPE_FIELD_OF_VISION: {
myInputStorage.readByte();
double angle = myInputStorage.readDouble();
addSubscriptionFilterFieldOfVision(angle);
}
break;
case libsumo::FILTER_TYPE_LATERAL_DIST: {
myInputStorage.readByte();
double dist = myInputStorage.readDouble();
addSubscriptionFilterLateralDistance(dist);
}
break;
default:
writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_NOTIMPLEMENTED,
"'" + toString(filterType) + "' is no valid filter type code.");
success = false;
}
if (success) {
writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_OK, "");
}
return success;
}
void
TraCIServer::removeFilters() {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Removing filters" << std::endl;
#endif
myLastContextSubscription->activeFilters = libsumo::SUBS_FILTER_NONE;
}
void
TraCIServer::addSubscriptionFilterLanes(std::vector<int> lanes) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding lane filter (lanes=" << toString(lanes) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LANES;
myLastContextSubscription->filterLanes = lanes;
}
void
TraCIServer::addSubscriptionFilterNoOpposite() {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding no opposite filter" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_NOOPPOSITE;
}
void
TraCIServer::addSubscriptionFilterDownstreamDistance(double dist) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding downstream dist filter (dist=" << toString(dist) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_DOWNSTREAM_DIST;
myLastContextSubscription->filterDownstreamDist = dist;
}
void
TraCIServer::addSubscriptionFilterUpstreamDistance(double dist) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding upstream dist filter (dist=" << toString(dist) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_UPSTREAM_DIST;
myLastContextSubscription->filterUpstreamDist = dist;
}
void
TraCIServer::addSubscriptionFilterLeadFollow() {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding Lead/Follow-maneuver filter" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LEAD_FOLLOW;
}
void
TraCIServer::addSubscriptionFilterTurn(double dist) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding turn-maneuver filter" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_TURN;
myLastContextSubscription->filterFoeDistToJunction = dist;
}
void
TraCIServer::addSubscriptionFilterVClass(SVCPermissions vClasses) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding vClass filter (vClasses=" << toString(vClasses) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VCLASS;
myLastContextSubscription->filterVClasses = vClasses;
}
void
TraCIServer::addSubscriptionFilterVType(std::set<std::string> vTypes) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding vType filter (vTypes=" << toString(vTypes) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VTYPE;
myLastContextSubscription->filterVTypes = vTypes;
}
void
TraCIServer::addSubscriptionFilterFieldOfVision(double openingAngle) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding FieldOfVision filter (openingAngle=" << toString(openingAngle) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_FIELD_OF_VISION;
myLastContextSubscription->filterFieldOfVisionOpeningAngle = openingAngle;
}
void
TraCIServer::addSubscriptionFilterLateralDistance(double dist) {
#ifdef DEBUG_SUBSCRIPTION_FILTERS
std::cout << "Adding lateral dist filter (dist=" << toString(dist) << ")" << std::endl;
#endif
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LATERAL_DIST;
myLastContextSubscription->filterLateralDist = dist;
}
void
TraCIServer::writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg) {
if (tempMsg.size() < 254) {
outputStorage.writeUnsignedByte(1 + (int)tempMsg.size());
} else {
outputStorage.writeUnsignedByte(0);
outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
}
outputStorage.writeStorage(tempMsg);
}
void
TraCIServer::writePositionVector(tcpip::Storage& outputStorage, const libsumo::TraCIPositionVector& shape) {
outputStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
if (shape.value.size() < 256) {
outputStorage.writeUnsignedByte((int)shape.value.size());
} else {
outputStorage.writeUnsignedByte(0);
outputStorage.writeInt((int)shape.value.size());
}
for (const libsumo::TraCIPosition& pos : shape.value) {
outputStorage.writeDouble(pos.x);
outputStorage.writeDouble(pos.y);
}
}
bool
TraCIServer::readTypeCheckingDouble(tcpip::Storage& inputStorage, double& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLE) {
return false;
}
into = inputStorage.readDouble();
return true;
}
bool
TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRING) {
return false;
}
into = inputStorage.readString();
return true;
}
bool
TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRINGLIST) {
return false;
}
into = inputStorage.readStringList();
return true;
}
bool
TraCIServer::readTypeCheckingDoubleList(tcpip::Storage& inputStorage, std::vector<double>& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLELIST) {
return false;
}
into = inputStorage.readDoubleList();
return true;
}
bool
TraCIServer::readTypeCheckingColor(tcpip::Storage& inputStorage, libsumo::TraCIColor& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_COLOR) {
return false;
}
into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
return true;
}
bool
TraCIServer::readTypeCheckingPosition2D(tcpip::Storage& inputStorage, libsumo::TraCIPosition& into) {
if (inputStorage.readUnsignedByte() != libsumo::POSITION_2D) {
return false;
}
into.x = inputStorage.readDouble();
into.y = inputStorage.readDouble();
into.z = 0;
return true;
}
bool
TraCIServer::readTypeCheckingByte(tcpip::Storage& inputStorage, int& into) {
if (inputStorage.readByte() != libsumo::TYPE_BYTE) {
return false;
}
into = inputStorage.readByte();
return true;
}
bool
TraCIServer::readTypeCheckingUnsignedByte(tcpip::Storage& inputStorage, int& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_UBYTE) {
return false;
}
into = inputStorage.readUnsignedByte();
return true;
}
bool
TraCIServer::readTypeCheckingPolygon(tcpip::Storage& inputStorage, PositionVector& into) {
if (inputStorage.readUnsignedByte() != libsumo::TYPE_POLYGON) {
return false;
}
into.clear();
int size = inputStorage.readUnsignedByte();
if (size == 0) {
size = inputStorage.readInt();
}
PositionVector shape;
for (int i = 0; i < size; ++i) {
double x = inputStorage.readDouble();
double y = inputStorage.readDouble();
if (std::isnan(x) || std::isnan(y)) {
throw libsumo::TraCIException("NaN-Value in shape.");
}
into.push_back(Position(x, y));
}
return true;
}
void
TraCIServer::stateLoaded(SUMOTime targetTime) {
myTargetTime = targetTime;
for (auto& s : mySockets) {
s.second->targetTime = targetTime;
s.second->executeMove = false;
for (auto& stateChange : s.second->vehicleStateChanges) {
stateChange.second.clear();
}
for (auto& stateChange : s.second->transportableStateChanges) {
stateChange.second.clear();
}
}
mySubscriptions.clear();
mySubscriptionCache.reset();
}
bool
TraCIServer::centralObject(const libsumo::Subscription& s, const std::string& objID) {
return (s.id == objID && s.commandId + 32 == s.contextDomain);
}