Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/traci-server/TraCIServer.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2007-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 TraCIServer.cpp
15
/// @author Axel Wegener
16
/// @author Friedemann Wesner
17
/// @author Christoph Sommer
18
/// @author Jakob Erdmann
19
/// @author Daniel Krajzewicz
20
/// @author Thimor Bohn
21
/// @author Tino Morenz
22
/// @author Laura Bieker
23
/// @author Michael Behrisch
24
/// @author Mario Krumnow
25
/// @author Leonhard Luecken
26
/// @date 2007/10/24
27
///
28
// TraCI server used to control sumo by a remote TraCI client (e.g., ns2)
29
/****************************************************************************/
30
#include <config.h>
31
32
#ifdef HAVE_VERSION_H
33
#include <version.h>
34
#endif
35
36
#include <string>
37
#include <cmath>
38
#include <map>
39
#include <iostream>
40
#include <algorithm>
41
#include <foreign/tcpip/socket.h>
42
#include <foreign/tcpip/storage.h>
43
#include <utils/common/SUMOTime.h>
44
#include <utils/router/DijkstraRouter.h>
45
#include <utils/common/NamedObjectCont.h>
46
#include <utils/common/RandHelper.h>
47
#include <utils/common/MsgHandler.h>
48
#include <utils/vehicle/SUMOVehicleParameter.h>
49
#include <utils/shapes/PointOfInterest.h>
50
#include <utils/shapes/ShapeContainer.h>
51
#include <utils/xml/XMLSubSys.h>
52
#include <microsim/MSNet.h>
53
#include <microsim/MSVehicle.h>
54
#include <microsim/MSEdge.h>
55
#include <microsim/MSJunctionControl.h>
56
#include <microsim/transportables/MSTransportableControl.h>
57
#include <microsim/MSJunction.h>
58
#include <microsim/MSEdgeControl.h>
59
#include <microsim/MSLane.h>
60
#include <microsim/MSGlobals.h>
61
#include <microsim/traffic_lights/MSTLLogicControl.h>
62
#include <libsumo/Helper.h>
63
#include <libsumo/StorageHelper.h>
64
#include <libsumo/Simulation.h>
65
#include <libsumo/Subscription.h>
66
#include <libsumo/TraCIConstants.h>
67
#include "TraCIServer.h"
68
#include "TraCIServerAPI_InductionLoop.h"
69
#include "TraCIServerAPI_Junction.h"
70
#include "TraCIServerAPI_Lane.h"
71
#include "TraCIServerAPI_MultiEntryExit.h"
72
#include "TraCIServerAPI_LaneArea.h"
73
#include "TraCIServerAPI_TrafficLight.h"
74
#include "TraCIServerAPI_Vehicle.h"
75
#include "TraCIServerAPI_VehicleType.h"
76
#include "TraCIServerAPI_Route.h"
77
#include "TraCIServerAPI_POI.h"
78
#include "TraCIServerAPI_Polygon.h"
79
#include "TraCIServerAPI_Edge.h"
80
#include "TraCIServerAPI_Simulation.h"
81
#include "TraCIServerAPI_Person.h"
82
#include "TraCIServerAPI_Calibrator.h"
83
#include "TraCIServerAPI_BusStop.h"
84
#include "TraCIServerAPI_ParkingArea.h"
85
#include "TraCIServerAPI_ChargingStation.h"
86
#include "TraCIServerAPI_RouteProbe.h"
87
#include "TraCIServerAPI_Rerouter.h"
88
#include "TraCIServerAPI_VariableSpeedSign.h"
89
#include "TraCIServerAPI_MeanData.h"
90
#include "TraCIServerAPI_OverheadWire.h"
91
92
93
// ===========================================================================
94
// debug constants
95
// ===========================================================================
96
//#define DEBUG_MULTI_CLIENTS
97
//#define DEBUG_SUBSCRIPTIONS
98
//#define DEBUG_SUBSCRIPTION_FILTERS
99
//#define DEBUG_RAW_INPUT
100
101
102
// ===========================================================================
103
// static member definitions
104
// ===========================================================================
105
TraCIServer* TraCIServer::myInstance = nullptr;
106
bool TraCIServer::myDoCloseConnection = false;
107
108
109
// ===========================================================================
110
// method definitions
111
// ===========================================================================
112
void
113
TraCIServer::initWrapper(const int domainID, const int variable, const std::string& objID) {
114
myWrapperStorage.reset();
115
myWrapperStorage.writeUnsignedByte(domainID);
116
myWrapperStorage.writeUnsignedByte(variable);
117
myWrapperStorage.writeString(objID);
118
}
119
120
121
bool
122
TraCIServer::wrapConnectionVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIConnection>& value) {
123
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 8);
124
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
125
for (const libsumo::TraCIConnection& c : value) {
126
StoHelp::writeTypedString(myWrapperStorage, c.approachedLane);
127
StoHelp::writeTypedString(myWrapperStorage, c.approachedInternal);
128
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.hasPrio);
129
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.isOpen);
130
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.hasFoe);
131
StoHelp::writeTypedString(myWrapperStorage, c.state);
132
StoHelp::writeTypedString(myWrapperStorage, c.direction);
133
StoHelp::writeTypedDouble(myWrapperStorage, c.length);
134
}
135
return true;
136
}
137
138
139
bool
140
TraCIServer::wrapDouble(const std::string& /* objID */, const int /* variable */, const double value) {
141
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
142
myWrapperStorage.writeDouble(value);
143
return true;
144
}
145
146
147
bool
148
TraCIServer::wrapInt(const std::string& /* objID */, const int /* variable */, const int value) {
149
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_INTEGER);
150
myWrapperStorage.writeInt(value);
151
return true;
152
}
153
154
155
bool
156
TraCIServer::wrapString(const std::string& /* objID */, const int /* variable */, const std::string& value) {
157
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
158
myWrapperStorage.writeString(value);
159
return true;
160
}
161
162
163
bool
164
TraCIServer::wrapStringList(const std::string& /* objID */, const int /* variable */, const std::vector<std::string>& value) {
165
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
166
myWrapperStorage.writeStringList(value);
167
return true;
168
}
169
170
171
bool
172
TraCIServer::wrapDoubleList(const std::string& /* objID */, const int /* variable */, const std::vector<double>& value) {
173
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLELIST);
174
myWrapperStorage.writeDoubleList(value);
175
return true;
176
}
177
178
179
bool
180
TraCIServer::wrapPosition(const std::string& /* objID */, const int variable, const libsumo::TraCIPosition& value) {
181
const bool includeZ = variable == libsumo::VAR_POSITION3D;
182
myWrapperStorage.writeUnsignedByte(includeZ ? libsumo::POSITION_3D : libsumo::POSITION_2D);
183
myWrapperStorage.writeDouble(value.x);
184
myWrapperStorage.writeDouble(value.y);
185
if (includeZ) {
186
myWrapperStorage.writeDouble(value.z);
187
}
188
return true;
189
}
190
191
192
bool
193
TraCIServer::wrapPositionVector(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIPositionVector& shape) {
194
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
195
if (shape.value.size() < 256) {
196
myWrapperStorage.writeUnsignedByte((int)shape.value.size());
197
} else {
198
myWrapperStorage.writeUnsignedByte(0);
199
myWrapperStorage.writeInt((int)shape.value.size());
200
}
201
for (const libsumo::TraCIPosition& pos : shape.value) {
202
myWrapperStorage.writeDouble(pos.x);
203
myWrapperStorage.writeDouble(pos.y);
204
}
205
return true;
206
}
207
208
209
bool
210
TraCIServer::wrapColor(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIColor& value) {
211
myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COLOR);
212
myWrapperStorage.writeUnsignedByte(value.r);
213
myWrapperStorage.writeUnsignedByte(value.g);
214
myWrapperStorage.writeUnsignedByte(value.b);
215
myWrapperStorage.writeUnsignedByte(value.a);
216
return true;
217
}
218
219
220
bool
221
TraCIServer::wrapStringDoublePair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, double>& value) {
222
StoHelp::writeCompound(myWrapperStorage, 2);
223
StoHelp::writeTypedString(myWrapperStorage, value.first);
224
StoHelp::writeTypedDouble(myWrapperStorage, value.second);
225
return true;
226
}
227
228
229
bool
230
TraCIServer::wrapStringDoublePairList(const std::string& /* objID */, const int /* variable */, const std::vector<std::pair<std::string, double> >& value) {
231
StoHelp::writeCompound(myWrapperStorage, (int)value.size());
232
for (const auto& p : value) {
233
myWrapperStorage.writeString(p.first);
234
myWrapperStorage.writeDouble(p.second);
235
}
236
return true;
237
}
238
239
240
bool
241
TraCIServer::wrapStringPair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, std::string>& value) {
242
StoHelp::writeCompound(myWrapperStorage, 2);
243
StoHelp::writeTypedString(myWrapperStorage, value.first);
244
StoHelp::writeTypedString(myWrapperStorage, value.second);
245
return true;
246
}
247
248
249
bool
250
TraCIServer::wrapIntPair(const std::string& /* objID */, const int /* variable */, const std::pair<int, int>& value) {
251
StoHelp::writeCompound(myWrapperStorage, 2);
252
StoHelp::writeTypedInt(myWrapperStorage, value.first);
253
StoHelp::writeTypedInt(myWrapperStorage, value.second);
254
return true;
255
}
256
257
258
bool
259
TraCIServer::wrapStage(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIStage& value) {
260
StoHelp::writeStage(myWrapperStorage, value);
261
return true;
262
}
263
264
265
bool
266
TraCIServer::wrapReservationVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIReservation>& value) {
267
StoHelp::writeCompound(myWrapperStorage, (int)value.size());
268
for (const libsumo::TraCIReservation& r : value) {
269
StoHelp::writeCompound(myWrapperStorage, 10);
270
StoHelp::writeTypedString(myWrapperStorage, r.id);
271
StoHelp::writeTypedStringList(myWrapperStorage, r.persons);
272
StoHelp::writeTypedString(myWrapperStorage, r.group);
273
StoHelp::writeTypedString(myWrapperStorage, r.fromEdge);
274
StoHelp::writeTypedString(myWrapperStorage, r.toEdge);
275
StoHelp::writeTypedDouble(myWrapperStorage, r.departPos);
276
StoHelp::writeTypedDouble(myWrapperStorage, r.arrivalPos);
277
StoHelp::writeTypedDouble(myWrapperStorage, r.depart);
278
StoHelp::writeTypedDouble(myWrapperStorage, r.reservationTime);
279
StoHelp::writeTypedInt(myWrapperStorage, r.state);
280
}
281
return true;
282
}
283
284
285
bool
286
TraCIServer::wrapLogicVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCILogic>& value) {
287
StoHelp::writeCompound(myWrapperStorage, (int)value.size());
288
for (const libsumo::TraCILogic& logic : value) {
289
StoHelp::writeCompound(myWrapperStorage, 5);
290
StoHelp::writeTypedString(myWrapperStorage, logic.programID);
291
StoHelp::writeTypedInt(myWrapperStorage, logic.type);
292
StoHelp::writeTypedInt(myWrapperStorage, logic.currentPhaseIndex);
293
StoHelp::writeCompound(myWrapperStorage, (int)logic.phases.size());
294
for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
295
StoHelp::writeCompound(myWrapperStorage, 6);
296
StoHelp::writeTypedDouble(myWrapperStorage, phase->duration);
297
StoHelp::writeTypedString(myWrapperStorage, phase->state);
298
StoHelp::writeTypedDouble(myWrapperStorage, phase->minDur);
299
StoHelp::writeTypedDouble(myWrapperStorage, phase->maxDur);
300
StoHelp::writeCompound(myWrapperStorage, (int)phase->next.size());
301
for (int n : phase->next) {
302
StoHelp::writeTypedInt(myWrapperStorage, n);
303
}
304
StoHelp::writeTypedString(myWrapperStorage, phase->name);
305
}
306
StoHelp::writeCompound(myWrapperStorage, (int)logic.subParameter.size());
307
for (const auto& item : logic.subParameter) {
308
StoHelp::writeTypedStringList(myWrapperStorage, std::vector<std::string> {item.first, item.second});
309
}
310
}
311
return true;
312
}
313
314
315
bool
316
TraCIServer::wrapLinkVectorVector(const std::string& /* objID */, const int /* variable */, const std::vector<std::vector<libsumo::TraCILink> >& value) {
317
int cnt = 1;
318
for (const std::vector<libsumo::TraCILink>& sublinks : value) {
319
cnt += (int)sublinks.size() + 1;
320
}
321
StoHelp::writeCompound(myWrapperStorage, cnt);
322
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
323
for (const std::vector<libsumo::TraCILink>& sublinks : value) {
324
StoHelp::writeTypedInt(myWrapperStorage, (int)sublinks.size());
325
for (const libsumo::TraCILink& link : sublinks) {
326
StoHelp::writeTypedStringList(myWrapperStorage, std::vector<std::string>({ link.fromLane, link.toLane, link.viaLane }));
327
}
328
}
329
return true;
330
}
331
332
333
bool
334
TraCIServer::wrapSignalConstraintVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCISignalConstraint>& value) {
335
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 5);
336
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
337
for (const auto& c : value) {
338
StoHelp::writeConstraint(myWrapperStorage, c);
339
}
340
return true;
341
}
342
343
344
bool
345
TraCIServer::wrapJunctionFoeVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIJunctionFoe>& value) {
346
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 9);
347
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
348
for (const auto& c : value) {
349
StoHelp::writeTypedString(myWrapperStorage, c.foeId);
350
StoHelp::writeTypedDouble(myWrapperStorage, c.egoDist);
351
StoHelp::writeTypedDouble(myWrapperStorage, c.foeDist);
352
StoHelp::writeTypedDouble(myWrapperStorage, c.egoExitDist);
353
StoHelp::writeTypedDouble(myWrapperStorage, c.foeExitDist);
354
StoHelp::writeTypedString(myWrapperStorage, c.egoLane);
355
StoHelp::writeTypedString(myWrapperStorage, c.foeLane);
356
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.egoResponse);
357
StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.foeResponse);
358
}
359
return true;
360
}
361
362
363
bool
364
TraCIServer::wrapNextStopDataVector(const std::string& /* objID */, const int variable, const std::vector<libsumo::TraCINextStopData>& value) {
365
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 4);
366
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
367
const bool full = variable == libsumo::VAR_NEXT_STOPS2;
368
for (const auto& s : value) {
369
const int legacyStopFlags = (s.stopFlags << 1) + (s.arrival >= 0 ? 1 : 0);
370
StoHelp::writeTypedString(myWrapperStorage, s.lane);
371
StoHelp::writeTypedDouble(myWrapperStorage, s.endPos);
372
StoHelp::writeTypedString(myWrapperStorage, s.stoppingPlaceID);
373
StoHelp::writeTypedInt(myWrapperStorage, full ? s.stopFlags : legacyStopFlags);
374
StoHelp::writeTypedDouble(myWrapperStorage, s.duration);
375
StoHelp::writeTypedDouble(myWrapperStorage, s.until);
376
if (full) {
377
StoHelp::writeTypedDouble(myWrapperStorage, s.startPos);
378
StoHelp::writeTypedDouble(myWrapperStorage, s.intendedArrival);
379
StoHelp::writeTypedDouble(myWrapperStorage, s.arrival);
380
StoHelp::writeTypedDouble(myWrapperStorage, s.depart);
381
StoHelp::writeTypedString(myWrapperStorage, s.split);
382
StoHelp::writeTypedString(myWrapperStorage, s.join);
383
StoHelp::writeTypedString(myWrapperStorage, s.actType);
384
StoHelp::writeTypedString(myWrapperStorage, s.tripId);
385
StoHelp::writeTypedString(myWrapperStorage, s.line);
386
StoHelp::writeTypedDouble(myWrapperStorage, s.speed);
387
}
388
}
389
return true;
390
}
391
392
393
bool
394
TraCIServer::wrapVehicleDataVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIVehicleData>& value) {
395
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 5);
396
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
397
for (const libsumo::TraCIVehicleData& vd : value) {
398
StoHelp::writeTypedString(myWrapperStorage, vd.id);
399
StoHelp::writeTypedDouble(myWrapperStorage, vd.length);
400
StoHelp::writeTypedDouble(myWrapperStorage, vd.entryTime);
401
StoHelp::writeTypedDouble(myWrapperStorage, vd.leaveTime);
402
StoHelp::writeTypedString(myWrapperStorage, vd.typeID);
403
}
404
return true;
405
}
406
407
408
bool
409
TraCIServer::wrapBestLanesDataVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIBestLanesData>& value) {
410
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 6);
411
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
412
for (const libsumo::TraCIBestLanesData& bld : value) {
413
StoHelp::writeTypedString(myWrapperStorage, bld.laneID);
414
StoHelp::writeTypedDouble(myWrapperStorage, bld.length);
415
StoHelp::writeTypedDouble(myWrapperStorage, bld.occupation);
416
StoHelp::writeTypedByte(myWrapperStorage, bld.bestLaneOffset);
417
StoHelp::writeTypedUnsignedByte(myWrapperStorage, bld.allowsContinuation ? 1 : 0);
418
StoHelp::writeTypedStringList(myWrapperStorage, bld.continuationLanes);
419
}
420
return true;
421
}
422
423
424
bool
425
TraCIServer::wrapNextTLSDataVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCINextTLSData>& value) {
426
StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 4);
427
StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
428
for (const libsumo::TraCINextTLSData& tlsd : value) {
429
StoHelp::writeTypedString(myWrapperStorage, tlsd.id);
430
StoHelp::writeTypedInt(myWrapperStorage, tlsd.tlIndex);
431
StoHelp::writeTypedDouble(myWrapperStorage, tlsd.dist);
432
StoHelp::writeTypedByte(myWrapperStorage, tlsd.state);
433
}
434
return true;
435
}
436
437
438
tcpip::Storage&
439
TraCIServer::getWrapperStorage() {
440
return myWrapperStorage;
441
}
442
443
444
445
TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
446
: myTargetTime(begin), myLastContextSubscription(nullptr) {
447
#ifdef DEBUG_MULTI_CLIENTS
448
std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
449
#endif
450
myVehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
451
myVehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
452
myVehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
453
myVehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
454
myVehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
455
myVehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
456
myVehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
457
myVehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
458
myVehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
459
myVehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
460
myVehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
461
myVehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
462
myVehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
463
464
myTransportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
465
myTransportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
466
myTransportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
467
myTransportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
468
469
myExecutors[libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processGet;
470
myExecutors[libsumo::CMD_SET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processSet;
471
myExecutors[libsumo::CMD_GET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processGet;
472
myExecutors[libsumo::CMD_SET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processSet;
473
myExecutors[libsumo::CMD_GET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processGet;
474
myExecutors[libsumo::CMD_SET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processSet;
475
476
myExecutors[libsumo::CMD_GET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processGet;
477
myExecutors[libsumo::CMD_SET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processSet;
478
myExecutors[libsumo::CMD_GET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processGet;
479
myExecutors[libsumo::CMD_SET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processSet;
480
myExecutors[libsumo::CMD_GET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processGet;
481
myExecutors[libsumo::CMD_SET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processSet;
482
myExecutors[libsumo::CMD_GET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processGet;
483
myExecutors[libsumo::CMD_SET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processSet;
484
myExecutors[libsumo::CMD_GET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processGet;
485
myExecutors[libsumo::CMD_SET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processSet;
486
myExecutors[libsumo::CMD_GET_POI_VARIABLE] = &TraCIServerAPI_POI::processGet;
487
myExecutors[libsumo::CMD_SET_POI_VARIABLE] = &TraCIServerAPI_POI::processSet;
488
myExecutors[libsumo::CMD_GET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processGet;
489
myExecutors[libsumo::CMD_SET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processSet;
490
myExecutors[libsumo::CMD_GET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processGet;
491
myExecutors[libsumo::CMD_SET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processSet;
492
myExecutors[libsumo::CMD_GET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processGet;
493
myExecutors[libsumo::CMD_SET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processSet;
494
myExecutors[libsumo::CMD_GET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processGet;
495
myExecutors[libsumo::CMD_SET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processSet;
496
myExecutors[libsumo::CMD_GET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processGet;
497
myExecutors[libsumo::CMD_SET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processSet;
498
myExecutors[libsumo::CMD_GET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processGet;
499
myExecutors[libsumo::CMD_SET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processSet;
500
myExecutors[libsumo::CMD_GET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processGet;
501
myExecutors[libsumo::CMD_SET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processSet;
502
myExecutors[libsumo::CMD_GET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processGet;
503
myExecutors[libsumo::CMD_SET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processSet;
504
myExecutors[libsumo::CMD_GET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processGet;
505
myExecutors[libsumo::CMD_SET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processSet;
506
myExecutors[libsumo::CMD_GET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processGet;
507
myExecutors[libsumo::CMD_SET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processSet;
508
myExecutors[libsumo::CMD_GET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processGet;
509
myExecutors[libsumo::CMD_SET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processSet;
510
myExecutors[libsumo::CMD_GET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processGet;
511
myExecutors[libsumo::CMD_SET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processSet;
512
myExecutors[libsumo::CMD_GET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processGet;
513
//myExecutors[libsumo::CMD_SET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processSet;
514
myExecutors[libsumo::CMD_GET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processGet;
515
myExecutors[libsumo::CMD_SET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processSet;
516
517
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_EDGE_TRAVELTIME));
518
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_EDGE_EFFORT));
519
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_ANGLE));
520
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::VAR_ANGLE));
521
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::LANE_CHANGES));
522
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::VAR_FOES));
523
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::DISTANCE_REQUEST));
524
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_EDGES));
525
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_STAGE));
526
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_TAXI_RESERVATIONS));
527
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::SPLIT_TAXI_RESERVATIONS));
528
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_BLOCKING_VEHICLES));
529
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_RIVAL_VEHICLES));
530
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_PRIORITY_VEHICLES));
531
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_CONSTRAINT));
532
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_CONSTRAINT_BYFOE));
533
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::VAR_PERSON_NUMBER));
534
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::DISTANCE_REQUEST));
535
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_EDGE_TRAVELTIME));
536
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_EDGE_EFFORT));
537
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOW_SPEED));
538
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_SECURE_GAP));
539
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_STOP_SPEED));
540
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOES));
541
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::CMD_CHANGELANE));
542
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_LEADER));
543
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOWER));
544
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEIGHBORS));
545
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_STOP_PARAMETER));
546
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEXT_STOPS)); // this is just a dummy to trigger an error
547
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEXT_STOPS2));
548
myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_TAXI_FLEET));
549
myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER));
550
myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER_WITH_KEY));
551
552
myDoCloseConnection = false;
553
554
// display warning if internal lanes are not used
555
// TODO this may be redundant to the warning in NLBuilder::build
556
if (!MSGlobals::gUsingInternalLanes && !MSGlobals::gUseMesoSim) {
557
WRITE_WARNING(TL("Starting TraCI without using internal lanes!"));
558
MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
559
MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
560
}
561
562
try {
563
WRITE_MESSAGEF(TL("***Starting server on port % ***"), toString(port));
564
tcpip::Socket serverSocket(port);
565
if (numClients > 1) {
566
WRITE_MESSAGEF(TL(" waiting for % clients..."), toString(numClients));
567
}
568
while ((int)mySockets.size() < numClients) {
569
int index = (int)mySockets.size() + libsumo::MAX_ORDER + 1;
570
mySockets[index] = new SocketInfo(serverSocket.accept(true), begin);
571
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
572
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
573
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
574
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
575
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
576
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
577
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
578
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
579
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
580
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
581
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
582
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
583
mySockets[index]->vehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
584
585
mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
586
mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
587
mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
588
mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
589
if (numClients > 1) {
590
WRITE_MESSAGE(TL(" client connected"));
591
}
592
}
593
// When got here, all clients have connected
594
if (numClients > 1) {
595
checkClientOrdering();
596
}
597
// set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommands()
598
myCurrentSocket = mySockets.begin();
599
} catch (tcpip::SocketException& e) {
600
throw ProcessError(e.what());
601
}
602
}
603
604
605
TraCIServer::~TraCIServer() {
606
for (const auto& socket : mySockets) {
607
delete socket.second;
608
}
609
// there is no point in calling cleanup() here, it does not free any pointers and will only modify members which get deleted anyway
610
}
611
612
613
// ---------- Initialisation and Shutdown
614
void
615
TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
616
if (myInstance == nullptr && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0)) {
617
myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
618
OptionsCont::getOptions().getInt("remote-port"),
619
OptionsCont::getOptions().getInt("num-clients"));
620
for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
621
myInstance->myExecutors[i->first] = i->second;
622
}
623
}
624
if (myInstance != nullptr) {
625
// maybe net was deleted and built again
626
MSNet::getInstance()->addVehicleStateListener(myInstance);
627
MSNet::getInstance()->addTransportableStateListener(myInstance);
628
myInstance->mySubscriptionCache.writeInt(0);
629
}
630
}
631
632
633
void
634
TraCIServer::close() {
635
if (myInstance == nullptr) {
636
return;
637
}
638
delete myInstance;
639
myInstance = nullptr;
640
myDoCloseConnection = true;
641
}
642
643
644
bool
645
TraCIServer::wasClosed() {
646
return myDoCloseConnection;
647
}
648
649
650
// ---------- Initialisation and Shutdown
651
652
653
void
654
TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
655
if (!myDoCloseConnection) {
656
myVehicleStateChanges[to].push_back(vehicle->getID());
657
for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
658
i->second->vehicleStateChanges[to].push_back(vehicle->getID());
659
}
660
}
661
}
662
663
664
void
665
TraCIServer::transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& /*info*/) {
666
if (!myDoCloseConnection) {
667
myTransportableStateChanges[to].push_back(transportable->getID());
668
for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
669
i->second->transportableStateChanges[to].push_back(transportable->getID());
670
}
671
}
672
}
673
674
675
void
676
TraCIServer::checkClientOrdering() {
677
#ifdef DEBUG_MULTI_CLIENTS
678
std::cout << "Checking client order requests." << std::endl;
679
#endif
680
// check for SET_ORDER commands queued by connected clients
681
// In multiclient cas it is mandatory that SET_ORDER is sent as the first command (or directly after GET_VERSION)
682
myCurrentSocket = mySockets.begin();
683
while (myCurrentSocket != mySockets.end()) {
684
#ifdef DEBUG_MULTI_CLIENTS
685
std::cout << " Socket " << myCurrentSocket->second->socket << ":" << std::endl;
686
#endif
687
// bool clientUnordered = true;
688
while (true) {
689
myInputStorage.reset();
690
myCurrentSocket->second->socket->receiveExact(myInputStorage);
691
int commandStart, commandLength;
692
int commandId = readCommandID(commandStart, commandLength);
693
#ifdef DEBUG_MULTI_CLIENTS
694
std::cout << " received command " << commandId << std::endl;
695
#endif
696
// Whether the received command is a permitted command for the initialization phase.
697
// Currently, getVersion and setOrder are permitted.
698
bool initCommand = commandId == libsumo::CMD_SETORDER || commandId == libsumo::CMD_GETVERSION;
699
if (initCommand) {
700
#ifdef DEBUG_MULTI_CLIENTS
701
std::cout << " Init command. Sending response." << std::endl;
702
#endif
703
// reset input storage to initial state before reading the commandId
704
// (ugly, but we can't just reset the store's iter_ from here)
705
// Giving the commandId to dispatch command didn't work either
706
tcpip::Storage tmp;
707
tmp.writeStorage(myInputStorage);
708
myInputStorage.reset();
709
// we don't know whether the command was set with extended
710
// length syntax or not so we hardcode the length here (#5037)
711
myInputStorage.writeUnsignedByte(commandId == libsumo::CMD_SETORDER ? 6 : 2);
712
myInputStorage.writeUnsignedByte(commandId);
713
myInputStorage.writeStorage(tmp);
714
715
// Handle initialization command completely
716
dispatchCommand();
717
myCurrentSocket->second->socket->sendExact(myOutputStorage);
718
myOutputStorage.reset();
719
} else {
720
#ifdef DEBUG_MULTI_CLIENTS
721
std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
722
#endif
723
throw ProcessError(TL("Execution order (libsumo::CMD_SETORDER) was not set for all TraCI clients in pre-execution phase."));
724
}
725
if (commandId == libsumo::CMD_SETORDER) {
726
// This is what we have waited for.
727
break;
728
}
729
}
730
++myCurrentSocket;
731
}
732
}
733
734
735
void
736
TraCIServer::processReorderingRequests() {
737
// Process reordering requests
738
if (mySocketReorderRequests.size() > 0) {
739
// process reordering requests
740
std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
741
std::map<int, SocketInfo*>::iterator j;
742
#ifdef DEBUG_MULTI_CLIENTS
743
std::cout << SIMTIME << " Current socket ordering:\n";
744
for (j = mySockets.begin(); j != mySockets.end(); ++j) {
745
std::cout << " " << j->first << ": " << j->second->socket << "\n";
746
}
747
std::cout << "Reordering requests:\n";
748
for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
749
std::cout << " Socket " << i->second->socket << " -> " << i->first << "\n";
750
}
751
i = mySocketReorderRequests.begin();
752
#endif
753
while (i != mySocketReorderRequests.end()) {
754
j = mySockets.begin();
755
while (j != mySockets.end()) {
756
if (j->second->socket == i->second->socket) {
757
break;
758
} else {
759
j++;
760
}
761
}
762
assert(j != mySockets.end());
763
mySockets.erase(j);
764
mySockets[i->first] = i->second;
765
++i;
766
}
767
mySocketReorderRequests.clear();
768
#ifdef DEBUG_MULTI_CLIENTS
769
std::cout << "New socket ordering:\n";
770
for (j = mySockets.begin(); j != mySockets.end(); ++j) {
771
std::cout << " " << j->first << ": " << j->second->socket << "\n";
772
}
773
std::cout << std::endl;
774
#endif
775
}
776
}
777
778
779
SUMOTime
780
TraCIServer::nextTargetTime() const {
781
#ifdef DEBUG_MULTI_CLIENTS
782
std::cout << "\n Determining new target time..." << std::endl;
783
if (mySockets.size() == 0) {
784
std::cout << " All clients have disconnected." << std::endl;
785
}
786
#endif
787
std::map<int, SocketInfo*>::const_iterator i;
788
SUMOTime targetTime = std::numeric_limits<SUMOTime>::max();
789
for (i = mySockets.begin(); i != mySockets.end(); ++i) {
790
#ifdef DEBUG_MULTI_CLIENTS
791
std::cout << " target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
792
#endif
793
targetTime = MIN2(targetTime, i->second->targetTime);
794
}
795
#ifdef DEBUG_MULTI_CLIENTS
796
std::cout << std::endl;
797
#endif
798
return targetTime;
799
}
800
801
802
// send out subscription results to clients which will act in this step (i.e. with client target time <= myTargetTime)
803
void
804
TraCIServer::sendOutputToAll() const {
805
#ifdef DEBUG_MULTI_CLIENTS
806
std::cout << "\n Sending subscription results to clients:\n";
807
#endif
808
std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
809
while (i != mySockets.end()) {
810
if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
811
// this client will become active before the next SUMO step. Provide subscription results.
812
i->second->socket->sendExact(myOutputStorage);
813
#ifdef DEBUG_MULTI_CLIENTS
814
std::cout << i->second->socket << "\n";
815
#endif
816
}
817
++i;
818
}
819
#ifdef DEBUG_MULTI_CLIENTS
820
std::cout << std::endl;
821
#endif
822
}
823
824
825
int
826
TraCIServer::processCommands(const SUMOTime step, const bool afterMove) {
827
#ifdef DEBUG_MULTI_CLIENTS
828
std::cout << SIMTIME << " processCommands(step = " << step << "):\n" << std::endl;
829
#endif
830
try {
831
int finalCmd = 0;
832
const bool firstStep = myCurrentSocket != mySockets.end();
833
// update client order if requested
834
processReorderingRequests();
835
if (!firstStep && !afterMove) {
836
// This is the entry point after performing a SUMO step (block is skipped before first SUMO step since then no simulation results have to be sent)
837
// update subscription results
838
postProcessSimulationStep();
839
// Send out subscription results to clients which will act in this SUMO step (i.e. with client target time <= current sumo timestep end)
840
sendOutputToAll();
841
myOutputStorage.reset();
842
}
843
844
// determine minimal next target time among clients
845
myTargetTime = nextTargetTime();
846
847
if (step < myTargetTime) {
848
#ifdef DEBUG_MULTI_CLIENTS
849
std::cout << " next target time is larger than next SUMO simstep (" << step << "). Returning from processCommands()." << std::endl;
850
#endif
851
return finalCmd;
852
}
853
854
// Simulation should run until
855
// 1. end time reached or
856
// 2. got libsumo::CMD_CLOSE or
857
// 3. got libsumo::CMD_LOAD or
858
// 4. Client closes socket connection
859
while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep()) && finalCmd != libsumo::CMD_EXECUTEMOVE) {
860
#ifdef DEBUG_MULTI_CLIENTS
861
std::cout << " Next target time: " << myTargetTime << std::endl;
862
#endif
863
// Iterate over clients and process communication for the ones with target time == myTargetTime
864
myCurrentSocket = mySockets.begin();
865
while (myCurrentSocket != mySockets.end()) {
866
#ifdef DEBUG_MULTI_CLIENTS
867
std::cout << " current socket: " << myCurrentSocket->second->socket
868
<< " with target time=" << myCurrentSocket->second->targetTime
869
<< std::endl;
870
#endif
871
872
if (myCurrentSocket->second->targetTime > myTargetTime || (afterMove && !myCurrentSocket->second->executeMove)) {
873
// this client must wait
874
#ifdef DEBUG_MULTI_CLIENTS
875
std::cout << " skipping client " << myCurrentSocket->second->socket
876
<< " with target time=" << myCurrentSocket->second->targetTime << std::endl;
877
#endif
878
myCurrentSocket++;
879
continue;
880
}
881
finalCmd = 0;
882
while (finalCmd == 0) {
883
if (!myInputStorage.valid_pos()) {
884
// have read request completely, send response if adequate
885
if (myOutputStorage.size() > 0) {
886
// send response to previous query
887
myCurrentSocket->second->socket->sendExact(myOutputStorage);
888
myOutputStorage.reset();
889
}
890
#ifdef DEBUG_MULTI_CLIENTS
891
std::cout << " resetting input storage and reading next command..." << std::endl;
892
#endif
893
// Read next request
894
myInputStorage.reset();
895
myCurrentSocket->second->socket->receiveExact(myInputStorage);
896
}
897
898
while (myInputStorage.valid_pos() && !myDoCloseConnection) {
899
const int cmd = dispatchCommand();
900
if (cmd == libsumo::CMD_SIMSTEP || cmd == libsumo::CMD_LOAD || cmd == libsumo::CMD_EXECUTEMOVE || cmd == libsumo::CMD_CLOSE) {
901
finalCmd = cmd;
902
}
903
}
904
}
905
}
906
if (!myLoadArgs.empty()) {
907
#ifdef DEBUG_MULTI_CLIENTS
908
std::cout << " Breaking loop to load new simulation." << std::endl;
909
#endif
910
break;
911
} else if (myDoCloseConnection) {
912
#ifdef DEBUG_MULTI_CLIENTS
913
std::cout << " Breaking loop because last client closed connection." << std::endl;
914
#endif
915
break;
916
}
917
SUMOTime nextT = nextTargetTime();
918
// minimal target time among clients should have been increased during the last loop through mySockets
919
// XXX: The assert below is disabled since many tests do sth. like simulationStep(step). Such that for a first call step=0,
920
// leading to targetTime==1000 (increased by DELTA_T in dispatchCommand()),
921
// the next call is then usually simulationStep(step=1000) leading to no further increase
922
// and thus a failing assertion here.
923
//assert(myTargetTime < nextT || myDoCloseConnection);
924
myTargetTime = nextT;
925
}
926
// All clients are done with the current time step
927
// Reset myVehicleStateChanges and myTransportableStateChanges
928
for (auto& item : myVehicleStateChanges) {
929
item.second.clear();
930
}
931
for (auto& item : myTransportableStateChanges) {
932
item.second.clear();
933
}
934
return finalCmd;
935
} catch (std::invalid_argument& e) {
936
throw ProcessError(e.what());
937
} catch (libsumo::TraCIException& e) {
938
throw ProcessError(e.what());
939
} catch (tcpip::SocketException& e) {
940
throw ProcessError(e.what());
941
}
942
}
943
944
945
void
946
TraCIServer::cleanup() {
947
mySubscriptions.clear();
948
myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
949
for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
950
myCurrentSocket->second->targetTime = myTargetTime;
951
myCurrentSocket->second->executeMove = false;
952
}
953
myOutputStorage.reset();
954
myInputStorage.reset();
955
mySubscriptionCache.reset();
956
for (auto& i : myVehicleStateChanges) {
957
i.second.clear();
958
}
959
for (auto& i : myTransportableStateChanges) {
960
i.second.clear();
961
}
962
myCurrentSocket = mySockets.begin();
963
}
964
965
966
std::map<int, TraCIServer::SocketInfo*>::iterator
967
TraCIServer::removeCurrentSocket() {
968
#ifdef DEBUG_MULTI_CLIENTS
969
std::cout << " Removing socket " << myCurrentSocket->second->socket
970
<< " (order " << myCurrentSocket->first << ")" << std::endl;
971
#endif
972
delete myCurrentSocket->second;
973
myCurrentSocket = mySockets.erase(myCurrentSocket);
974
return myCurrentSocket;
975
}
976
977
978
int
979
TraCIServer::readCommandID(int& commandStart, int& commandLength) {
980
commandStart = myInputStorage.position();
981
commandLength = myInputStorage.readUnsignedByte();
982
if (commandLength == 0) {
983
commandLength = myInputStorage.readInt();
984
}
985
#ifdef DEBUG_RAW_INPUT
986
std::cout << " commandStart=" << commandStart << " commandLength=" << commandLength << " pos=" << myInputStorage.position() << " raw=";
987
for (auto it = myInputStorage.begin(); it != myInputStorage.end(); ++it) {
988
std::cout << (int)*it << " ";
989
}
990
std::cout << "\n";
991
#endif
992
return myInputStorage.readUnsignedByte();
993
}
994
995
996
int
997
TraCIServer::dispatchCommand() {
998
int commandStart, commandLength;
999
int commandId = readCommandID(commandStart, commandLength);
1000
#ifdef DEBUG_MULTI_CLIENTS
1001
std::cout << " dispatchCommand() called for client " << myCurrentSocket->second->socket
1002
<< ", commandId = " << commandId << std::endl;
1003
#endif
1004
bool success = false;
1005
// dispatch commands
1006
if (myExecutors.find(commandId) != myExecutors.end()) {
1007
success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
1008
} else {
1009
switch (commandId) {
1010
case libsumo::CMD_GETVERSION:
1011
success = commandGetVersion();
1012
break;
1013
case libsumo::CMD_LOAD: {
1014
std::vector<std::string> args;
1015
if (!readTypeCheckingStringList(myInputStorage, args)) {
1016
return writeErrorStatusCmd(libsumo::CMD_LOAD, "A load command needs a list of string arguments.", myOutputStorage);
1017
}
1018
#ifdef DEBUG_MULTI_CLIENTS
1019
std::cout << " commandId == libsumo::CMD_LOAD"
1020
<< ", args = " << toString(args) << std::endl;
1021
#endif
1022
try {
1023
myLoadArgs = args;
1024
success = true;
1025
writeStatusCmd(libsumo::CMD_LOAD, libsumo::RTYPE_OK, "");
1026
// XXX: This only cares for the client that issued the load command.
1027
// Multiclient-load functionality is still to be implemented. Refs #3146.
1028
myCurrentSocket->second->socket->sendExact(myOutputStorage);
1029
myCurrentSocket = mySockets.end();
1030
myOutputStorage.reset();
1031
} catch (libsumo::TraCIException& e) {
1032
return writeErrorStatusCmd(libsumo::CMD_LOAD, e.what(), myOutputStorage);
1033
}
1034
break;
1035
}
1036
case libsumo::CMD_EXECUTEMOVE:
1037
myCurrentSocket->second->executeMove = true;
1038
myCurrentSocket++;
1039
success = true;
1040
writeStatusCmd(libsumo::CMD_EXECUTEMOVE, libsumo::RTYPE_OK, "");
1041
break;
1042
case libsumo::CMD_SIMSTEP: {
1043
const double nextT = myInputStorage.readDouble();
1044
if (nextT == 0.) {
1045
myCurrentSocket->second->targetTime += DELTA_T;
1046
} else {
1047
myCurrentSocket->second->targetTime = TIME2STEPS(nextT);
1048
}
1049
myCurrentSocket->second->executeMove = false;
1050
#ifdef DEBUG_MULTI_CLIENTS
1051
std::cout << " commandId == libsumo::CMD_SIMSTEP"
1052
<< ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
1053
#endif
1054
if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
1055
// This is not the last TraCI simstep in the current SUMO simstep -> send single simstep response.
1056
// @note: In the other case the simstep results are sent to all after the SUMO step was performed, see entry point for processCommands()
1057
sendSingleSimStepResponse();
1058
}
1059
// Clear vehicleStateChanges and transportableStateChanges for this client
1060
// -> For subsequent TraCI stepping
1061
// that is performed within this SUMO step, no updates on vehicle states
1062
// belonging to the last SUMO simulation step will be received by this client.
1063
for (auto& item : myCurrentSocket->second->vehicleStateChanges) {
1064
item.second.clear();
1065
}
1066
for (auto& item : myCurrentSocket->second->transportableStateChanges) {
1067
item.second.clear();
1068
}
1069
myCurrentSocket++;
1070
return commandId;
1071
}
1072
case libsumo::CMD_CLOSE:
1073
writeStatusCmd(libsumo::CMD_CLOSE, libsumo::RTYPE_OK, "");
1074
myCurrentSocket->second->socket->sendExact(myOutputStorage);
1075
myOutputStorage.reset();
1076
if (mySockets.size() == 1) {
1077
// Last client has closed connection
1078
myDoCloseConnection = true;
1079
}
1080
// remove current socket and increment to next socket in ordering
1081
myCurrentSocket = removeCurrentSocket();
1082
success = true;
1083
break;
1084
case libsumo::CMD_SETORDER: {
1085
const int order = myInputStorage.readInt();
1086
#ifdef DEBUG_MULTI_CLIENTS
1087
std::cout << " commandId == libsumo::CMD_SETORDER"
1088
<< ", order index is " << order << std::endl;
1089
#endif
1090
if (order > libsumo::MAX_ORDER) {
1091
return writeErrorStatusCmd(libsumo::CMD_SETORDER, "A set order command needs an int argument below " + toString(libsumo::MAX_ORDER) + ".", myOutputStorage);
1092
}
1093
if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
1094
return writeErrorStatusCmd(libsumo::CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
1095
}
1096
// memorize reorder request (will only take effect in the next step)
1097
mySocketReorderRequests[order] = myCurrentSocket->second;
1098
success = true;
1099
writeStatusCmd(libsumo::CMD_SETORDER, libsumo::RTYPE_OK, "");
1100
break;
1101
}
1102
case libsumo::CMD_SUBSCRIBE_BUSSTOP_VARIABLE:
1103
case libsumo::CMD_SUBSCRIBE_CALIBRATOR_VARIABLE:
1104
case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_VARIABLE:
1105
case libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE:
1106
case libsumo::CMD_SUBSCRIBE_GUI_VARIABLE:
1107
case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE:
1108
case libsumo::CMD_SUBSCRIBE_JUNCTION_VARIABLE:
1109
case libsumo::CMD_SUBSCRIBE_LANE_VARIABLE:
1110
case libsumo::CMD_SUBSCRIBE_LANEAREA_VARIABLE:
1111
case libsumo::CMD_SUBSCRIBE_MEANDATA_VARIABLE:
1112
case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE:
1113
case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_VARIABLE:
1114
case libsumo::CMD_SUBSCRIBE_PARKINGAREA_VARIABLE:
1115
case libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE:
1116
case libsumo::CMD_SUBSCRIBE_POI_VARIABLE:
1117
case libsumo::CMD_SUBSCRIBE_POLYGON_VARIABLE:
1118
case libsumo::CMD_SUBSCRIBE_REROUTER_VARIABLE:
1119
case libsumo::CMD_SUBSCRIBE_ROUTE_VARIABLE:
1120
case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_VARIABLE:
1121
case libsumo::CMD_SUBSCRIBE_SIM_VARIABLE:
1122
case libsumo::CMD_SUBSCRIBE_TL_VARIABLE:
1123
case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_VARIABLE:
1124
case libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE:
1125
case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE:
1126
success = addObjectVariableSubscription(commandId, false);
1127
break;
1128
case libsumo::CMD_SUBSCRIBE_BUSSTOP_CONTEXT:
1129
case libsumo::CMD_SUBSCRIBE_CALIBRATOR_CONTEXT:
1130
case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_CONTEXT:
1131
case libsumo::CMD_SUBSCRIBE_EDGE_CONTEXT:
1132
case libsumo::CMD_SUBSCRIBE_GUI_CONTEXT:
1133
case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT:
1134
case libsumo::CMD_SUBSCRIBE_JUNCTION_CONTEXT:
1135
case libsumo::CMD_SUBSCRIBE_LANE_CONTEXT:
1136
case libsumo::CMD_SUBSCRIBE_LANEAREA_CONTEXT:
1137
case libsumo::CMD_SUBSCRIBE_MEANDATA_CONTEXT:
1138
case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT:
1139
case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_CONTEXT:
1140
case libsumo::CMD_SUBSCRIBE_PARKINGAREA_CONTEXT:
1141
case libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT:
1142
case libsumo::CMD_SUBSCRIBE_POI_CONTEXT:
1143
case libsumo::CMD_SUBSCRIBE_POLYGON_CONTEXT:
1144
case libsumo::CMD_SUBSCRIBE_REROUTER_CONTEXT:
1145
case libsumo::CMD_SUBSCRIBE_ROUTE_CONTEXT:
1146
case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_CONTEXT:
1147
case libsumo::CMD_SUBSCRIBE_SIM_CONTEXT:
1148
case libsumo::CMD_SUBSCRIBE_TL_CONTEXT:
1149
case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_CONTEXT:
1150
case libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT:
1151
case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_CONTEXT:
1152
success = addObjectVariableSubscription(commandId, true);
1153
break;
1154
case libsumo::CMD_ADD_SUBSCRIPTION_FILTER:
1155
success = addSubscriptionFilter();
1156
break;
1157
default:
1158
if (commandId == libsumo::CMD_GET_GUI_VARIABLE || commandId == libsumo::CMD_SET_GUI_VARIABLE) {
1159
writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo");
1160
} else {
1161
writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
1162
}
1163
}
1164
}
1165
if (!success) {
1166
while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
1167
myInputStorage.readChar();
1168
}
1169
}
1170
if ((int)myInputStorage.position() != commandStart + commandLength) {
1171
std::ostringstream msg;
1172
msg << "Wrong position in requestMessage after dispatching command " << commandId << ".";
1173
msg << " Expected command length was " << commandLength;
1174
msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
1175
writeStatusCmd(commandId, libsumo::RTYPE_ERR, msg.str());
1176
myDoCloseConnection = true;
1177
}
1178
return commandId;
1179
}
1180
1181
1182
// ---------- Server-internal command handling
1183
bool
1184
TraCIServer::commandGetVersion() {
1185
// Prepare response
1186
tcpip::Storage answerTmp;
1187
answerTmp.writeInt(libsumo::TRACI_VERSION);
1188
answerTmp.writeString("SUMO " VERSION_STRING);
1189
// When we get here, the response is stored in answerTmp -> put into myOutputStorage
1190
writeStatusCmd(libsumo::CMD_GETVERSION, libsumo::RTYPE_OK, "");
1191
// command length
1192
myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
1193
// command type
1194
myOutputStorage.writeUnsignedByte(libsumo::CMD_GETVERSION);
1195
// and the parameter dependant part
1196
myOutputStorage.writeStorage(answerTmp);
1197
return true;
1198
}
1199
1200
1201
void
1202
TraCIServer::postProcessSimulationStep() {
1203
SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1204
#ifdef DEBUG_MULTI_CLIENTS
1205
std::cout << " postProcessSimulationStep() at time=" << t << std::endl;
1206
#endif
1207
writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
1208
int noActive = 0;
1209
for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
1210
const libsumo::Subscription& s = *i;
1211
bool isArrivedVehicle = (s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT)
1212
&& (find(myVehicleStateChanges[MSNet::VehicleState::ARRIVED].begin(), myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end(), s.id) != myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end());
1213
1214
bool isArrivedPerson = (s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT) && MSNet::getInstance()->getPersonControl().get(s.id) == nullptr;
1215
if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
1216
i = mySubscriptions.erase(i);
1217
continue;
1218
}
1219
++i;
1220
if (s.beginTime > t) {
1221
continue;
1222
}
1223
++noActive;
1224
}
1225
mySubscriptionCache.reset();
1226
#ifdef DEBUG_SUBSCRIPTIONS
1227
std::cout << " Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
1228
<< "\n Nr. of active subscriptions = " << noActive << std::endl;
1229
#endif
1230
mySubscriptionCache.writeInt(noActive);
1231
#ifdef DEBUG_SUBSCRIPTIONS
1232
std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
1233
#endif
1234
for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
1235
const libsumo::Subscription& s = *i;
1236
if (s.beginTime > t) {
1237
++i;
1238
continue;
1239
}
1240
tcpip::Storage into;
1241
std::string errors;
1242
bool ok = processSingleSubscription(s, into, errors);
1243
#ifdef DEBUG_SUBSCRIPTIONS
1244
std::cout << " Size of into-store for subscription " << s.id
1245
<< ": " << into.size() << std::endl;
1246
#endif
1247
mySubscriptionCache.writeStorage(into);
1248
if (ok) {
1249
++i;
1250
} else {
1251
i = mySubscriptions.erase(i);
1252
}
1253
}
1254
myOutputStorage.writeStorage(mySubscriptionCache);
1255
#ifdef DEBUG_SUBSCRIPTIONS
1256
std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
1257
#endif
1258
}
1259
1260
1261
void
1262
TraCIServer::sendSingleSimStepResponse() {
1263
#ifdef DEBUG_MULTI_CLIENTS
1264
std::cout << " Sending cached simstep response to current client " << myCurrentSocket->second->socket
1265
<< " (-> intermediate TraCI step)."
1266
<< "\n Size of mySubscriptionCache is " << mySubscriptionCache.size()
1267
<< std::endl;
1268
#endif
1269
writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
1270
1271
// NOTE: the commented code would send an empty response
1272
// myOutputStorage.writeInt(0);
1273
// myCurrentSocket->second->socket->sendExact(myOutputStorage);
1274
// myOutputStorage.reset();
1275
myOutputStorage.writeStorage(mySubscriptionCache);
1276
// send results to active client
1277
myCurrentSocket->second->socket->sendExact(myOutputStorage);
1278
myOutputStorage.reset();
1279
}
1280
1281
1282
void
1283
TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
1284
writeStatusCmd(commandId, status, description, myOutputStorage);
1285
}
1286
1287
1288
void
1289
TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
1290
if (status == libsumo::RTYPE_ERR) {
1291
WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
1292
} else if (status == libsumo::RTYPE_NOTIMPLEMENTED) {
1293
WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
1294
}
1295
outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
1296
outputStorage.writeUnsignedByte(commandId); // command type
1297
outputStorage.writeUnsignedByte(status); // status
1298
outputStorage.writeString(description); // description
1299
}
1300
1301
1302
bool
1303
TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
1304
writeStatusCmd(commandId, libsumo::RTYPE_ERR, description, outputStorage);
1305
return false;
1306
}
1307
1308
1309
void
1310
TraCIServer::initialiseSubscription(libsumo::Subscription& s) {
1311
tcpip::Storage writeInto;
1312
std::string errors;
1313
libsumo::Subscription* modifiedSubscription = nullptr;
1314
try {
1315
if (processSingleSubscription(s, writeInto, errors)) {
1316
if (s.endTime < MSNet::getInstance()->getCurrentTimeStep()) {
1317
writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Subscription has ended.");
1318
} else {
1319
if (libsumo::Helper::needNewSubscription(s, mySubscriptions, modifiedSubscription)) {
1320
// Add new subscription to subscription cache (note: seems a bit inefficient)
1321
if (s.beginTime < MSNet::getInstance()->getCurrentTimeStep()) {
1322
// copy new subscription into cache
1323
int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
1324
tcpip::Storage tmp;
1325
tmp.writeInt(noActive);
1326
while (mySubscriptionCache.valid_pos()) {
1327
tmp.writeByte(mySubscriptionCache.readByte());
1328
}
1329
tmp.writeStorage(writeInto);
1330
mySubscriptionCache.reset();
1331
mySubscriptionCache.writeStorage(tmp);
1332
}
1333
}
1334
writeStatusCmd(s.commandId, libsumo::RTYPE_OK, "");
1335
}
1336
if (modifiedSubscription != nullptr && (
1337
modifiedSubscription->isVehicleToVehicleContextSubscription()
1338
|| modifiedSubscription->isVehicleToPersonContextSubscription())) {
1339
// Set last modified vehicle context subscription active for filter modifications
1340
myLastContextSubscription = modifiedSubscription;
1341
} else {
1342
// adding other subscriptions deactivates the activation for filter addition
1343
myLastContextSubscription = nullptr;
1344
}
1345
} else {
1346
writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Could not add subscription. " + errors);
1347
}
1348
} catch (libsumo::TraCIException& e) {
1349
writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, e.what());
1350
}
1351
myOutputStorage.writeStorage(writeInto);
1352
}
1353
1354
1355
void
1356
TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
1357
bool found = false;
1358
std::vector<libsumo::Subscription>::iterator j;
1359
for (j = mySubscriptions.begin(); j != mySubscriptions.end();) {
1360
if (j->id == id && j->commandId == commandId && j->contextDomain == domain) {
1361
j = mySubscriptions.erase(j);
1362
if (j != mySubscriptions.end() && myLastContextSubscription == &(*j)) {
1363
// Remove also reference for filter additions
1364
myLastContextSubscription = nullptr;
1365
}
1366
found = true;
1367
continue;
1368
}
1369
++j;
1370
}
1371
// try unsubscribe
1372
if (found) {
1373
writeStatusCmd(commandId, libsumo::RTYPE_OK, "");
1374
} else {
1375
writeStatusCmd(commandId, libsumo::RTYPE_ERR, "The subscription to remove was not found.");
1376
}
1377
}
1378
1379
1380
bool
1381
TraCIServer::processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
1382
std::string& errors) {
1383
bool ok = true;
1384
tcpip::Storage outputStorage;
1385
const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
1386
std::set<std::string> objIDs;
1387
if (s.contextDomain > 0) {
1388
if ((s.activeFilters & libsumo::SUBS_FILTER_NO_RTREE) == 0) {
1389
PositionVector shape;
1390
libsumo::Helper::findObjectShape(s.commandId, s.id, shape);
1391
libsumo::Helper::collectObjectIDsInRange(s.contextDomain, shape, s.range, objIDs);
1392
}
1393
libsumo::Helper::applySubscriptionFilters(s, objIDs);
1394
} else {
1395
objIDs.insert(s.id);
1396
}
1397
const int numVars = s.contextDomain > 0 && s.variables.size() == 1 && s.variables[0] == libsumo::TRACI_ID_LIST ? 0 : (int)s.variables.size();
1398
int skipped = 0;
1399
for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
1400
if (s.contextDomain > 0) {
1401
//if (centralObject(s, *j)) {
1402
// skipped++;
1403
// continue;
1404
//}
1405
outputStorage.writeString(*j);
1406
}
1407
if (numVars > 0) {
1408
std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
1409
for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
1410
tcpip::Storage message;
1411
message.writeUnsignedByte(*i);
1412
message.writeString(*j);
1413
// TODO check why writeStorage fails here (probably some kind of invalid iterator)
1414
for (const auto& v :** k) {
1415
message.writeChar(v);
1416
}
1417
tcpip::Storage tmpOutput;
1418
try {
1419
if (myExecutors.find(getCommandId) != myExecutors.end()) {
1420
ok &= myExecutors[getCommandId](*this, message, tmpOutput);
1421
} else {
1422
writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
1423
ok = false;
1424
}
1425
} catch (const std::invalid_argument&) {
1426
writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
1427
ok = false;
1428
}
1429
// copy response part
1430
if (ok) {
1431
int length = tmpOutput.readUnsignedByte();
1432
while (--length > 0) {
1433
tmpOutput.readUnsignedByte();
1434
}
1435
int lengthLength = 1;
1436
length = tmpOutput.readUnsignedByte();
1437
if (length == 0) {
1438
lengthLength = 5;
1439
length = tmpOutput.readInt();
1440
}
1441
//read responseType
1442
tmpOutput.readUnsignedByte();
1443
int variable = tmpOutput.readUnsignedByte();
1444
std::string id = tmpOutput.readString();
1445
outputStorage.writeUnsignedByte(variable);
1446
outputStorage.writeUnsignedByte(libsumo::RTYPE_OK);
1447
length -= (lengthLength + 1 + 4 + (int)id.length());
1448
while (--length > 0) {
1449
outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
1450
}
1451
} else {
1452
//read length
1453
tmpOutput.readUnsignedByte();
1454
//read cmd
1455
tmpOutput.readUnsignedByte();
1456
//read status
1457
tmpOutput.readUnsignedByte();
1458
std::string msg = tmpOutput.readString();
1459
outputStorage.writeUnsignedByte(*i);
1460
outputStorage.writeUnsignedByte(libsumo::RTYPE_ERR);
1461
outputStorage.writeUnsignedByte(libsumo::TYPE_STRING);
1462
outputStorage.writeString(msg);
1463
errors = errors + msg;
1464
}
1465
}
1466
}
1467
}
1468
int length = (1 + 4) + 1 + (4 + (int)s.id.length()) + 1 + (int)outputStorage.size();
1469
if (s.contextDomain > 0) {
1470
length += 1 + 4; // context domain and number of objects
1471
}
1472
// we always write extended command length here for backward compatibility
1473
writeInto.writeUnsignedByte(0); // command length -> extended
1474
writeInto.writeInt(length);
1475
writeInto.writeUnsignedByte(s.commandId + 0x10);
1476
writeInto.writeString(s.id);
1477
if (s.contextDomain > 0) {
1478
writeInto.writeUnsignedByte(s.contextDomain);
1479
}
1480
writeInto.writeUnsignedByte(numVars);
1481
if (s.contextDomain > 0) {
1482
writeInto.writeInt((int)objIDs.size() - skipped);
1483
}
1484
if (s.contextDomain == 0 || objIDs.size() != 0) {
1485
writeInto.writeStorage(outputStorage);
1486
}
1487
return ok;
1488
}
1489
1490
1491
bool
1492
TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
1493
const double beginTime = myInputStorage.readDouble();
1494
const double endTime = myInputStorage.readDouble();
1495
const SUMOTime begin = beginTime == libsumo::INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
1496
const SUMOTime end = endTime == libsumo::INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
1497
const std::string id = myInputStorage.readString();
1498
const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
1499
double range = hasContext ? myInputStorage.readDouble() : 0.;
1500
if (commandId == libsumo::CMD_SUBSCRIBE_SIM_CONTEXT) {
1501
range = std::numeric_limits<double>::max();
1502
}
1503
const int num = myInputStorage.readUnsignedByte();
1504
std::vector<int> variables;
1505
std::vector<std::shared_ptr<tcpip::Storage> > parameters;
1506
for (int i = 0; i < num; ++i) {
1507
const int varID = myInputStorage.readUnsignedByte();
1508
variables.push_back(varID);
1509
parameters.push_back(std::make_shared<tcpip::Storage>());
1510
if ((myParameterized.count(std::make_pair(0, varID)) > 0) || (myParameterized.count(std::make_pair(commandId, varID)) > 0)) {
1511
if (!myInputStorage.valid_pos()) {
1512
writeStatusCmd(commandId, libsumo::RTYPE_ERR, "Missing parameter for subscription " + toHex(commandId, 2));
1513
return false;
1514
}
1515
int count = 1;
1516
while (count-- > 0) {
1517
const int parType = myInputStorage.readUnsignedByte();
1518
parameters.back()->writeUnsignedByte(parType);
1519
if (parType == libsumo::TYPE_DOUBLE) {
1520
parameters.back()->writeDouble(myInputStorage.readDouble());
1521
} else if (parType == libsumo::TYPE_INTEGER) {
1522
parameters.back()->writeInt(myInputStorage.readInt());
1523
} else if (parType == libsumo::TYPE_STRING) {
1524
parameters.back()->writeString(myInputStorage.readString());
1525
} else if (parType == libsumo::TYPE_BYTE) {
1526
parameters.back()->writeByte(myInputStorage.readByte());
1527
} else if (parType == libsumo::TYPE_UBYTE) {
1528
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
1529
} else if (parType == libsumo::POSITION_2D) {
1530
parameters.back()->writeDouble(myInputStorage.readDouble());
1531
parameters.back()->writeDouble(myInputStorage.readDouble());
1532
if (varID == libsumo::DISTANCE_REQUEST) {
1533
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
1534
break;
1535
}
1536
} else if (parType == libsumo::POSITION_3D) {
1537
parameters.back()->writeDouble(myInputStorage.readDouble());
1538
parameters.back()->writeDouble(myInputStorage.readDouble());
1539
parameters.back()->writeDouble(myInputStorage.readDouble());
1540
if (varID == libsumo::DISTANCE_REQUEST) {
1541
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
1542
break;
1543
}
1544
} else if (parType == libsumo::POSITION_ROADMAP) {
1545
parameters.back()->writeString(myInputStorage.readString());
1546
parameters.back()->writeDouble(myInputStorage.readDouble());
1547
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
1548
if (varID == libsumo::DISTANCE_REQUEST) {
1549
parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
1550
break;
1551
}
1552
} else if (parType == libsumo::TYPE_COMPOUND) {
1553
count = myInputStorage.readInt();
1554
parameters.back()->writeInt(count);
1555
} else {
1556
writeStatusCmd(commandId, libsumo::RTYPE_ERR, "Invalid parameter for subscription " + toHex(commandId, 2));
1557
return false;
1558
}
1559
}
1560
}
1561
}
1562
// check subscribe/unsubscribe
1563
if (variables.empty()) {
1564
removeSubscription(commandId, id, domain);
1565
return true;
1566
}
1567
// process subscription
1568
libsumo::Subscription s(commandId, id, variables, parameters, begin, end, domain, range);
1569
initialiseSubscription(s);
1570
return true;
1571
}
1572
1573
1574
1575
bool
1576
TraCIServer::addSubscriptionFilter() {
1577
bool success = true;
1578
// Read filter type
1579
int filterType = myInputStorage.readUnsignedByte();
1580
1581
if (myLastContextSubscription == nullptr) {
1582
writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_ERR,
1583
"No previous vehicle context subscription exists to apply filter type " + toHex(filterType, 2));
1584
return false;
1585
}
1586
1587
// dispatch according to filter type
1588
switch (filterType) {
1589
case libsumo::FILTER_TYPE_NONE:
1590
// Remove all filters
1591
removeFilters();
1592
break;
1593
case libsumo::FILTER_TYPE_LANES: {
1594
// Read relative lanes to consider for context filter
1595
int nrLanes = (int)myInputStorage.readByte();
1596
std::vector<int> lanes;
1597
for (int i = 0; i < nrLanes; ++i) {
1598
lanes.push_back((int) myInputStorage.readByte());
1599
}
1600
addSubscriptionFilterLanes(lanes);
1601
}
1602
break;
1603
case libsumo::FILTER_TYPE_NOOPPOSITE:
1604
// Add no-opposite filter
1605
addSubscriptionFilterNoOpposite();
1606
break;
1607
case libsumo::FILTER_TYPE_DOWNSTREAM_DIST: {
1608
myInputStorage.readByte(); // read type double
1609
double dist = myInputStorage.readDouble();
1610
addSubscriptionFilterDownstreamDistance(dist);
1611
}
1612
break;
1613
case libsumo::FILTER_TYPE_UPSTREAM_DIST: {
1614
myInputStorage.readByte(); // read type double
1615
double dist = myInputStorage.readDouble();
1616
addSubscriptionFilterUpstreamDistance(dist);
1617
}
1618
break;
1619
case libsumo::FILTER_TYPE_LEAD_FOLLOW: {
1620
// Read relative lanes to consider for context filter
1621
addSubscriptionFilterLeadFollow();
1622
}
1623
break;
1624
case libsumo::FILTER_TYPE_TURN: {
1625
myInputStorage.readByte(); // read type double
1626
double dist = myInputStorage.readDouble();
1627
addSubscriptionFilterTurn(dist);
1628
}
1629
break;
1630
case libsumo::FILTER_TYPE_VCLASS: {
1631
myInputStorage.readByte(); // read type stringlist
1632
SVCPermissions vClasses = parseVehicleClasses(myInputStorage.readStringList());
1633
addSubscriptionFilterVClass(vClasses);
1634
}
1635
break;
1636
case libsumo::FILTER_TYPE_VTYPE: {
1637
myInputStorage.readByte(); // read type stringlist
1638
std::vector<std::string> vTypesVector = myInputStorage.readStringList();
1639
std::set<std::string> vTypesSet;
1640
vTypesSet.insert(vTypesVector.begin(), vTypesVector.end());
1641
addSubscriptionFilterVType(vTypesSet);
1642
}
1643
break;
1644
case libsumo::FILTER_TYPE_FIELD_OF_VISION: {
1645
myInputStorage.readByte(); // read type double
1646
double angle = myInputStorage.readDouble();
1647
addSubscriptionFilterFieldOfVision(angle);
1648
}
1649
break;
1650
case libsumo::FILTER_TYPE_LATERAL_DIST: {
1651
myInputStorage.readByte(); // read type double
1652
double dist = myInputStorage.readDouble();
1653
addSubscriptionFilterLateralDistance(dist);
1654
}
1655
break;
1656
default:
1657
writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_NOTIMPLEMENTED,
1658
"'" + toString(filterType) + "' is no valid filter type code.");
1659
success = false;
1660
}
1661
1662
if (success) {
1663
// acknowledge filter addition
1664
writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_OK, "");
1665
}
1666
1667
return success;
1668
}
1669
1670
1671
void
1672
TraCIServer::removeFilters() {
1673
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1674
std::cout << "Removing filters" << std::endl;
1675
#endif
1676
myLastContextSubscription->activeFilters = libsumo::SUBS_FILTER_NONE;
1677
}
1678
1679
void
1680
TraCIServer::addSubscriptionFilterLanes(std::vector<int> lanes) {
1681
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1682
std::cout << "Adding lane filter (lanes=" << toString(lanes) << ")" << std::endl;
1683
#endif
1684
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LANES;
1685
myLastContextSubscription->filterLanes = lanes;
1686
}
1687
1688
void
1689
TraCIServer::addSubscriptionFilterNoOpposite() {
1690
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1691
std::cout << "Adding no opposite filter" << std::endl;
1692
#endif
1693
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_NOOPPOSITE;
1694
}
1695
1696
void
1697
TraCIServer::addSubscriptionFilterDownstreamDistance(double dist) {
1698
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1699
std::cout << "Adding downstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1700
#endif
1701
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_DOWNSTREAM_DIST;
1702
myLastContextSubscription->filterDownstreamDist = dist;
1703
}
1704
1705
void
1706
TraCIServer::addSubscriptionFilterUpstreamDistance(double dist) {
1707
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1708
std::cout << "Adding upstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1709
#endif
1710
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_UPSTREAM_DIST;
1711
myLastContextSubscription->filterUpstreamDist = dist;
1712
}
1713
1714
void
1715
TraCIServer::addSubscriptionFilterLeadFollow() {
1716
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1717
std::cout << "Adding Lead/Follow-maneuver filter" << std::endl;
1718
#endif
1719
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LEAD_FOLLOW;
1720
}
1721
1722
void
1723
TraCIServer::addSubscriptionFilterTurn(double dist) {
1724
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1725
std::cout << "Adding turn-maneuver filter" << std::endl;
1726
#endif
1727
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_TURN;
1728
myLastContextSubscription->filterFoeDistToJunction = dist;
1729
}
1730
1731
void
1732
TraCIServer::addSubscriptionFilterVClass(SVCPermissions vClasses) {
1733
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1734
std::cout << "Adding vClass filter (vClasses=" << toString(vClasses) << ")" << std::endl;
1735
#endif
1736
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VCLASS;
1737
myLastContextSubscription->filterVClasses = vClasses;
1738
}
1739
1740
void
1741
TraCIServer::addSubscriptionFilterVType(std::set<std::string> vTypes) {
1742
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1743
std::cout << "Adding vType filter (vTypes=" << toString(vTypes) << ")" << std::endl;
1744
#endif
1745
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VTYPE;
1746
myLastContextSubscription->filterVTypes = vTypes;
1747
}
1748
1749
void
1750
TraCIServer::addSubscriptionFilterFieldOfVision(double openingAngle) {
1751
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1752
std::cout << "Adding FieldOfVision filter (openingAngle=" << toString(openingAngle) << ")" << std::endl;
1753
#endif
1754
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_FIELD_OF_VISION;
1755
myLastContextSubscription->filterFieldOfVisionOpeningAngle = openingAngle;
1756
}
1757
1758
void
1759
TraCIServer::addSubscriptionFilterLateralDistance(double dist) {
1760
#ifdef DEBUG_SUBSCRIPTION_FILTERS
1761
std::cout << "Adding lateral dist filter (dist=" << toString(dist) << ")" << std::endl;
1762
#endif
1763
myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LATERAL_DIST;
1764
myLastContextSubscription->filterLateralDist = dist;
1765
}
1766
1767
void
1768
TraCIServer::writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg) {
1769
if (tempMsg.size() < 254) {
1770
outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
1771
} else {
1772
outputStorage.writeUnsignedByte(0); // command length -> extended
1773
outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
1774
}
1775
outputStorage.writeStorage(tempMsg);
1776
}
1777
1778
1779
void
1780
TraCIServer::writePositionVector(tcpip::Storage& outputStorage, const libsumo::TraCIPositionVector& shape) {
1781
outputStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
1782
if (shape.value.size() < 256) {
1783
outputStorage.writeUnsignedByte((int)shape.value.size());
1784
} else {
1785
outputStorage.writeUnsignedByte(0);
1786
outputStorage.writeInt((int)shape.value.size());
1787
}
1788
for (const libsumo::TraCIPosition& pos : shape.value) {
1789
outputStorage.writeDouble(pos.x);
1790
outputStorage.writeDouble(pos.y);
1791
}
1792
}
1793
1794
1795
bool
1796
TraCIServer::readTypeCheckingDouble(tcpip::Storage& inputStorage, double& into) {
1797
if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLE) {
1798
return false;
1799
}
1800
into = inputStorage.readDouble();
1801
return true;
1802
}
1803
1804
1805
bool
1806
TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
1807
if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRING) {
1808
return false;
1809
}
1810
into = inputStorage.readString();
1811
return true;
1812
}
1813
1814
1815
bool
1816
TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
1817
if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRINGLIST) {
1818
return false;
1819
}
1820
into = inputStorage.readStringList();
1821
return true;
1822
}
1823
1824
1825
bool
1826
TraCIServer::readTypeCheckingDoubleList(tcpip::Storage& inputStorage, std::vector<double>& into) {
1827
if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLELIST) {
1828
return false;
1829
}
1830
into = inputStorage.readDoubleList();
1831
return true;
1832
}
1833
1834
1835
bool
1836
TraCIServer::readTypeCheckingColor(tcpip::Storage& inputStorage, libsumo::TraCIColor& into) {
1837
if (inputStorage.readUnsignedByte() != libsumo::TYPE_COLOR) {
1838
return false;
1839
}
1840
into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1841
into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1842
into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1843
into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1844
return true;
1845
}
1846
1847
1848
bool
1849
TraCIServer::readTypeCheckingPosition2D(tcpip::Storage& inputStorage, libsumo::TraCIPosition& into) {
1850
if (inputStorage.readUnsignedByte() != libsumo::POSITION_2D) {
1851
return false;
1852
}
1853
into.x = inputStorage.readDouble();
1854
into.y = inputStorage.readDouble();
1855
into.z = 0;
1856
return true;
1857
}
1858
1859
1860
bool
1861
TraCIServer::readTypeCheckingByte(tcpip::Storage& inputStorage, int& into) {
1862
if (inputStorage.readByte() != libsumo::TYPE_BYTE) {
1863
return false;
1864
}
1865
into = inputStorage.readByte();
1866
return true;
1867
}
1868
1869
1870
bool
1871
TraCIServer::readTypeCheckingUnsignedByte(tcpip::Storage& inputStorage, int& into) {
1872
if (inputStorage.readUnsignedByte() != libsumo::TYPE_UBYTE) {
1873
return false;
1874
}
1875
into = inputStorage.readUnsignedByte();
1876
return true;
1877
}
1878
1879
1880
bool
1881
TraCIServer::readTypeCheckingPolygon(tcpip::Storage& inputStorage, PositionVector& into) {
1882
if (inputStorage.readUnsignedByte() != libsumo::TYPE_POLYGON) {
1883
return false;
1884
}
1885
into.clear();
1886
int size = inputStorage.readUnsignedByte();
1887
if (size == 0) {
1888
size = inputStorage.readInt();
1889
}
1890
PositionVector shape;
1891
for (int i = 0; i < size; ++i) {
1892
double x = inputStorage.readDouble();
1893
double y = inputStorage.readDouble();
1894
if (std::isnan(x) || std::isnan(y)) {
1895
throw libsumo::TraCIException("NaN-Value in shape.");
1896
}
1897
into.push_back(Position(x, y));
1898
}
1899
return true;
1900
}
1901
1902
1903
void
1904
TraCIServer::stateLoaded(SUMOTime targetTime) {
1905
myTargetTime = targetTime;
1906
for (auto& s : mySockets) {
1907
s.second->targetTime = targetTime;
1908
s.second->executeMove = false;
1909
for (auto& stateChange : s.second->vehicleStateChanges) {
1910
stateChange.second.clear();
1911
}
1912
for (auto& stateChange : s.second->transportableStateChanges) {
1913
stateChange.second.clear();
1914
}
1915
}
1916
mySubscriptions.clear();
1917
mySubscriptionCache.reset();
1918
}
1919
1920
1921
bool
1922
TraCIServer::centralObject(const libsumo::Subscription& s, const std::string& objID) {
1923
return (s.id == objID && s.commandId + 32 == s.contextDomain);
1924
}
1925
1926
1927
/****************************************************************************/
1928
1929