SUMO - Simulation of Urban MObility

TraCIServer.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00010 /****************************************************************************/
00011 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00012 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors
00013 /****************************************************************************/
00014 //
00015 //   This program is free software; you can redistribute it and/or modify
00016 //   it under the terms of the GNU General Public License as published by
00017 //   the Free Software Foundation; either version 2 of the License, or
00018 //   (at your option) any later version.
00019 //
00020 /****************************************************************************/
00021 
00022 // ===========================================================================
00023 // included modules
00024 // ===========================================================================
00025 #ifdef _MSC_VER
00026 #include <windows_config.h>
00027 #else
00028 #include <config.h>
00029 #endif
00030 
00031 #ifdef HAVE_VERSION_H
00032 #include <version.h>
00033 #endif
00034 
00035 #ifndef NO_TRACI
00036 
00037 #ifdef HAVE_PYTHON
00038 #include <Python.h>
00039 #endif
00040 
00041 #include <string>
00042 #include <map>
00043 #include <iostream>
00044 #include <foreign/tcpip/socket.h>
00045 #include <foreign/tcpip/storage.h>
00046 #include <utils/common/SUMOTime.h>
00047 #include <utils/common/DijkstraRouterTT.h>
00048 #include <utils/common/NamedObjectCont.h>
00049 #include <utils/common/RandHelper.h>
00050 #include <utils/common/MsgHandler.h>
00051 #include <utils/common/HelpersHBEFA.h>
00052 #include <utils/common/HelpersHarmonoise.h>
00053 #include <utils/common/SUMOVehicleParameter.h>
00054 #include <utils/shapes/PointOfInterest.h>
00055 #include <utils/shapes/ShapeContainer.h>
00056 #include <utils/shapes/Polygon.h>
00057 #include <utils/xml/XMLSubSys.h>
00058 #include <microsim/MSNet.h>
00059 #include <microsim/MSVehicleControl.h>
00060 #include <microsim/MSVehicle.h>
00061 #include <microsim/MSEdge.h>
00062 #include <microsim/MSJunctionControl.h>
00063 #include <microsim/MSJunction.h>
00064 #include <microsim/MSEdgeControl.h>
00065 #include <microsim/MSLane.h>
00066 #include <microsim/MSGlobals.h>
00067 #include <microsim/traffic_lights/MSTLLogicControl.h>
00068 #include "TraCIConstants.h"
00069 #include "TraCIServer.h"
00070 #include "TraCIServerAPI_InductionLoop.h"
00071 #include "TraCIServerAPI_Junction.h"
00072 #include "TraCIServerAPI_Lane.h"
00073 #include "TraCIServerAPI_MeMeDetector.h"
00074 #include "TraCIServerAPI_TLS.h"
00075 #include "TraCIServerAPI_Vehicle.h"
00076 #include "TraCIServerAPI_VehicleType.h"
00077 #include "TraCIServerAPI_Route.h"
00078 #include "TraCIServerAPI_POI.h"
00079 #include "TraCIServerAPI_Polygon.h"
00080 #include "TraCIServerAPI_Edge.h"
00081 #include "TraCIServerAPI_Simulation.h"
00082 
00083 #ifdef CHECK_MEMORY_LEAKS
00084 #include <foreign/nvwa/debug_new.h>
00085 #endif // CHECK_MEMORY_LEAKS
00086 
00087 
00088 // ===========================================================================
00089 // used namespaces
00090 // ===========================================================================
00091 namespace traci {
00092 
00093 // ===========================================================================
00094 // static member definitions
00095 // ===========================================================================
00096 TraCIServer* TraCIServer::myInstance = 0;
00097 bool TraCIServer::myDoCloseConnection = false;
00098 
00099 
00100 // ===========================================================================
00101 // method definitions
00102 // ===========================================================================
00103 
00104 void
00105 TraCIServer::openSocket(const std::map<int, CmdExecutor> &execs) {
00106     if (myInstance == 0) {
00107         if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
00108             myInstance = new traci::TraCIServer(OptionsCont::getOptions().getInt("remote-port"));
00109             for (std::map<int, CmdExecutor>::const_iterator i=execs.begin(); i!=execs.end(); ++i) {
00110                 myInstance->myExecutors[i->first] = i->second;
00111             }
00112         }
00113     }
00114 }
00115 
00116 /*****************************************************************************/
00117 
00118 TraCIServer::TraCIServer(int port)
00119     : mySocket(0), myTargetTime(0), myDoingSimStep(false), myHaveWarnedDeprecation(false), myAmEmbedded(port == 0) {
00120     myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
00121     myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
00122     myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
00123     myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
00124     myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
00125     myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
00126     MSNet::getInstance()->addVehicleStateListener(this);
00127 
00128     myExecutors[CMD_GET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processGet;
00129     myExecutors[CMD_GET_MULTI_ENTRY_EXIT_DETECTOR_VARIABLE] = &TraCIServerAPI_MeMeDetector::processGet;
00130     myExecutors[CMD_GET_TL_VARIABLE] = &TraCIServerAPI_TLS::processGet;
00131     myExecutors[CMD_SET_TL_VARIABLE] = &TraCIServerAPI_TLS::processSet;
00132     myExecutors[CMD_GET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processGet;
00133     myExecutors[CMD_SET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processSet;
00134     myExecutors[CMD_GET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processGet;
00135     myExecutors[CMD_SET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processSet;
00136     myExecutors[CMD_GET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processGet;
00137     myExecutors[CMD_SET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processSet;
00138     myExecutors[CMD_GET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processGet;
00139     myExecutors[CMD_SET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processSet;
00140     myExecutors[CMD_GET_POI_VARIABLE] = &TraCIServerAPI_POI::processGet;
00141     myExecutors[CMD_SET_POI_VARIABLE] = &TraCIServerAPI_POI::processSet;
00142     myExecutors[CMD_GET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processGet;
00143     myExecutors[CMD_SET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processSet;
00144     myExecutors[CMD_GET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processGet;
00145     myExecutors[CMD_GET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processGet;
00146     myExecutors[CMD_SET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processSet;
00147     myExecutors[CMD_GET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processGet;
00148 
00149     myDoCloseConnection = false;
00150 
00151     // display warning if internal lanes are not used
00152     if (!MSGlobals::gUsingInternalLanes) {
00153         WRITE_WARNING("Starting TraCI without using internal lanes!");
00154         MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
00155         MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
00156     }
00157 
00158     if (!myAmEmbedded) {
00159         try {
00160             WRITE_MESSAGE("***Starting server on port " + toString(port) + " ***");
00161             mySocket = new tcpip::Socket(port);
00162             mySocket->accept();
00163             // When got here, a client has connected
00164         } catch (tcpip::SocketException& e) {
00165             throw ProcessError(e.what());
00166         }
00167     }
00168 }
00169 
00170 /*****************************************************************************/
00171 
00172 TraCIServer::~TraCIServer() {
00173     MSNet::getInstance()->removeVehicleStateListener(this);
00174     if (mySocket != NULL) {
00175         mySocket->close();
00176         delete mySocket;
00177     }
00178 }
00179 
00180 /*****************************************************************************/
00181 
00182 void
00183 TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to) {
00184     if (myDoCloseConnection || OptionsCont::getOptions().getInt("remote-port") == 0) {
00185         return;
00186     }
00187     myVehicleStateChanges[to].push_back(vehicle->getID());
00188 }
00189 
00190 /*****************************************************************************/
00191 void
00192 TraCIServer::processCommandsUntilSimStep(SUMOTime step) {
00193     try {
00194         if (myInstance == 0) {
00195             if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
00196                 myInstance = new traci::TraCIServer(OptionsCont::getOptions().getInt("remote-port"));
00197             } else {
00198                 return;
00199             }
00200         }
00201         if (myInstance->myAmEmbedded || step < myInstance->myTargetTime) {
00202             return;
00203         }
00204         // Simulation should run until
00205         // 1. end time reached or
00206         // 2. got CMD_CLOSE or
00207         // 3. Client closes socket connection
00208         if (myInstance->myDoingSimStep) {
00209             myInstance->postProcessSimulationStep2();
00210             myInstance->myDoingSimStep = false;
00211         }
00212         while (!myDoCloseConnection) {
00213             if (!myInstance->myInputStorage.valid_pos()) {
00214                 if (myInstance->myOutputStorage.size() > 0) {
00215                     // send out all answers as one storage
00216                     myInstance->mySocket->sendExact(myInstance->myOutputStorage);
00217                 }
00218                 myInstance->myInputStorage.reset();
00219                 myInstance->myOutputStorage.reset();
00220                 // Read a message
00221                 myInstance->mySocket->receiveExact(myInstance->myInputStorage);
00222             }
00223             while (myInstance->myInputStorage.valid_pos() && !myDoCloseConnection) {
00224                 // dispatch each command
00225                 int cmd = myInstance->dispatchCommand();
00226                 if (cmd==CMD_SIMSTEP2) {
00227                     myInstance->myDoingSimStep = true;
00228                     for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i=myInstance->myVehicleStateChanges.begin(); i!=myInstance->myVehicleStateChanges.end(); ++i) {
00229                         (*i).second.clear();
00230                     }
00231                     return;
00232                 }
00233             }
00234         }
00235         if (myDoCloseConnection && myInstance->myOutputStorage.size() > 0) {
00236             // send out all answers as one storage
00237             myInstance->mySocket->sendExact(myInstance->myOutputStorage);
00238         }
00239         for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i=myInstance->myVehicleStateChanges.begin(); i!=myInstance->myVehicleStateChanges.end(); ++i) {
00240             (*i).second.clear();
00241         }
00242     } catch (std::invalid_argument& e) {
00243         throw ProcessError(e.what());
00244     } catch (TraCIException& e) {
00245         throw ProcessError(e.what());
00246     } catch (tcpip::SocketException& e) {
00247         throw ProcessError(e.what());
00248     }
00249     if (myInstance != NULL) {
00250         delete myInstance;
00251         myInstance = 0;
00252         myDoCloseConnection = true;
00253     }
00254 }
00255 
00256 /*****************************************************************************/
00257 
00258 bool
00259 TraCIServer::wasClosed() {
00260     return myDoCloseConnection;
00261 }
00262 
00263 
00264 void
00265 TraCIServer::close() {
00266     if (myInstance!=0) {
00267         delete myInstance;
00268         myInstance = 0;
00269         myDoCloseConnection = true;
00270     }
00271 }
00272 
00273 /*****************************************************************************/
00274 
00275 #ifdef HAVE_PYTHON
00276 // ===========================================================================
00277 // python functions (traciemb module)
00278 // ===========================================================================
00279 static PyObject*
00280 traciemb_execute(PyObject* self, PyObject* args) {
00281     const char* msg;
00282     int size;
00283     if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
00284         return NULL;
00285     }
00286     std::string result = traci::TraCIServer::execute(std::string(msg, size));
00287     return Py_BuildValue("s#", result.c_str(), result.size());
00288 }
00289 
00290 static PyMethodDef EmbMethods[] = {
00291     {
00292         "execute", traciemb_execute, METH_VARARGS,
00293         "Execute the given TraCI command and return the result."
00294     },
00295     {NULL, NULL, 0, NULL}
00296 };
00297 
00298 
00299 std::string
00300 TraCIServer::execute(std::string cmd) {
00301     try {
00302         if (myInstance == 0) {
00303             if (!myDoCloseConnection) {
00304                 myInstance = new traci::TraCIServer();
00305             } else {
00306                 return "";
00307             }
00308         }
00309         myInstance->myInputStorage.reset();
00310         myInstance->myOutputStorage.reset();
00311         for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
00312             myInstance->myInputStorage.writeChar(*i);
00313         }
00314         myInstance->dispatchCommand();
00315         return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
00316     } catch (std::invalid_argument& e) {
00317         throw ProcessError(e.what());
00318     } catch (TraCIException& e) {
00319         throw ProcessError(e.what());
00320     } catch (tcpip::SocketException& e) {
00321         throw ProcessError(e.what());
00322     }
00323 }
00324 
00325 
00326 void
00327 TraCIServer::runEmbedded(std::string pyFile) {
00328     PyObject* pName, *pModule;
00329     Py_Initialize();
00330     Py_InitModule("traciemb", EmbMethods);
00331     if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
00332         FILE* pFile = fopen(pyFile.c_str(), "r");
00333         PyRun_SimpleFile(pFile, pyFile.c_str());
00334         fclose(pFile);
00335     } else {
00336         pName = PyString_FromString(pyFile.c_str());
00337         /* Error checking of pName left out */
00338         pModule = PyImport_Import(pName);
00339         Py_DECREF(pName);
00340         if (pModule == NULL) {
00341             PyErr_Print();
00342             throw ProcessError("Failed to load \"" + pyFile + "\"!");
00343         }
00344     }
00345     Py_Finalize();
00346 }
00347 #endif
00348 
00349 /*****************************************************************************/
00350 
00351 int
00352 TraCIServer::dispatchCommand() {
00353     unsigned int commandStart = myInputStorage.position();
00354     unsigned int commandLength = myInputStorage.readUnsignedByte();
00355     if (commandLength==0) {
00356         commandLength = myInputStorage.readInt();
00357     }
00358 
00359     int commandId = myInputStorage.readUnsignedByte();
00360     bool success = false;
00361     // dispatch commands
00362     if (myExecutors.find(commandId)!=myExecutors.end()) {
00363         success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
00364     } else {
00365         switch (commandId) {
00366         case CMD_GETVERSION:
00367             success = commandGetVersion();
00368             break;
00369         case CMD_SIMSTEP2: {
00370             SUMOTime nextT = myInputStorage.readInt();
00371             success = true;
00372             if (nextT!=0) {
00373                 myTargetTime = nextT;
00374             } else {
00375                 myTargetTime += DELTA_T;
00376             }
00377             if (myAmEmbedded) {
00378                 MSNet::getInstance()->simulationStep();
00379                 postProcessSimulationStep2();
00380             }
00381             return commandId;
00382         }
00383         case CMD_CLOSE:
00384             success = commandCloseConnection();
00385             break;
00386         case CMD_POSITIONCONVERSION: {
00387             if (!myHaveWarnedDeprecation) {
00388                 WRITE_WARNING("Using old TraCI API, please update your client!");
00389                 myHaveWarnedDeprecation = true;
00390             }
00391             tcpip::Storage tempMsg;
00392             success = TraCIServerAPI_Simulation::commandPositionConversion(*this, myInputStorage, tempMsg, CMD_POSITIONCONVERSION);
00393             if (success) {
00394                 writeStatusCmd(CMD_POSITIONCONVERSION, RTYPE_OK, "");
00395                 myOutputStorage.writeStorage(tempMsg);
00396             }
00397         }
00398         break;
00399         case CMD_ADDVEHICLE:
00400             if (!myHaveWarnedDeprecation) {
00401                 WRITE_WARNING("Using old TraCI API, please update your client!");
00402                 myHaveWarnedDeprecation = true;
00403             }
00404             success = commandAddVehicle();
00405             break;
00406         case CMD_DISTANCEREQUEST: {
00407             if (!myHaveWarnedDeprecation) {
00408                 WRITE_WARNING("Using old TraCI API, please update your client!");
00409                 myHaveWarnedDeprecation = true;
00410             }
00411             tcpip::Storage tempMsg;
00412             success = TraCIServerAPI_Simulation::commandDistanceRequest(*this, myInputStorage, tempMsg, CMD_DISTANCEREQUEST);
00413             if (success) {
00414                 writeStatusCmd(CMD_DISTANCEREQUEST, RTYPE_OK, "");
00415                 myOutputStorage.writeStorage(tempMsg);
00416             }
00417         }
00418         break;
00419         case CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE:
00420         case CMD_SUBSCRIBE_MULTI_ENTRY_EXIT_DETECTOR_VARIABLE:
00421         case CMD_SUBSCRIBE_TL_VARIABLE:
00422         case CMD_SUBSCRIBE_LANE_VARIABLE:
00423         case CMD_SUBSCRIBE_VEHICLE_VARIABLE:
00424         case CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE:
00425         case CMD_SUBSCRIBE_ROUTE_VARIABLE:
00426         case CMD_SUBSCRIBE_POI_VARIABLE:
00427         case CMD_SUBSCRIBE_POLYGON_VARIABLE:
00428         case CMD_SUBSCRIBE_JUNCTION_VARIABLE:
00429         case CMD_SUBSCRIBE_EDGE_VARIABLE:
00430         case CMD_SUBSCRIBE_SIM_VARIABLE:
00431         case CMD_SUBSCRIBE_GUI_VARIABLE:
00432             success = addSubscription(commandId);
00433             break;
00434         default:
00435             writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
00436         }
00437     }
00438     if (!success) {
00439         while (myInputStorage.valid_pos() && myInputStorage.position() < commandStart + commandLength) {
00440             myInputStorage.readChar();
00441         }
00442     }
00443     if (myInputStorage.position() != commandStart + commandLength) {
00444         std::ostringstream msg;
00445         msg << "Wrong position in requestMessage after dispatching command.";
00446         msg << " Expected command length was " << commandLength;
00447         msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
00448         writeStatusCmd(commandId, RTYPE_ERR, msg.str());
00449         myDoCloseConnection = true;
00450     }
00451     return commandId;
00452 }
00453 
00454 /*****************************************************************************/
00455 
00456 void
00457 TraCIServer::postProcessSimulationStep2() {
00458     SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
00459     writeStatusCmd(CMD_SIMSTEP2, RTYPE_OK, "");
00460     int noActive = 0;
00461     for (std::vector<Subscription>::iterator i=mySubscriptions.begin(); i!=mySubscriptions.end();) {
00462         const Subscription& s = *i;
00463         bool isArrivedVehicle = (s.commandId == CMD_SUBSCRIBE_VEHICLE_VARIABLE) && (find(myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED].begin(), myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED].end(), s.id) != myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED].end());
00464         if ((s.endTime<t) || isArrivedVehicle) {
00465             i = mySubscriptions.erase(i);
00466             continue;
00467         }
00468         ++i;
00469         if (s.beginTime>t) {
00470             continue;
00471         }
00472         ++noActive;
00473     }
00474     myOutputStorage.writeInt(noActive);
00475     for (std::vector<Subscription>::iterator i=mySubscriptions.begin(); i!=mySubscriptions.end(); ++i) {
00476         const Subscription& s = *i;
00477         if (s.beginTime>t) {
00478             continue;
00479         }
00480         tcpip::Storage into;
00481         std::string errors;
00482         processSingleSubscription(s, into, errors);
00483         myOutputStorage.writeStorage(into);
00484     }
00485 }
00486 
00487 /*****************************************************************************/
00488 
00489 bool
00490 TraCIServer::commandGetVersion() {
00491 
00492     std::string sumoVersion = VERSION_STRING;
00493 
00494     // Prepare response
00495     tcpip::Storage answerTmp;
00496 
00497     answerTmp.writeInt(TRACI_VERSION);
00498     answerTmp.writeString(std::string("SUMO ") + sumoVersion);
00499 
00500     // When we get here, the response is stored in answerTmp -> put into myOutputStorage
00501     writeStatusCmd(CMD_GETVERSION, RTYPE_OK, "");
00502 
00503     // command length
00504     myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
00505     // command type
00506     myOutputStorage.writeUnsignedByte(CMD_GETVERSION);
00507     // and the parameter dependant part
00508     myOutputStorage.writeStorage(answerTmp);
00509     return true;
00510 }
00511 
00512 /*****************************************************************************/
00513 
00514 bool
00515 TraCIServer::commandCloseConnection() {
00516     myDoCloseConnection = true;
00517     // write answer
00518     writeStatusCmd(CMD_CLOSE, RTYPE_OK, "Goodbye");
00519     return true;
00520 }
00521 
00522 /*****************************************************************************/
00523 
00524 bool
00525 TraCIServer::commandAddVehicle() {
00526 
00527     // read parameters
00528     std::string vehicleId = myInputStorage.readString();
00529     std::string vehicleTypeId = myInputStorage.readString();
00530     std::string routeId = myInputStorage.readString();
00531     std::string laneId = myInputStorage.readString();
00532     SUMOReal insertionPosition = myInputStorage.readFloat();
00533     SUMOReal insertionSpeed = myInputStorage.readFloat();
00534 
00535     // find vehicleType
00536     MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(vehicleTypeId);
00537     if (!vehicleType) {
00538         writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid vehicleTypeId: '"+vehicleTypeId+"'");
00539         return false;
00540     }
00541 
00542     // find route
00543     const MSRoute* route = MSRoute::dictionary(routeId);
00544     if (!route) {
00545         writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid routeId: '"+routeId+"'");
00546         return false;
00547     }
00548 
00549     // find lane
00550     MSLane* lane;
00551     if (laneId != "") {
00552         lane = MSLane::dictionary(laneId);
00553         if (!lane) {
00554             writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid laneId: '"+laneId+"'");
00555             return false;
00556         }
00557     } else {
00558         lane = route->getEdges()[0]->getLanes()[0];
00559         if (!lane) {
00560             writeStatusCmd(CMD_STOP, RTYPE_ERR, "Could not find first lane of first edge in routeId '"+routeId+"'");
00561             return false;
00562         }
00563     }
00564 
00565     if (&lane->getEdge()!=*route->begin()) {
00566         writeStatusCmd(CMD_STOP, RTYPE_ERR, "The route must start at the edge the lane starts at.");
00567         return false;
00568     }
00569 
00570     // build vehicle
00571     SUMOVehicleParameter* vehicleParams = new SUMOVehicleParameter();
00572     vehicleParams->id = vehicleId;
00573     vehicleParams->depart = MSNet::getInstance()->getCurrentTimeStep()+1;
00574     MSVehicle* vehicle = static_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(vehicleParams, route, vehicleType));
00575     if (vehicle == NULL) {
00576         writeStatusCmd(CMD_STOP, RTYPE_ERR, "Could not build vehicle");
00577         return false;
00578     }
00579 
00580     // calculate speed
00581     float clippedInsertionSpeed;
00582     if (insertionSpeed<0) {
00583         clippedInsertionSpeed = (float) MIN2(lane->getMaxSpeed(), vehicle->getMaxSpeed());
00584     } else {
00585         clippedInsertionSpeed = (float) MIN3(lane->getMaxSpeed(), vehicle->getMaxSpeed(), insertionSpeed);
00586     }
00587 
00588     // insert vehicle into the dictionary
00589     if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
00590         writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Could not add vehicle to VehicleControl");
00591         return false;
00592     }
00593 
00594     // try to emit
00595     if (!lane->isInsertionSuccess(vehicle, clippedInsertionSpeed, insertionPosition, true)) {
00596         MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle);
00597         writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Could not insert vehicle");
00598         return false;
00599     }
00600 
00601     // exec callback
00602     vehicle->onDepart();
00603 
00604     // create a reply message
00605     writeStatusCmd(CMD_ADDVEHICLE, RTYPE_OK, "");
00606 
00607     return true;
00608 }
00609 
00610 
00611 /*****************************************************************************/
00612 
00613 void
00614 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
00615     writeStatusCmd(commandId, status, description, myOutputStorage);
00616 }
00617 
00618 
00619 void
00620 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
00621     if (status == RTYPE_ERR) {
00622         WRITE_ERROR("Answered with error to command " + toString(commandId) + ": " + description);
00623     } else if (status == RTYPE_NOTIMPLEMENTED) {
00624         WRITE_ERROR("Requested command not implemented (" + toString(commandId) + "): " + description);
00625     }
00626     outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
00627     outputStorage.writeUnsignedByte(commandId); // command type
00628     outputStorage.writeUnsignedByte(status); // status
00629     outputStorage.writeString(description); // description
00630 }
00631 
00632 /*****************************************************************************/
00633 
00634 bool
00635 TraCIServer::addSubscription(int commandId) {
00636     SUMOTime beginTime = myInputStorage.readInt();
00637     SUMOTime endTime = myInputStorage.readInt();
00638     std::string id = myInputStorage.readString();
00639     int no = myInputStorage.readUnsignedByte();
00640     std::vector<int> variables;
00641     for (int i=0; i<no; ++i) {
00642         variables.push_back(myInputStorage.readUnsignedByte());
00643     }
00644     // check subscribe/unsubscribe
00645     bool ok = true;
00646     if (variables.size()==0) {
00647         // try unsubscribe
00648         bool found = false;
00649         for (std::vector<Subscription>::iterator j=mySubscriptions.begin(); j!=mySubscriptions.end();) {
00650             if ((*j).id==id&&(*j).commandId==commandId) {
00651                 j = mySubscriptions.erase(j);
00652                 found = true;
00653                 continue;
00654             }
00655             ++j;
00656         }
00657         if (found) {
00658             writeStatusCmd(commandId, RTYPE_OK, "");
00659         } else {
00660             writeStatusCmd(commandId, RTYPE_OK, "The subscription to remove was not found.");
00661         }
00662     } else {
00663         // process subscription
00664         Subscription s(commandId, id, variables, beginTime, endTime);
00665         tcpip::Storage writeInto;
00666         std::string errors;
00667         if (s.endTime<MSNet::getInstance()->getCurrentTimeStep()) {
00668             processSingleSubscription(s, writeInto, errors);
00669             writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
00670         } else {
00671             if (processSingleSubscription(s, writeInto, errors)) {
00672                 mySubscriptions.push_back(s);
00673                 writeStatusCmd(s.commandId, RTYPE_OK, "");
00674             } else {
00675                 writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
00676             }
00677         }
00678         myOutputStorage.writeStorage(writeInto);
00679     }
00680     return ok;
00681 }
00682 
00683 
00684 bool
00685 TraCIServer::processSingleSubscription(const Subscription& s, tcpip::Storage& writeInto,
00686                                        std::string& errors) {
00687     bool ok = true;
00688     tcpip::Storage outputStorage;
00689     for (std::vector<int>::const_iterator i=s.variables.begin(); i!=s.variables.end(); ++i) {
00690         tcpip::Storage message;
00691         message.writeUnsignedByte(*i);
00692         message.writeString(s.id);
00693         tcpip::Storage tmpOutput;
00694         int getId = s.commandId - 0x30;
00695         if (myExecutors.find(getId)!=myExecutors.end()) {
00696             ok &= myExecutors[getId](*this, message, tmpOutput);
00697         } else {
00698             writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
00699             ok = false;
00700         }
00701         // copy response part
00702         if (ok) {
00703             int length = tmpOutput.readUnsignedByte();
00704             while (--length>0) {
00705                 tmpOutput.readUnsignedByte();
00706             }
00707             int lengthLength = 1;
00708             length = tmpOutput.readUnsignedByte();
00709             if (length==0) {
00710                 lengthLength = 5;
00711                 length = tmpOutput.readInt();
00712             }
00713             //read responseType
00714             tmpOutput.readUnsignedByte();
00715             int variable = tmpOutput.readUnsignedByte();
00716             std::string id = tmpOutput.readString();
00717             outputStorage.writeUnsignedByte(variable);
00718             outputStorage.writeUnsignedByte(RTYPE_OK);
00719             length -= (lengthLength+1+4+(int)id.length());
00720             while (--length>0) {
00721                 outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
00722             }
00723         } else {
00724             //read length
00725             tmpOutput.readUnsignedByte();
00726             //read cmd
00727             tmpOutput.readUnsignedByte();
00728             //read status
00729             tmpOutput.readUnsignedByte();
00730             std::string msg = tmpOutput.readString();
00731             outputStorage.writeUnsignedByte(*i);
00732             outputStorage.writeUnsignedByte(RTYPE_ERR);
00733             outputStorage.writeUnsignedByte(TYPE_STRING);
00734             outputStorage.writeString(msg);
00735             errors = errors + msg;
00736         }
00737     }
00738     writeInto.writeUnsignedByte(0); // command length -> extended
00739     writeInto.writeInt((1+4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size());
00740     writeInto.writeUnsignedByte(s.commandId + 0x10);
00741     writeInto.writeString(s.id);
00742     writeInto.writeUnsignedByte((int)(s.variables.size()));
00743     writeInto.writeStorage(outputStorage);
00744     return ok;
00745 }
00746 
00747 void
00748 TraCIServer::writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg) {
00749     if (tempMsg.size()<254) {
00750         outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
00751     } else {
00752         outputStorage.writeUnsignedByte(0); // command length -> extended
00753         outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
00754     }
00755     outputStorage.writeStorage(tempMsg);
00756 }
00757 
00758 }
00759 
00760 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines