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