1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2009-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_TrafficLight.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Laura Bieker
13 /// @author  Michael Behrisch
14 /// @author  Jakob Erdmann
15 /// @date    07.05.2009
16 /// @version $Id$
17 ///
18 // APIs for getting/setting traffic light values via TraCI
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <microsim/MSLane.h>
28 #include <microsim/MSEdge.h>
29 #include <microsim/traffic_lights/MSTLLogicControl.h>
30 #include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
31 #include <libsumo/TraCIConstants.h>
32 #include <libsumo/TrafficLight.h>
33 #include "TraCIServerAPI_TrafficLight.h"
34 
35 
36 // ===========================================================================
37 // method definitions
38 // ===========================================================================
39 bool
processGet(TraCIServer & server,tcpip::Storage & inputStorage,tcpip::Storage & outputStorage)40 TraCIServerAPI_TrafficLight::processGet(TraCIServer& server, tcpip::Storage& inputStorage,
41                                         tcpip::Storage& outputStorage) {
42     const int variable = inputStorage.readUnsignedByte();
43     const std::string id = inputStorage.readString();
44     server.initWrapper(libsumo::RESPONSE_GET_TL_VARIABLE, variable, id);
45     try {
46         if (!libsumo::TrafficLight::handleVariable(id, variable, &server)) {
47             switch (variable) {
48                 case libsumo::TL_COMPLETE_DEFINITION_RYG: {
49                     std::vector<libsumo::TraCILogic> logics = libsumo::TrafficLight::getCompleteRedYellowGreenDefinition(id);
50                     tcpip::Storage& storage = server.getWrapperStorage();
51                     storage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
52                     storage.writeInt((int)logics.size());
53                     for (const libsumo::TraCILogic& logic : logics) {
54                         storage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
55                         storage.writeInt(5);
56                         storage.writeUnsignedByte(libsumo::TYPE_STRING);
57                         storage.writeString(logic.programID);
58                         // type
59                         storage.writeUnsignedByte(libsumo::TYPE_INTEGER);
60                         storage.writeInt(logic.type);
61                         // (current) phase index
62                         storage.writeUnsignedByte(libsumo::TYPE_INTEGER);
63                         storage.writeInt(logic.currentPhaseIndex);
64                         // phase number
65                         storage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
66                         storage.writeInt((int)logic.phases.size());
67                         for (const libsumo::TraCIPhase& phase : logic.phases) {
68                             storage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
69                             storage.writeInt(6);
70                             storage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
71                             storage.writeDouble(phase.duration);
72                             storage.writeUnsignedByte(libsumo::TYPE_STRING);
73                             storage.writeString(phase.state);
74                             storage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
75                             storage.writeDouble(phase.minDur);
76                             storage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
77                             storage.writeDouble(phase.maxDur);
78                             storage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
79                             storage.writeInt((int)phase.next.size());
80                             for (int n : phase.next) {
81                                 storage.writeUnsignedByte(libsumo::TYPE_INTEGER);
82                                 storage.writeInt(n);
83                             }
84                             storage.writeUnsignedByte(libsumo::TYPE_STRING);
85                             storage.writeString(phase.name);
86                         }
87                         // subparameter
88                         storage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
89                         storage.writeInt((int)logic.subParameter.size());
90                         for (const auto& item : logic.subParameter) {
91                             storage.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
92                             storage.writeInt(2);
93                             storage.writeString(item.first);
94                             storage.writeString(item.second);
95                         }
96                     }
97                     break;
98                 }
99                 case libsumo::TL_CONTROLLED_LINKS: {
100                     const std::vector<std::vector<libsumo::TraCILink> > links = libsumo::TrafficLight::getControlledLinks(id);
101                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_COMPOUND);
102                     tcpip::Storage tempContent;
103                     int cnt = 0;
104                     tempContent.writeUnsignedByte(libsumo::TYPE_INTEGER);
105                     tempContent.writeInt((int)links.size());
106                     for (const std::vector<libsumo::TraCILink>& sublinks : links) {
107                         tempContent.writeUnsignedByte(libsumo::TYPE_INTEGER);
108                         tempContent.writeInt((int)sublinks.size());
109                         ++cnt;
110                         for (const libsumo::TraCILink& link : sublinks) {
111                             tempContent.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
112                             tempContent.writeStringList(std::vector<std::string>({ link.fromLane, link.toLane, link.viaLane }));
113                             ++cnt;
114                         }
115                     }
116                     server.getWrapperStorage().writeInt(cnt);
117                     server.getWrapperStorage().writeStorage(tempContent);
118                     break;
119                 }
120                 case libsumo::VAR_PARAMETER: {
121                     std::string paramName = "";
122                     if (!server.readTypeCheckingString(inputStorage, paramName)) {
123                         return server.writeErrorStatusCmd(libsumo::CMD_GET_TL_VARIABLE, "Retrieval of a parameter requires its name.", outputStorage);
124                     }
125                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_STRING);
126                     server.getWrapperStorage().writeString(libsumo::TrafficLight::getParameter(id, paramName));
127                     break;
128                 }
129                 case libsumo::TL_EXTERNAL_STATE: {
130                     if (!MSNet::getInstance()->getTLSControl().knows(id)) {
131                         throw libsumo::TraCIException("Traffic light '" + id + "' is not known");
132                     }
133                     MSTrafficLightLogic* tls = MSNet::getInstance()->getTLSControl().get(id).getActive();
134                     const std::string& state = tls->getCurrentPhaseDef().getState();
135                     const std::map<std::string, std::string>& params = tls->getParametersMap();
136                     int num = 0;
137                     for (std::map<std::string, std::string>::const_iterator i = params.begin(); i != params.end(); ++i) {
138                         if ("connection:" == (*i).first.substr(0, 11)) {
139                             ++num;
140                         }
141                     }
142 
143                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_COMPOUND);
144                     server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_INTEGER);
145                     server.getWrapperStorage().writeInt(num * 2);
146                     for (std::map<std::string, std::string>::const_iterator i = params.begin(); i != params.end(); ++i) {
147                         if ("connection:" != (*i).first.substr(0, 11)) {
148                             continue;
149                         }
150                         server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_STRING);
151                         server.getWrapperStorage().writeString((*i).second); // foreign id
152                         std::string connection = (*i).first.substr(11);
153                         std::string from, to;
154                         const std::string::size_type b = connection.find("->");
155                         if (b == std::string::npos) {
156                             from = connection;
157                         } else {
158                             from = connection.substr(0, b);
159                             to = connection.substr(b + 2);
160                         }
161                         bool denotesEdge = from.find("_") == std::string::npos;
162                         MSLane* fromLane = nullptr;
163                         const MSTrafficLightLogic::LaneVectorVector& lanes = tls->getLaneVectors();
164                         MSTrafficLightLogic::LaneVectorVector::const_iterator j = lanes.begin();
165                         for (; j != lanes.end() && fromLane == nullptr;) {
166                             for (MSTrafficLightLogic::LaneVector::const_iterator k = (*j).begin(); k != (*j).end() && fromLane == nullptr;) {
167                                 if (denotesEdge && (*k)->getEdge().getID() == from) {
168                                     fromLane = *k;
169                                 } else if (!denotesEdge && (*k)->getID() == from) {
170                                     fromLane = *k;
171                                 }
172                                 if (fromLane == nullptr) {
173                                     ++k;
174                                 }
175                             }
176                             if (fromLane == nullptr) {
177                                 ++j;
178                             }
179                         }
180                         if (fromLane == nullptr) {
181                             return server.writeErrorStatusCmd(libsumo::CMD_GET_TL_VARIABLE, "Could not find edge or lane '" + from + "' in traffic light '" + id + "'.", outputStorage);
182                         }
183                         int pos = (int)std::distance(lanes.begin(), j);
184                         server.getWrapperStorage().writeUnsignedByte(libsumo::TYPE_UBYTE);
185                         server.getWrapperStorage().writeUnsignedByte(state[pos]); // state
186                     }
187                     break;
188                 }
189                 default:
190                     return server.writeErrorStatusCmd(libsumo::CMD_GET_TL_VARIABLE, "Get TLS Variable: unsupported variable " + toHex(variable, 2) + " specified", outputStorage);
191             }
192         }
193     } catch (libsumo::TraCIException& e) {
194         return server.writeErrorStatusCmd(libsumo::CMD_GET_TL_VARIABLE, e.what(), outputStorage);
195     }
196     server.writeStatusCmd(libsumo::CMD_GET_TL_VARIABLE, libsumo::RTYPE_OK, "", outputStorage);
197     server.writeResponseWithLength(outputStorage, server.getWrapperStorage());
198     return true;
199 }
200 
201 
202 bool
processSet(TraCIServer & server,tcpip::Storage & inputStorage,tcpip::Storage & outputStorage)203 TraCIServerAPI_TrafficLight::processSet(TraCIServer& server, tcpip::Storage& inputStorage,
204                                         tcpip::Storage& outputStorage) {
205     std::string warning = ""; // additional description for response
206     // variable
207     const int variable = inputStorage.readUnsignedByte();
208     if (variable != libsumo::TL_PHASE_INDEX && variable != libsumo::TL_PROGRAM && variable != libsumo::TL_PHASE_DURATION
209             && variable != libsumo::TL_RED_YELLOW_GREEN_STATE && variable != libsumo::TL_COMPLETE_PROGRAM_RYG
210             && variable != libsumo::VAR_NAME
211             && variable != libsumo::VAR_PARAMETER) {
212         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "Change TLS State: unsupported variable " + toHex(variable, 2) + " specified", outputStorage);
213     }
214     const std::string id = inputStorage.readString();
215     try {
216         switch (variable) {
217             case libsumo::TL_PHASE_INDEX: {
218                 int index = 0;
219                 if (!server.readTypeCheckingInt(inputStorage, index)) {
220                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The phase index must be given as an integer.", outputStorage);
221                 }
222                 libsumo::TrafficLight::setPhase(id, index);
223             }
224             break;
225             case libsumo::VAR_NAME: {
226                 std::string name;
227                 if (!server.readTypeCheckingString(inputStorage, name)) {
228                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The phase name must be given as a string.", outputStorage);
229                 }
230                 libsumo::TrafficLight::setPhaseName(id, name);
231             }
232             break;
233             case libsumo::TL_PROGRAM: {
234                 std::string subID;
235                 if (!server.readTypeCheckingString(inputStorage, subID)) {
236                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The program must be given as a string.", outputStorage);
237                 }
238                 libsumo::TrafficLight::setProgram(id, subID);
239             }
240             break;
241             case libsumo::TL_PHASE_DURATION: {
242                 double duration = 0.;
243                 if (!server.readTypeCheckingDouble(inputStorage, duration)) {
244                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The phase duration must be given as a double.", outputStorage);
245                 }
246                 libsumo::TrafficLight::setPhaseDuration(id, duration);
247             }
248             break;
249             case libsumo::TL_RED_YELLOW_GREEN_STATE: {
250                 std::string state;
251                 if (!server.readTypeCheckingString(inputStorage, state)) {
252                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The phase must be given as a string.", outputStorage);
253                 }
254                 libsumo::TrafficLight::setRedYellowGreenState(id, state);
255             }
256             break;
257             case libsumo::TL_COMPLETE_PROGRAM_RYG: {
258                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
259                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "A compound object is needed for setting a new program.", outputStorage);
260                 }
261                 //read itemNo
262                 inputStorage.readInt();
263                 libsumo::TraCILogic logic;
264                 if (!server.readTypeCheckingString(inputStorage, logic.programID)) {
265                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 1. parameter (programID) must be a string.", outputStorage);
266                 }
267                 if (!server.readTypeCheckingInt(inputStorage, logic.type)) {
268                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 2. parameter (type) must be an int.", outputStorage);
269                 }
270                 if (!server.readTypeCheckingInt(inputStorage, logic.currentPhaseIndex)) {
271                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 3. parameter (index) must be an int.", outputStorage);
272                 }
273                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
274                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "A compound object is needed for the phases.", outputStorage);
275                 }
276                 const int numPhases = inputStorage.readInt();
277                 for (int j = 0; j < numPhases; ++j) {
278                     if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
279                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "A compound object is needed for every phase.", outputStorage);
280                     }
281                     int items = inputStorage.readInt();
282                     if (items != 6 && items != 5) {
283                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "A phase compound object requires 5 or 6 items.", outputStorage);
284                     }
285                     double duration = 0., minDuration = 0., maxDuration = 0.;
286                     std::vector<int> next;
287                     std::string name;
288                     if (!server.readTypeCheckingDouble(inputStorage, duration)) {
289                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 4.1. parameter (duration) must be a double.", outputStorage);
290                     }
291                     std::string state;
292                     if (!server.readTypeCheckingString(inputStorage, state)) {
293                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 4.2. parameter (phase) must be a string.", outputStorage);
294                     }
295                     if (!server.readTypeCheckingDouble(inputStorage, minDuration)) {
296                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 4.3. parameter (min duration) must be a double.", outputStorage);
297                     }
298                     if (!server.readTypeCheckingDouble(inputStorage, maxDuration)) {
299                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 4.4. parameter (max duration) must be a double.", outputStorage);
300                     }
301                     auto tmp = inputStorage.readUnsignedByte();
302                     if (tmp != libsumo::TYPE_COMPOUND) {
303                         std::cout << " byte:" << tmp << "\n";
304                         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program 4.5 parameter (next) must be a compound (list of ints).", outputStorage);
305                     }
306                     const int numNext = inputStorage.readInt();
307                     for (int k = 0; k < numNext; k++) {
308                         int tmp;
309                         if (!server.readTypeCheckingInt(inputStorage, tmp)) {
310                             return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 4.5. parameter (next) must be a list of int.", outputStorage);
311                         }
312                         next.push_back(tmp);
313                     }
314                     if (items == 6) {
315                         if (!server.readTypeCheckingString(inputStorage, name)) {
316                             return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 4.6. parameter (name) must be a string.", outputStorage);
317                         }
318                     }
319                     logic.phases.emplace_back(libsumo::TraCIPhase(duration, state, minDuration, maxDuration, next, name));
320                 }
321                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
322                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "set program: 5. parameter (subparams) must be a compound object.", outputStorage);
323                 }
324                 const int numParams = inputStorage.readInt();
325                 for (int j = 0; j < numParams; j++) {
326                     std::vector<std::string> par;
327                     server.readTypeCheckingStringList(inputStorage, par);
328                     logic.subParameter[par[0]] = par[1];
329                 }
330                 libsumo::TrafficLight::setCompleteRedYellowGreenDefinition(id, logic);
331             }
332             break;
333             case libsumo::VAR_PARAMETER: {
334                 if (inputStorage.readUnsignedByte() != libsumo::TYPE_COMPOUND) {
335                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "A compound object is needed for setting a parameter.", outputStorage);
336                 }
337                 //read itemNo
338                 inputStorage.readInt();
339                 std::string name;
340                 if (!server.readTypeCheckingString(inputStorage, name)) {
341                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The name of the parameter must be given as a string.", outputStorage);
342                 }
343                 std::string value;
344                 if (!server.readTypeCheckingString(inputStorage, value)) {
345                     return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, "The value of the parameter must be given as a string.", outputStorage);
346                 }
347                 libsumo::TrafficLight::setParameter(id, name, value);
348             }
349             break;
350             default:
351                 break;
352         }
353     } catch (libsumo::TraCIException& e) {
354         return server.writeErrorStatusCmd(libsumo::CMD_SET_TL_VARIABLE, e.what(), outputStorage);
355     }
356     server.writeStatusCmd(libsumo::CMD_SET_TL_VARIABLE, libsumo::RTYPE_OK, warning, outputStorage);
357     return true;
358 }
359 
360 
361 /****************************************************************************/
362