LCOV - code coverage report
Current view: top level - src/libtraci - Connection.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.1 % 303 285
Test Date: 2025-12-06 15:35:27 Functions: 100.0 % 14 14

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    Connection.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Mario Krumnow
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Michael Behrisch
      19              : /// @date    30.05.2012
      20              : ///
      21              : // C++ TraCI client API implementation
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <thread>
      26              : #include <chrono>
      27              : #include <array>
      28              : #include <libsumo/StorageHelper.h>
      29              : #include <libsumo/TraCIDefs.h>
      30              : #include "Connection.h"
      31              : 
      32              : 
      33              : namespace libtraci {
      34              : // ===========================================================================
      35              : // static member initializations
      36              : // ===========================================================================
      37              : Connection* Connection::myActive = nullptr;
      38              : std::map<const std::string, Connection*> Connection::myConnections;
      39              : 
      40              : 
      41              : // ===========================================================================
      42              : // member method definitions
      43              : // ===========================================================================
      44          786 : Connection::Connection(const std::string& host, int port, int numRetries, const std::string& label, FILE* const pipe) :
      45         2361 :     myLabel(label), myProcessPipe(pipe), myProcessReader(nullptr), mySocket(host, port) {
      46          786 :     if (pipe != nullptr) {
      47          610 :         myProcessReader = new std::thread(&Connection::readOutput, this);
      48              :     }
      49         1518 :     for (int i = 0; i <= numRetries; i++) {
      50              :         try {
      51         1518 :             mySocket.connect();
      52              :             break;
      53          735 :         } catch (tcpip::SocketException& e) {
      54          735 :             mySocket.close();
      55          735 :             if (i == numRetries) {
      56            3 :                 close();
      57            6 :                 throw libsumo::FatalTraCIError("Could not connect in " + toString(numRetries + 1) + " tries");
      58              :             }
      59         1464 :             std::cout << "Could not connect to TraCI server at " << host << ":" << port << " " << e.what() << std::endl;
      60              :             std::cout << " Retrying in 1 second" << std::endl;
      61          732 :             std::this_thread::sleep_for(std::chrono::seconds(1));
      62          735 :         }
      63              :     }
      64          792 : }
      65              : 
      66              : 
      67              : void
      68          610 : Connection::readOutput() {
      69              :     std::array<char, 256> buffer;
      70              :     bool errout = false;
      71         1775 :     while (fgets(buffer.data(), (int)buffer.size(), myProcessPipe) != nullptr) {
      72         1165 :         std::stringstream result;
      73         1165 :         result << buffer.data();
      74              :         std::string line;
      75         2330 :         while (std::getline(result, line)) {
      76         1165 :             if ((errout && (line.empty() || line[0] == ' ')) || line.compare(0, 6, "Error:") == 0 || line.compare(0, 8, "Warning:") == 0) {
      77              :                 std::cerr << line << std::endl;
      78              :                 errout = true;
      79              :             } else {
      80              :                 std::cout << line << std::endl;
      81              :                 errout = false;
      82              :             }
      83              :         }
      84         1165 :     }
      85          610 : }
      86              : 
      87              : 
      88              : void
      89          782 : Connection::close() {
      90          782 :     if (mySocket.has_client_connection()) {
      91          779 :         std::unique_lock<std::mutex> lock{ myMutex };
      92          779 :         tcpip::Storage outMsg;
      93              :         // command length
      94          779 :         outMsg.writeUnsignedByte(1 + 1);
      95              :         // command id
      96          779 :         outMsg.writeUnsignedByte(libsumo::CMD_CLOSE);
      97          779 :         mySocket.sendExact(outMsg);
      98              : 
      99          779 :         tcpip::Storage inMsg;
     100              :         std::string acknowledgement;
     101          779 :         check_resultState(inMsg, libsumo::CMD_CLOSE, false, &acknowledgement);
     102          779 :         mySocket.close();
     103          779 :     }
     104          782 :     if (myProcessReader != nullptr) {
     105          610 :         myProcessReader->join();
     106         1220 :         delete myProcessReader;
     107          610 :         myProcessReader = nullptr;
     108              : #ifdef WIN32
     109              :         _pclose(myProcessPipe);
     110              : #else
     111          610 :         pclose(myProcessPipe);
     112              : #endif
     113              :     }
     114          782 :     myConnections.erase(myLabel);
     115          782 :     delete myActive;
     116          782 :     myActive = nullptr;
     117          782 : }
     118              : 
     119              : 
     120              : void
     121       139192 : Connection::simulationStep(double time) {
     122       139192 :     std::unique_lock<std::mutex> lock{myMutex};
     123       139192 :     tcpip::Storage outMsg;
     124              :     // command length
     125       139192 :     outMsg.writeUnsignedByte(1 + 1 + 8);
     126              :     // command id
     127       139192 :     outMsg.writeUnsignedByte(libsumo::CMD_SIMSTEP);
     128       139192 :     outMsg.writeDouble(time);
     129              :     // send request message
     130       139192 :     mySocket.sendExact(outMsg);
     131              : 
     132       139192 :     tcpip::Storage inMsg;
     133       139192 :     check_resultState(inMsg, libsumo::CMD_SIMSTEP);
     134              :     mySubscriptionResults.clear();
     135              :     myContextSubscriptionResults.clear();
     136       139189 :     int numSubs = inMsg.readInt();
     137       187478 :     while (numSubs-- > 0) {
     138        48289 :         const int responseID = check_commandGetResult(inMsg, 0, -1, true);
     139        48289 :         if ((responseID >= libsumo::RESPONSE_SUBSCRIBE_INDUCTIONLOOP_VARIABLE && responseID <= libsumo::RESPONSE_SUBSCRIBE_BUSSTOP_VARIABLE) ||
     140        48289 :                 (responseID >= libsumo::RESPONSE_SUBSCRIBE_PARKINGAREA_VARIABLE && responseID <= libsumo::RESPONSE_SUBSCRIBE_OVERHEADWIRE_VARIABLE)) {
     141        18817 :             readVariableSubscription(responseID, inMsg);
     142              :         } else {
     143        29472 :             readContextSubscription(responseID, inMsg);
     144              :         }
     145              :     }
     146       278384 : }
     147              : 
     148              : 
     149              : void
     150          119 : Connection::setOrder(int order) {
     151          119 :     std::unique_lock<std::mutex> lock{ myMutex };
     152          119 :     tcpip::Storage outMsg;
     153              :     // command length
     154          119 :     outMsg.writeUnsignedByte(1 + 1 + 4);
     155              :     // command id
     156          119 :     outMsg.writeUnsignedByte(libsumo::CMD_SETORDER);
     157              :     // client index
     158          119 :     outMsg.writeInt(order);
     159          119 :     mySocket.sendExact(outMsg);
     160              : 
     161          119 :     tcpip::Storage inMsg;
     162          119 :     check_resultState(inMsg, libsumo::CMD_SETORDER);
     163          238 : }
     164              : 
     165              : 
     166              : void
     167       701132 : Connection::createCommand(int cmdID, int varID, const std::string* const objID, tcpip::Storage* add) const {
     168       701132 :     if (!mySocket.has_client_connection()) {
     169            0 :         throw libsumo::FatalTraCIError("Connection already closed.");
     170              :     }
     171       701132 :     myOutput.reset();
     172              :     // command length
     173              :     int length = 1 + 1;
     174       701132 :     if (varID >= 0) {
     175              :         length += 1;
     176       700342 :         if (objID != nullptr) {
     177       700156 :             length += 4 + (int)objID->length();
     178              :         }
     179              :     }
     180       701132 :     if (add != nullptr) {
     181        42371 :         length += (int)add->size();
     182              :     }
     183       701132 :     if (length <= 255) {
     184       701123 :         myOutput.writeUnsignedByte(length);
     185              :     } else {
     186            9 :         myOutput.writeUnsignedByte(0);
     187            9 :         myOutput.writeInt(length + 4);
     188              :     }
     189       701132 :     myOutput.writeUnsignedByte(cmdID);
     190       701132 :     if (varID >= 0) {
     191       700342 :         myOutput.writeUnsignedByte(varID);
     192       700342 :         if (objID != nullptr) {
     193       700156 :             myOutput.writeString(*objID);
     194              :         }
     195              :     }
     196              :     // additional values
     197       701132 :     if (add != nullptr) {
     198        42371 :         myOutput.writeStorage(*add);
     199              :     }
     200       701132 : }
     201              : 
     202              : 
     203              : void
     204         2682 : Connection::subscribe(int domID, const std::string& objID, double beginTime, double endTime,
     205              :                       int domain, double range, const std::vector<int>& vars, const libsumo::TraCIResults& params) {
     206         2682 :     if (!mySocket.has_client_connection()) {
     207            0 :         throw tcpip::SocketException("Socket is not initialised");
     208              :     }
     209              :     const bool isContext = domain != -1;
     210         2682 :     tcpip::Storage outMsg;
     211         2682 :     outMsg.writeUnsignedByte(domID); // command id
     212         2682 :     outMsg.writeDouble(beginTime);
     213         2682 :     outMsg.writeDouble(endTime);
     214         2682 :     outMsg.writeString(objID);
     215         2682 :     if (isContext) {
     216         1676 :         outMsg.writeUnsignedByte(domain);
     217         1676 :         outMsg.writeDouble(range);
     218              :     }
     219         2682 :     if (vars.size() == 1 && vars.front() == -1) {
     220          512 :         if (domID == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE && !isContext) {
     221              :             // default for vehicles is edge id and lane position
     222            3 :             outMsg.writeUnsignedByte(2);
     223            3 :             outMsg.writeUnsignedByte(libsumo::VAR_ROAD_ID);
     224            3 :             outMsg.writeUnsignedByte(libsumo::VAR_LANEPOSITION);
     225              :         } else {
     226              :             // default for detectors is vehicle number, for all others (and contexts) id list
     227          509 :             outMsg.writeUnsignedByte(1);
     228          509 :             const bool isDetector = domID == libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE
     229          509 :                                     || domID == libsumo::CMD_SUBSCRIBE_LANEAREA_VARIABLE
     230              :                                     || domID == libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE
     231              :                                     || domID == libsumo::CMD_SUBSCRIBE_LANE_VARIABLE
     232              :                                     || domID == libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE;
     233          509 :             outMsg.writeUnsignedByte(isDetector ? libsumo::LAST_STEP_VEHICLE_NUMBER : libsumo::TRACI_ID_LIST);
     234              :         }
     235              :     } else {
     236         2170 :         outMsg.writeUnsignedByte((int)vars.size());
     237         3851 :         for (const int v : vars) {
     238         1681 :             outMsg.writeUnsignedByte(v);
     239              :             const auto& paramEntry = params.find(v);
     240         1681 :             if (paramEntry != params.end()) {
     241          222 :                 outMsg.writeStorage(*libsumo::StorageHelper::toStorage(*paramEntry->second));
     242              :             }
     243              :         }
     244              :     }
     245         2682 :     tcpip::Storage complete;
     246         2682 :     complete.writeUnsignedByte(0);
     247         2682 :     complete.writeInt(5 + (int)outMsg.size());
     248         2682 :     complete.writeStorage(outMsg);
     249         2682 :     std::unique_lock<std::mutex> lock{ myMutex };
     250              :     // send message
     251         2682 :     mySocket.sendExact(complete);
     252              : 
     253         2682 :     tcpip::Storage inMsg;
     254         2682 :     check_resultState(inMsg, domID);
     255         2196 :     if (!vars.empty()) {
     256         1599 :         const int responseID = check_commandGetResult(inMsg, domID);
     257         1599 :         if (isContext) {
     258          632 :             readContextSubscription(responseID, inMsg);
     259              :         } else {
     260          967 :             readVariableSubscription(responseID, inMsg);
     261              :         }
     262              :     }
     263         5850 : }
     264              : 
     265              : 
     266              : void
     267       843904 : Connection::check_resultState(tcpip::Storage& inMsg, int command, bool ignoreCommandId, std::string* acknowledgement) {
     268       843904 :     mySocket.receiveExact(inMsg);
     269              :     int cmdLength;
     270              :     int cmdId;
     271              :     int resultType;
     272              :     int cmdStart;
     273              :     std::string msg;
     274              :     try {
     275       843900 :         cmdStart = inMsg.position();
     276       843900 :         cmdLength = inMsg.readUnsignedByte();
     277       843900 :         cmdId = inMsg.readUnsignedByte();
     278       843900 :         resultType = inMsg.readUnsignedByte();
     279       843900 :         msg = inMsg.readString();
     280            0 :     } catch (std::invalid_argument&) {
     281            0 :         throw libsumo::TraCIException("#Error: an exception was thrown while reading result state message");
     282            0 :     }
     283       843900 :     switch (resultType) {
     284          714 :         case libsumo::RTYPE_ERR:
     285         1428 :             throw libsumo::TraCIException(msg);
     286           49 :         case libsumo::RTYPE_NOTIMPLEMENTED:
     287           98 :             throw libsumo::TraCIException(".. Sent command is not implemented (" + toHex(command) + "), [description: " + msg + "]");
     288       843137 :         case libsumo::RTYPE_OK:
     289       843137 :             if (acknowledgement != nullptr) {
     290         3100 :                 (*acknowledgement) = ".. Command acknowledged (" + toHex(command) + "), [description: " + msg + "]";
     291              :             }
     292              :             break;
     293            0 :         default:
     294            0 :             throw libsumo::TraCIException(".. Answered with unknown result code(" + toHex(resultType) + ") to command(" + toHex(command) + "), [description: " + msg + "]");
     295              :     }
     296       843137 :     if (command != cmdId && !ignoreCommandId) {
     297            0 :         throw libsumo::TraCIException("#Error: received status response to command: " + toHex(cmdId) + " but expected: " + toHex(command));
     298              :     }
     299       843137 :     if ((cmdStart + cmdLength) != (int) inMsg.position()) {
     300            0 :         throw libsumo::TraCIException("#Error: command at position " + toHex(cmdStart) + " has wrong length");
     301              :     }
     302       843137 : }
     303              : 
     304              : 
     305              : int
     306       732460 : Connection::check_commandGetResult(tcpip::Storage& inMsg, int command, int expectedType, bool ignoreCommandId) const {
     307       732460 :     int length = inMsg.readUnsignedByte();
     308       732460 :     if (length == 0) {
     309        61515 :         length = inMsg.readInt();
     310              :     }
     311       732460 :     int cmdId = inMsg.readUnsignedByte();
     312       732460 :     if (!ignoreCommandId && cmdId != (command + 0x10)) {
     313            0 :         throw libsumo::TraCIException("#Error: received response with command id: " + toString(cmdId) + "but expected: " + toString(command + 0x10));
     314              :     }
     315       732460 :     if (expectedType >= 0) {
     316              :         // not called from the TraCITestClient but from within the Connection
     317       682572 :         inMsg.readUnsignedByte(); // variableID
     318       682572 :         inMsg.readString(); // objectID
     319       682572 :         int valueDataType = inMsg.readUnsignedByte();
     320       682572 :         if (valueDataType != expectedType) {
     321            0 :             throw libsumo::TraCIException("Expected " + toString(expectedType) + " but got " + toString(valueDataType));
     322              :         }
     323              :     }
     324       732460 :     return cmdId;
     325              : }
     326              : 
     327              : 
     328              : tcpip::Storage&
     329       700946 : Connection::doCommand(int command, int var, const std::string& id, tcpip::Storage* add, int expectedType) {
     330       700946 :     createCommand(command, var, &id, add);
     331       700946 :     mySocket.sendExact(myOutput);
     332       700946 :     myInput.reset();
     333       700946 :     check_resultState(myInput, command);
     334       700669 :     if (expectedType >= 0) {
     335       682572 :         check_commandGetResult(myInput, command, expectedType);
     336              :     }
     337       700669 :     return myInput;
     338              : }
     339              : 
     340              : 
     341              : void
     342          186 : Connection::addFilter(int var, tcpip::Storage* add) {
     343          186 :     std::unique_lock<std::mutex> lock{ myMutex };
     344          186 :     createCommand(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, var, nullptr, add);
     345          186 :     mySocket.sendExact(myOutput);
     346          186 :     myInput.reset();
     347          186 :     check_resultState(myInput, libsumo::CMD_ADD_SUBSCRIPTION_FILTER);
     348          185 : }
     349              : 
     350              : 
     351              : void
     352       116572 : Connection::readVariables(tcpip::Storage& inMsg, const std::string& objectID, int variableCount, libsumo::SubscriptionResults& into) {
     353       259230 :     while (variableCount > 0) {
     354              : 
     355       142658 :         const int variableID = inMsg.readUnsignedByte();
     356       142658 :         const int status = inMsg.readUnsignedByte();
     357       142658 :         const int type = inMsg.readUnsignedByte();
     358              : 
     359       142658 :         if (status == libsumo::RTYPE_OK) {
     360       142658 :             switch (type) {
     361        19125 :                 case libsumo::TYPE_DOUBLE:
     362        19125 :                     into[objectID][variableID] = std::make_shared<libsumo::TraCIDouble>(inMsg.readDouble());
     363        19125 :                     break;
     364        16684 :                 case libsumo::TYPE_STRING:
     365        33368 :                     into[objectID][variableID] = std::make_shared<libsumo::TraCIString>(inMsg.readString());
     366        16684 :                     break;
     367        92815 :                 case libsumo::POSITION_2D: {
     368              :                     auto p = std::make_shared<libsumo::TraCIPosition>();
     369        92815 :                     p->x = inMsg.readDouble();
     370        92815 :                     p->y = inMsg.readDouble();
     371        92815 :                     into[objectID][variableID] = p;
     372              :                     break;
     373              :                 }
     374           32 :                 case libsumo::POSITION_3D: {
     375              :                     auto p = std::make_shared<libsumo::TraCIPosition>();
     376           32 :                     p->x = inMsg.readDouble();
     377           32 :                     p->y = inMsg.readDouble();
     378           32 :                     p->z = inMsg.readDouble();
     379           32 :                     into[objectID][variableID] = p;
     380              :                     break;
     381              :                 }
     382           10 :                 case libsumo::TYPE_COLOR: {
     383              :                     auto c = std::make_shared<libsumo::TraCIColor>();
     384           10 :                     c->r = (unsigned char)inMsg.readUnsignedByte();
     385           10 :                     c->g = (unsigned char)inMsg.readUnsignedByte();
     386           10 :                     c->b = (unsigned char)inMsg.readUnsignedByte();
     387           10 :                     c->a = (unsigned char)inMsg.readUnsignedByte();
     388           10 :                     into[objectID][variableID] = c;
     389              :                     break;
     390              :                 }
     391         8515 :                 case libsumo::TYPE_INTEGER:
     392         8515 :                     into[objectID][variableID] = std::make_shared<libsumo::TraCIInt>(inMsg.readInt());
     393         8515 :                     break;
     394          792 :                 case libsumo::TYPE_STRINGLIST: {
     395              :                     auto sl = std::make_shared<libsumo::TraCIStringList>();
     396          792 :                     int n = inMsg.readInt();
     397         2719 :                     for (int i = 0; i < n; ++i) {
     398         3854 :                         sl->value.push_back(inMsg.readString());
     399              :                     }
     400          792 :                     into[objectID][variableID] = sl;
     401              :                     break;
     402              :                 }
     403            8 :                 case libsumo::TYPE_POLYGON: {
     404              :                     auto po = std::make_shared<libsumo::TraCIPositionVector>();
     405            8 :                     StoHelp::readPolygon(inMsg, *po);
     406            8 :                     into[objectID][variableID] = po;
     407              :                     break;
     408              :                 }
     409            4 :                 case libsumo::TYPE_DOUBLELIST: {
     410              :                     auto po = std::make_shared<libsumo::TraCIDoubleList>();
     411            4 :                     po->value = inMsg.readDoubleList();
     412            4 :                     into[objectID][variableID] = po;
     413              :                     break;
     414              :                 }
     415         4673 :                 case libsumo::TYPE_COMPOUND: {
     416         4673 :                     const int n = inMsg.readInt();
     417         4673 :                     if (variableID == libsumo::LAST_STEP_VEHICLE_DATA) {
     418              :                         auto r = std::make_shared<libsumo::TraCIVehicleDataVectorWrapped>();
     419            2 :                         StoHelp::readVehicleDataVector(inMsg, r->value);
     420            2 :                         into[objectID][variableID] = r;
     421              :                         break;
     422              :                     } else if (variableID == libsumo::VAR_NEXT_LINKS) {
     423           20 :                         const int count = StoHelp::readTypedInt(inMsg);
     424              :                         auto r = std::make_shared<libsumo::TraCIConnectionVectorWrapped>();
     425           24 :                         for (int i = 0; i < count; ++i) {
     426              :                             libsumo::TraCIConnection con;
     427           28 :                             StoHelp::readConnection(inMsg, con);
     428           14 :                             r->value.emplace_back(con);
     429           14 :                         }
     430           10 :                         into[objectID][variableID] = r;
     431              :                         break;
     432              :                     } else if (variableID == libsumo::VAR_STAGE) {
     433              :                         auto r = std::make_shared<libsumo::TraCIStage>();
     434            2 :                         StoHelp::readStage(inMsg, *r);
     435            2 :                         into[objectID][variableID] = r;
     436              :                         break;
     437              :                     } else if (variableID == libsumo::VAR_TAXI_RESERVATIONS) {
     438              :                         auto r = std::make_shared<libsumo::TraCIReservationVectorWrapped>();
     439            2 :                         for (int i = 0; i < n; ++i) {
     440              :                             libsumo::TraCIReservation res;
     441            0 :                             StoHelp::readReservation(inMsg, res);
     442            0 :                             r->value.emplace_back(res);
     443            0 :                         }
     444            2 :                         into[objectID][variableID] = r;
     445              :                         break;
     446              :                     } else if (variableID == libsumo::TL_COMPLETE_DEFINITION_RYG) {
     447              :                         auto r = std::make_shared<libsumo::TraCILogicVectorWrapped>();
     448            6 :                         for (int i = 0; i < n; ++i) {
     449              :                             libsumo::TraCILogic logic;
     450            6 :                             StoHelp::readLogic(inMsg, logic);
     451            3 :                             r->value.emplace_back(logic);
     452            3 :                         }
     453            3 :                         into[objectID][variableID] = r;
     454              :                         break;
     455              :                     } else if (variableID == libsumo::TL_CONSTRAINT || variableID == libsumo::TL_CONSTRAINT_BYFOE) {
     456              :                         auto r = std::make_shared<libsumo::TraCISignalConstraintVectorWrapped>();
     457            4 :                         StoHelp::readConstraintVector(inMsg, r->value);
     458            4 :                         into[objectID][variableID] = r;
     459              :                         break;
     460              :                     } else if (variableID == libsumo::TL_CONTROLLED_LINKS) {
     461              :                         auto r = std::make_shared<libsumo::TraCILinkVectorVectorWrapped>();
     462            2 :                         StoHelp::readLinkVectorVector(inMsg, r->value);
     463            2 :                         into[objectID][variableID] = r;
     464              :                         break;
     465              :                     } else if (variableID == libsumo::VAR_BEST_LANES) {
     466              :                         auto r = std::make_shared<libsumo::TraCIBestLanesDataVectorWrapped>();
     467            2 :                         StoHelp::readBestLanesVector(inMsg, r->value);
     468            2 :                         into[objectID][variableID] = r;
     469              :                         break;
     470              :                     } else if (variableID == libsumo::VAR_COLLISIONS) {
     471              :                         auto r = std::make_shared<libsumo::TraCICollisionVectorWrapped>();
     472            2 :                         StoHelp::readCollisionVector(inMsg, r->value);
     473            2 :                         into[objectID][variableID] = r;
     474              :                         break;
     475              :                     } else if (variableID == libsumo::VAR_FOES) {
     476              :                         auto r = std::make_shared<libsumo::TraCIJunctionFoeVectorWrapped>();
     477            2 :                         StoHelp::readJunctionFoeVector(inMsg, r->value);
     478            2 :                         into[objectID][variableID] = r;
     479              :                         break;
     480              :                     } else if (variableID == libsumo::CMD_CHANGELANE) {
     481              :                         auto r = std::make_shared<libsumo::TraCIIntList>();
     482            2 :                         r->value.push_back(StoHelp::readTypedInt(inMsg));
     483            2 :                         r->value.push_back(StoHelp::readTypedInt(inMsg));
     484            2 :                         into[objectID][variableID] = r;
     485              :                         break;
     486              :                     } else if (variableID == libsumo::VAR_NEIGHBORS) {
     487              :                         auto r = std::make_shared<libsumo::TraCIStringDoublePairList>();
     488            2 :                         for (int i = 0; i < n; i++) {
     489            0 :                             const std::string neighID = inMsg.readString();
     490            0 :                             r->value.emplace_back(neighID, inMsg.readDouble());
     491              :                         }
     492            2 :                         into[objectID][variableID] = r;
     493              :                         break;
     494              :                     } else if (variableID == libsumo::VAR_NEXT_STOPS2) {
     495              :                         auto r = std::make_shared<libsumo::TraCINextStopDataVectorWrapped>();
     496            2 :                         StoHelp::readStopVector(inMsg, r->value);
     497            2 :                         into[objectID][variableID] = r;
     498              :                         break;
     499              :                     } else if (variableID == libsumo::VAR_NEXT_TLS) {
     500              :                         auto r = std::make_shared<libsumo::TraCINextTLSDataVectorWrapped>();
     501            2 :                         StoHelp::readTLSDataVector(inMsg, r->value);
     502            2 :                         into[objectID][variableID] = r;
     503              :                         break;
     504              :                     }
     505         4634 :                     if (n == 2) {
     506         4634 :                         const int firstType = inMsg.readUnsignedByte();
     507         4634 :                         if (firstType == libsumo::TYPE_STRING) {
     508         4634 :                             const std::string s = inMsg.readString();
     509         4634 :                             const int secondType = inMsg.readUnsignedByte();
     510         4634 :                             if (secondType == libsumo::TYPE_DOUBLE) {
     511              :                                 auto r = std::make_shared<libsumo::TraCIRoadPosition>();
     512         4539 :                                 r->edgeID = s;
     513         4539 :                                 r->pos = inMsg.readDouble();
     514         4539 :                                 into[objectID][variableID] = r;
     515              :                                 break;
     516           95 :                             } else if (secondType == libsumo::TYPE_STRING) {
     517              :                                 auto sl = std::make_shared<libsumo::TraCIStringList>();
     518           95 :                                 sl->value.push_back(s);
     519           95 :                                 sl->value.push_back(inMsg.readString());
     520           95 :                                 into[objectID][variableID] = sl;
     521              :                                 break;
     522              :                             }
     523              :                         }
     524              :                     }
     525              :                 }
     526              :                 FALLTHROUGH;
     527              :                 // TODO Other data types
     528              : 
     529              :                 default:
     530            0 :                     throw libsumo::TraCIException("Unimplemented subscription: variableID=" + toHex(variableID) + " type=" + toHex(type));
     531              :             }
     532              :         } else {
     533            0 :             throw libsumo::TraCIException("Subscription response error: variableID=" + toHex(variableID) + " status=" + toHex(status));
     534              :         }
     535              : 
     536       142658 :         variableCount--;
     537              :     }
     538       116572 : }
     539              : 
     540              : 
     541              : void
     542        19784 : Connection::readVariableSubscription(int responseID, tcpip::Storage& inMsg) {
     543        19784 :     const std::string objectID = inMsg.readString();
     544        19784 :     const int variableCount = inMsg.readUnsignedByte();
     545        19784 :     readVariables(inMsg, objectID, variableCount, mySubscriptionResults[responseID]);
     546        19784 : }
     547              : 
     548              : 
     549              : void
     550        30104 : Connection::readContextSubscription(int responseID, tcpip::Storage& inMsg) {
     551        30104 :     const std::string contextID = inMsg.readString();
     552        30104 :     inMsg.readUnsignedByte(); // context domain
     553        30104 :     const int variableCount = inMsg.readUnsignedByte();
     554        30104 :     int numObjects = inMsg.readInt();
     555              :     // the following also instantiates the empty map to get comparable results with libsumo
     556              :     // see also https://github.com/eclipse/sumo/issues/7288
     557        30104 :     libsumo::SubscriptionResults& results = myContextSubscriptionResults[responseID][contextID];
     558       126892 :     while (numObjects-- > 0) {
     559        96788 :         const std::string& objectID = inMsg.readString();
     560        96788 :         results[objectID]; // instantiate empty map for id lists
     561        96788 :         readVariables(inMsg, objectID, variableCount, results);
     562              :     }
     563        30104 : }
     564              : 
     565              : 
     566              : }
     567              : 
     568              : 
     569              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1