1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    TraCIServerAPI_Person.cpp
11 /// @author  Daniel Krajzewicz
12 /// @date    26.05.2014
13 /// @version $Id$
14 ///
15 // APIs for getting/setting person values via TraCI
16 /****************************************************************************/
17 
18 
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23 
24 #include <utils/common/StringTokenizer.h>
25 #include <microsim/MSTransportableControl.h>
26 #include <microsim/MSVehicleControl.h>
27 #include <microsim/pedestrians/MSPerson.h>
28 #include <microsim/MSNet.h>
29 #include <microsim/MSEdge.h>
30 #include <libsumo/Person.h>
31 #include <libsumo/TraCIConstants.h>
32 #include <libsumo/VehicleType.h>
33 #include "TraCIServer.h"
34 #include "TraCIServerAPI_VehicleType.h"
35 #include "TraCIServerAPI_Person.h"
36 
37 
38 // ===========================================================================
39 // method definitions
40 // ===========================================================================
41 bool
processGet(TraCIServer & server,tcpip::Storage & inputStorage,tcpip::Storage & outputStorage)42 TraCIServerAPI_Person::processGet(TraCIServer& server, tcpip::Storage& inputStorage,
43                                   tcpip::Storage& outputStorage) {
44     const int variable = inputStorage.readUnsignedByte();
45     const std::string id = inputStorage.readString();
46     server.initWrapper(libsumo::RESPONSE_GET_PERSON_VARIABLE, variable, id);
47     try {
48         if (!libsumo::Person::handleVariable(id, variable, &server) &&
49                 !libsumo::VehicleType::handleVariable(libsumo::Person::getTypeID(id), variable, &server)) {
50             switch (variable) {
51                 case libsumo::VAR_EDGES: {
52                     int nextStageIndex = 0;
53                     if (!server.readTypeCheckingInt(inputStorage, nextStageIndex)) {
54                         return server.writeErrorStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, "The message must contain the stage index.", outputStorage);
55                     }
56                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_STRINGLIST);
57                     server.getWrapperStorage().writeStringList(libsumo::Person::getEdges(id, nextStageIndex));
58                     break;
59                 }
60                 case libsumo::VAR_STAGE: {
61                     int nextStageIndex = 0;
62                     if (!server.readTypeCheckingInt(inputStorage, nextStageIndex)) {
63                         return server.writeErrorStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, "The message must contain the stage index.", outputStorage);
64                     }
65                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_INTEGER);
66                     server.getWrapperStorage().writeInt(libsumo::Person::getStage(id, nextStageIndex));
67                     break;
68                 }
69                 case libsumo::VAR_PARAMETER: {
70                     std::string paramName = "";
71                     if (!server.readTypeCheckingString(inputStorage, paramName)) {
72                         return server.writeErrorStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, "Retrieval of a parameter requires its name.", outputStorage);
73                     }
74                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_STRING);
75                     server.getWrapperStorage().writeString(libsumo::Person::getParameter(id, paramName));
76                     break;
77                 }
78                 default:
79                     return server.writeErrorStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, "Get Person Variable: unsupported variable " + toHex(variable, 2) + " specified", outputStorage);
80             }
81         }
82     } catch (libsumo::TraCIException& e) {
83         return server.writeErrorStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, e.what(), outputStorage);
84     }
85     server.writeStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, libsumo::RTYPE_OK, "", outputStorage);
86     server.writeResponseWithLength(outputStorage, server.getWrapperStorage());
87     return true;
88 }
89 
90 
91 bool
processSet(TraCIServer & server,tcpip::Storage & inputStorage,tcpip::Storage & outputStorage)92 TraCIServerAPI_Person::processSet(TraCIServer& server, tcpip::Storage& inputStorage,
93                                   tcpip::Storage& outputStorage) {
94     std::string warning = ""; // additional description for response
95     // variable
96     int variable = inputStorage.readUnsignedByte();
97     if (variable != libsumo::VAR_PARAMETER
98             && variable != libsumo::ADD
99             && variable != libsumo::APPEND_STAGE
100             && variable != libsumo::REMOVE_STAGE
101             && variable != libsumo::CMD_REROUTE_TRAVELTIME
102             && variable != libsumo::MOVE_TO_XY
103             && variable != libsumo::VAR_SPEED
104             && variable != libsumo::VAR_TYPE
105             && variable != libsumo::VAR_LENGTH
106             && variable != libsumo::VAR_WIDTH
107             && variable != libsumo::VAR_HEIGHT
108             && variable != libsumo::VAR_MINGAP
109             && variable != libsumo::VAR_COLOR
110        ) {
111         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Change Person State: unsupported variable " + toHex(variable, 2) + " specified", outputStorage);
112     }
113 
114     try {
115         // TODO: remove declaration of c after completion
116         MSTransportableControl& c = MSNet::getInstance()->getPersonControl();
117         // id
118         std::string id = inputStorage.readString();
119         // TODO: remove declaration of p after completion
120         const bool shouldExist = variable != libsumo::ADD;
121         MSTransportable* p = c.get(id);
122         if (p == nullptr && shouldExist) {
123             return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Person '" + id + "' is not known", outputStorage);
124         }
125         // process
126         switch (variable) {
127             case libsumo::VAR_SPEED: {
128                 double speed = 0;
129                 if (!server.readTypeCheckingDouble(inputStorage, speed)) {
130                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Setting speed requires a double.", outputStorage);
131                 }
132                 // set the speed for all (walking) stages
133                 libsumo::Person::setSpeed(id, speed);
134                 // modify the vType so that stages added later are also affected
135                 TraCIServerAPI_VehicleType::setVariable(libsumo::CMD_SET_VEHICLE_VARIABLE, variable, p->getSingularType().getID(), server, inputStorage, outputStorage);
136             }
137             break;
138             case libsumo::VAR_TYPE: {
139                 std::string vTypeID;
140                 if (!server.readTypeCheckingString(inputStorage, vTypeID)) {
141                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The vehicle type id must be given as a string.", outputStorage);
142                 }
143                 libsumo::Person::setType(id, vTypeID);
144                 break;
145             }
146             case libsumo::VAR_COLOR: {
147                 libsumo::TraCIColor col;
148                 if (!server.readTypeCheckingColor(inputStorage, col)) {
149                     return server.writeErrorStatusCmd(libsumo::CMD_SET_VEHICLE_VARIABLE, "The color must be given using the according type.", outputStorage);
150                 }
151                 libsumo::Person::setColor(id, col);
152                 break;
153             }
154             case libsumo::ADD: {
155                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
156                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Adding a person requires a compound object.", outputStorage);
157                 }
158                 if (inputStorage.readInt() != 4) {
159                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Adding a person needs four parameters.", outputStorage);
160                 }
161                 std::string vTypeID;
162                 if (!server.readTypeCheckingString(inputStorage, vTypeID)) {
163                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "First parameter (type) requires a string.", outputStorage);
164                 }
165                 std::string edgeID;
166                 if (!server.readTypeCheckingString(inputStorage, edgeID)) {
167                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Second parameter (edge) requires a string.", outputStorage);
168                 }
169                 double depart;
170                 if (!server.readTypeCheckingDouble(inputStorage, depart)) {
171                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Third parameter (depart) requires a double.", outputStorage);
172                 }
173                 double pos;
174                 if (!server.readTypeCheckingDouble(inputStorage, pos)) {
175                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Fourth parameter (position) requires a double.", outputStorage);
176                 }
177                 libsumo::Person::add(id, edgeID, pos, depart, vTypeID);
178             }
179             break;
180             case libsumo::APPEND_STAGE: {
181                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
182                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Adding a person stage requires a compound object.", outputStorage);
183                 }
184                 int numParameters = inputStorage.readInt();
185                 int stageType;
186                 if (!server.readTypeCheckingInt(inputStorage, stageType)) {
187                     return server.writeErrorStatusCmd(libsumo::CMD_SET_VEHICLE_VARIABLE, "The first parameter for adding a stage must be the stage type given as int.", outputStorage);
188                 }
189                 if (stageType == MSTransportable::DRIVING) {
190                     // append driving stage
191                     if (numParameters != 4) {
192                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Adding a driving stage needs four parameters.", outputStorage);
193                     }
194                     std::string edgeID;
195                     if (!server.readTypeCheckingString(inputStorage, edgeID)) {
196                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Second parameter (edge) requires a string.", outputStorage);
197                     }
198                     std::string lines;
199                     if (!server.readTypeCheckingString(inputStorage, lines)) {
200                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Third parameter (lines) requires a string.", outputStorage);
201                     }
202                     std::string stopID;
203                     if (!server.readTypeCheckingString(inputStorage, stopID)) {
204                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Fourth parameter (stopID) requires a string.", outputStorage);
205                     }
206                     libsumo::Person::appendDrivingStage(id, edgeID, lines, stopID);
207                 } else if (stageType == MSTransportable::WAITING) {
208                     // append waiting stage
209                     if (numParameters != 4) {
210                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Adding a waiting stage needs four parameters.", outputStorage);
211                     }
212                     int duration;
213                     if (!server.readTypeCheckingInt(inputStorage, duration)) {
214                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Second parameter (duration) requires an int.", outputStorage);
215                     }
216                     std::string description;
217                     if (!server.readTypeCheckingString(inputStorage, description)) {
218                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Third parameter (description) requires a string.", outputStorage);
219                     }
220                     std::string stopID;
221                     if (!server.readTypeCheckingString(inputStorage, stopID)) {
222                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Fourth parameter (stopID) requires a string.", outputStorage);
223                     }
224                     libsumo::Person::appendWaitingStage(id, STEPS2TIME(duration), description, stopID);
225                 } else if (stageType == MSTransportable::MOVING_WITHOUT_VEHICLE) {
226                     // append walking stage
227                     if (numParameters != 6) {
228                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Adding a walking stage needs six parameters.", outputStorage);
229                     }
230                     std::vector<std::string> edgeIDs;
231                     if (!server.readTypeCheckingStringList(inputStorage, edgeIDs)) {
232                         return server.writeErrorStatusCmd(libsumo::CMD_SET_VEHICLE_VARIABLE, "Second parameter (edges) route must be defined as a list of edge ids.", outputStorage);
233                     }
234                     double arrivalPos;
235                     if (!server.readTypeCheckingDouble(inputStorage, arrivalPos)) {
236                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Third parameter (arrivalPos) requires a double.", outputStorage);
237                     }
238                     int duration;
239                     if (!server.readTypeCheckingInt(inputStorage, duration)) {
240                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Fourth parameter (duration) requires an int.", outputStorage);
241                     }
242                     double speed;
243                     if (!server.readTypeCheckingDouble(inputStorage, speed)) {
244                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Fifth parameter (speed) requires a double.", outputStorage);
245                     }
246                     std::string stopID;
247                     if (!server.readTypeCheckingString(inputStorage, stopID)) {
248                         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Fourth parameter (stopID) requires a string.", outputStorage);
249                     }
250                     libsumo::Person::appendWalkingStage(id, edgeIDs, arrivalPos, STEPS2TIME(duration), speed, stopID);
251                 } else {
252                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Invalid stage type for person '" + id + "'", outputStorage);
253                 }
254             }
255             break;
256             case libsumo::REMOVE_STAGE: {
257                 int nextStageIndex = 0;
258                 if (!server.readTypeCheckingInt(inputStorage, nextStageIndex)) {
259                     return server.writeErrorStatusCmd(libsumo::CMD_GET_PERSON_VARIABLE, "The message must contain the stage index.", outputStorage);
260                 }
261                 libsumo::Person::removeStage(id, nextStageIndex);
262             }
263             break;
264             case libsumo::CMD_REROUTE_TRAVELTIME: {
265                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
266                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Rerouting requires a compound object.", outputStorage);
267                 }
268                 if (inputStorage.readInt() != 0) {
269                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "Rerouting should obtain an empty compound object.", outputStorage);
270                 }
271                 libsumo::Person::rerouteTraveltime(id);
272             }
273             break;
274             case libsumo::MOVE_TO_XY: {
275                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
276                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "MoveToXY person requires a compound object.", outputStorage);
277                 }
278                 const int numArgs = inputStorage.readInt();
279                 if (numArgs != 5) {
280                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "MoveToXY person should obtain: edgeID, x, y, angle and keepRouteFlag.", outputStorage);
281                 }
282                 // edge ID
283                 std::string edgeID;
284                 if (!server.readTypeCheckingString(inputStorage, edgeID)) {
285                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The first parameter for moveToXY must be the edge ID given as a string.", outputStorage);
286                 }
287                 // x
288                 double x = 0;
289                 if (!server.readTypeCheckingDouble(inputStorage, x)) {
290                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The second parameter for moveToXY must be the x-position given as a double.", outputStorage);
291                 }
292                 // y
293                 double y = 0;
294                 if (!server.readTypeCheckingDouble(inputStorage, y)) {
295                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The third parameter for moveToXY must be the y-position given as a double.", outputStorage);
296                 }
297                 // angle
298                 double angle = 0;
299                 if (!server.readTypeCheckingDouble(inputStorage, angle)) {
300                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The fourth parameter for moveToXY must be the angle given as a double.", outputStorage);
301                 }
302                 int keepRouteFlag = 1;
303                 if (!server.readTypeCheckingByte(inputStorage, keepRouteFlag)) {
304                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The fifth parameter for moveToXY must be the keepRouteFlag given as a byte.", outputStorage);
305                 }
306                 libsumo::Person::moveToXY(id, edgeID, x, y, angle, keepRouteFlag);
307             }
308             break;
309             case libsumo::VAR_PARAMETER: {
310                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
311                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "A compound object is needed for setting a parameter.", outputStorage);
312                 }
313                 //read itemNo
314                 inputStorage.readInt();
315                 std::string name;
316                 if (!server.readTypeCheckingString(inputStorage, name)) {
317                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The name of the parameter must be given as a string.", outputStorage);
318                 }
319                 std::string value;
320                 if (!server.readTypeCheckingString(inputStorage, value)) {
321                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, "The value of the parameter must be given as a string.", outputStorage);
322                 }
323                 libsumo::Person::setParameter(id, name, value);
324             }
325             break;
326             default:
327                 try {
328                     if (!TraCIServerAPI_VehicleType::setVariable(libsumo::CMD_SET_PERSON_VARIABLE, variable, p->getSingularType().getID(), server, inputStorage, outputStorage)) {
329                         return false;
330                     }
331                 } catch (ProcessError& e) {
332                     return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, e.what(), outputStorage);
333                 }
334                 break;
335         }
336     } catch (libsumo::TraCIException& e) {
337         return server.writeErrorStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, e.what(), outputStorage);
338     }
339     server.writeStatusCmd(libsumo::CMD_SET_PERSON_VARIABLE, libsumo::RTYPE_OK, warning, outputStorage);
340     return true;
341 }
342 
343 
344 /****************************************************************************/
345