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 : /****************************************************************************/
|