SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TraCITestClient.cpp
Go to the documentation of this file.
1 /****************************************************************************/
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
14 // Copyright (C) 2001-2013 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 /* =========================================================================
25  * included modules
26  * ======================================================================= */
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <vector>
34 #include <iostream>
35 #include <iomanip>
36 #include <fstream>
37 #include <sstream>
38 #include <ctime>
39 #include <cstdlib>
40 
41 #define BUILD_TCPIP
42 #include <foreign/tcpip/storage.h>
43 #include <foreign/tcpip/socket.h>
44 
46 #include <utils/common/SUMOTime.h>
47 #include "TraCITestClient.h"
48 
49 #ifdef CHECK_MEMORY_LEAKS
50 #include <foreign/nvwa/debug_new.h>
51 #endif // CHECK_MEMORY_LEAKS
52 
53 
54 // ===========================================================================
55 // used namespaces
56 // ===========================================================================
57 using namespace testclient;
58 
59 
60 // ===========================================================================
61 // method definitions
62 // ===========================================================================
63 TraCITestClient::TraCITestClient(std::string outputFileName)
64  : outputFileName(outputFileName), answerLog("") {
65  answerLog.setf(std::ios::fixed , std::ios::floatfield); // use decimal format
66  answerLog.setf(std::ios::showpoint); // print decimal point
67  answerLog << std::setprecision(2);
68 }
69 
70 
72  writeResult();
73 }
74 
75 
76 bool
77 TraCITestClient::run(std::string fileName, int port, std::string host) {
78  std::ifstream defFile;
79  std::string fileContentStr;
80  std::stringstream fileContent;
81  std::string lineCommand;
82  std::stringstream msg;
83  int repNo = 1;
84  bool commentRead = false;
85 
86  // try to connect
87  try {
88  TraCIAPI::connect(host, port);
89  } catch (tcpip::SocketException& e) {
90  std::stringstream msg;
91  msg << "#Error while connecting: " << e.what();
92  errorMsg(msg);
93  return false;
94  }
95 
96  // read definition file and trigger commands according to it
97  defFile.open(fileName.c_str());
98  if (!defFile) {
99  msg << "Can not open definition file " << fileName << std::endl;
100  errorMsg(msg);
101  return false;
102  }
103  defFile.unsetf(std::ios::dec);
104 
105  while (defFile >> lineCommand) {
106  repNo = 1;
107  if (lineCommand.compare("%") == 0) {
108  // a comment was read
109  commentRead = !commentRead;
110  continue;
111  }
112  if (commentRead) {
113  // wait until end of comment is reached
114  continue;
115  }
116  if (lineCommand.compare("repeat") == 0) {
117  defFile >> repNo;
118  defFile >> lineCommand;
119  }
120  if (lineCommand.compare("simstep2") == 0) {
121  // read parameter for command simulation step and trigger command
122  std::string time;
123  defFile >> time;
124  for (int i = 0; i < repNo; i++) {
126  }
127  } else if (lineCommand.compare("getvariable") == 0) {
128  // trigger command GetXXXVariable
129  int domID, varID;
130  std::string objID;
131  defFile >> domID >> varID >> objID;
132  commandGetVariable(domID, varID, objID);
133  } else if (lineCommand.compare("getvariable_plus") == 0) {
134  // trigger command GetXXXVariable with one parameter
135  int domID, varID;
136  std::string objID;
137  defFile >> domID >> varID >> objID;
138  std::stringstream msg;
139  tcpip::Storage tmp;
140  setValueTypeDependant(tmp, defFile, msg);
141  std::string msgS = msg.str();
142  if (msgS != "") {
143  errorMsg(msg);
144  }
145  commandGetVariable(domID, varID, objID, &tmp);
146  } else if (lineCommand.compare("subscribevariable") == 0) {
147  // trigger command SubscribeXXXVariable
148  int domID, varNo;
149  std::string beginTime, endTime;
150  std::string objID;
151  defFile >> domID >> objID >> beginTime >> endTime >> varNo;
152  commandSubscribeObjectVariable(domID, objID, string2time(beginTime), string2time(endTime), varNo, defFile);
153  } else if (lineCommand.compare("subscribecontext") == 0) {
154  // trigger command SubscribeXXXVariable
155  int domID, varNo, domain;
156  SUMOReal range;
157  std::string beginTime, endTime;
158  std::string objID;
159  defFile >> domID >> objID >> beginTime >> endTime >> domain >> range >> varNo;
160  commandSubscribeContextVariable(domID, objID, string2time(beginTime), string2time(endTime), domain, range, varNo, defFile);
161  } else if (lineCommand.compare("setvalue") == 0) {
162  // trigger command SetXXXValue
163  int domID, varID;
164  std::string objID;
165  defFile >> domID >> varID >> objID;
166  commandSetValue(domID, varID, objID, defFile);
167  } else {
168  msg << "Error in definition file: " << lineCommand << " is not a valid command";
169  errorMsg(msg);
170  commandClose();
171  close();
172  return false;
173  }
174  }
175  defFile.close();
176  commandClose();
177  close();
178  return true;
179 }
180 
181 
182 // ---------- Commands handling
183 void
186  answerLog << std::endl << "-> Command sent: <SimulationStep2>:" << std::endl;
187  tcpip::Storage inMsg;
188  try {
189  std::string acknowledgement;
190  check_resultState(inMsg, CMD_SIMSTEP2, false, &acknowledgement);
191  answerLog << acknowledgement << std::endl;
193  } catch (tcpip::SocketException& e) {
194  answerLog << e.what() << std::endl;
195  }
196 }
197 
198 
199 void
202  answerLog << std::endl << "-> Command sent: <Close>:" << std::endl;
203  try {
204  tcpip::Storage inMsg;
205  std::string acknowledgement;
206  check_resultState(inMsg, CMD_CLOSE, false, &acknowledgement);
207  answerLog << acknowledgement << std::endl;
208  } catch (tcpip::SocketException& e) {
209  answerLog << e.what() << std::endl;
210  }
211 }
212 
213 
214 void
215 TraCITestClient::commandGetVariable(int domID, int varID, const std::string& objID, tcpip::Storage* addData) {
216  send_commandGetVariable(domID, varID, objID, addData);
217  answerLog << std::endl << "-> Command sent: <GetVariable>:" << std::endl
218  << " domID=" << domID << " varID=" << varID
219  << " objID=" << objID << std::endl;
220  tcpip::Storage inMsg;
221  try {
222  std::string acknowledgement;
223  check_resultState(inMsg, domID, false, &acknowledgement);
224  answerLog << acknowledgement << std::endl;
225  } catch (tcpip::SocketException& e) {
226  answerLog << e.what() << std::endl;
227  return;
228  }
229  check_commandGetResult(inMsg, domID, -1, false);
230  // report result state
231  try {
232  int variableID = inMsg.readUnsignedByte();
233  std::string objectID = inMsg.readString();
234  answerLog << " CommandID=" << (domID + 0x10) << " VariableID=" << variableID << " ObjectID=" << objectID;
235  int valueDataType = inMsg.readUnsignedByte();
236  answerLog << " valueDataType=" << valueDataType;
237  readAndReportTypeDependent(inMsg, valueDataType);
238  } catch (tcpip::SocketException& e) {
239  std::stringstream msg;
240  msg << "Error while receiving command: " << e.what();
241  errorMsg(msg);
242  return;
243  }
244 }
245 
246 
247 void
248 TraCITestClient::commandSetValue(int domID, int varID, const std::string& objID, std::ifstream& defFile) {
249  std::stringstream msg;
250  tcpip::Storage inMsg, tmp;
251  setValueTypeDependant(tmp, defFile, msg);
252  std::string msgS = msg.str();
253  if (msgS != "") {
254  errorMsg(msg);
255  }
256  send_commandSetValue(domID, varID, objID, tmp);
257  answerLog << std::endl << "-> Command sent: <SetValue>:" << std::endl
258  << " domID=" << domID << " varID=" << varID
259  << " objID=" << objID << std::endl;
260  try {
261  std::string acknowledgement;
262  check_resultState(inMsg, domID, false, &acknowledgement);
263  answerLog << acknowledgement << std::endl;
264  } catch (tcpip::SocketException& e) {
265  answerLog << e.what() << std::endl;
266  }
267 }
268 
269 
270 void
271 TraCITestClient::commandSubscribeObjectVariable(int domID, const std::string& objID, int beginTime, int endTime, int varNo, std::ifstream& defFile) {
272  std::vector<int> vars;
273  for (int i = 0; i < varNo; ++i) {
274  int var;
275  defFile >> var;
276  // variable id
277  vars.push_back(var);
278  }
279  send_commandSubscribeObjectVariable(domID, objID, beginTime, endTime, vars);
280  answerLog << std::endl << "-> Command sent: <SubscribeVariable>:" << std::endl
281  << " domID=" << domID << " objID=" << objID << " with " << varNo << " variables" << std::endl;
282  tcpip::Storage inMsg;
283  try {
284  std::string acknowledgement;
285  check_resultState(inMsg, domID, false, &acknowledgement);
286  answerLog << acknowledgement << std::endl;
287  validateSubscription(inMsg);
288  } catch (tcpip::SocketException& e) {
289  answerLog << e.what() << std::endl;
290  }
291 }
292 
293 
294 void
295 TraCITestClient::commandSubscribeContextVariable(int domID, const std::string& objID, int beginTime, int endTime,
296  int domain, SUMOReal range, int varNo, std::ifstream& defFile) {
297  std::vector<int> vars;
298  for (int i = 0; i < varNo; ++i) {
299  int var;
300  defFile >> var;
301  // variable id
302  vars.push_back(var);
303  }
304  send_commandSubscribeObjectContext(domID, objID, beginTime, endTime, domain, range, vars);
305  answerLog << std::endl << "-> Command sent: <SubscribeContext>:" << std::endl
306  << " domID=" << domID << " objID=" << objID << " domain=" << domain << " range=" << range
307  << " with " << varNo << " variables" << std::endl;
308  tcpip::Storage inMsg;
309  try {
310  std::string acknowledgement;
311  check_resultState(inMsg, domID, false, &acknowledgement);
312  answerLog << acknowledgement << std::endl;
313  validateSubscription(inMsg);
314  } catch (tcpip::SocketException& e) {
315  answerLog << e.what() << std::endl;
316  }
317 }
318 
319 
320 // ---------- Report helper
321 void
323  time_t seconds;
324  tm* locTime;
325  std::ofstream outFile(outputFileName.c_str());
326  if (!outFile) {
327  std::cerr << "Unable to write result file" << std::endl;
328  }
329  time(&seconds);
330  locTime = localtime(&seconds);
331  outFile << "TraCITestClient output file. Date: " << asctime(locTime) << std::endl;
332  outFile << answerLog.str();
333  outFile.close();
334 }
335 
336 
337 void
338 TraCITestClient::errorMsg(std::stringstream& msg) {
339  std::cerr << msg.str() << std::endl;
340  answerLog << "----" << std::endl << msg.str() << std::endl;
341 }
342 
343 
344 
345 
346 
347 
348 bool
350  try {
351  int noSubscriptions = inMsg.readInt();
352  for (int s = 0; s < noSubscriptions; ++s) {
353  if (!validateSubscription(inMsg)) {
354  return false;
355  }
356  }
357  } catch (std::invalid_argument& e) {
358  answerLog << "#Error while reading message:" << e.what() << std::endl;
359  return false;
360  }
361  return true;
362 }
363 
364 
365 bool
367  try {
368  int length = inMsg.readUnsignedByte();
369  if (length == 0) {
370  length = inMsg.readInt();
371  }
372  int cmdId = inMsg.readUnsignedByte();
374  answerLog << " CommandID=" << cmdId;
375  answerLog << " ObjectID=" << inMsg.readString();
376  unsigned int varNo = inMsg.readUnsignedByte();
377  answerLog << " #variables=" << varNo << std::endl;
378  for (unsigned int i = 0; i < varNo; ++i) {
379  answerLog << " VariableID=" << inMsg.readUnsignedByte();
380  bool ok = inMsg.readUnsignedByte() == RTYPE_OK;
381  answerLog << " ok=" << ok;
382  int valueDataType = inMsg.readUnsignedByte();
383  answerLog << " valueDataType=" << valueDataType;
384  readAndReportTypeDependent(inMsg, valueDataType);
385  }
387  answerLog << " CommandID=" << cmdId;
388  answerLog << " ObjectID=" << inMsg.readString();
389  answerLog << " Domain=" << inMsg.readUnsignedByte();
390  unsigned int varNo = inMsg.readUnsignedByte();
391  answerLog << " #variables=" << varNo << std::endl;
392  unsigned int objNo = inMsg.readInt();
393  answerLog << " #objects=" << objNo << std::endl;
394  for (unsigned int j = 0; j < objNo; ++j) {
395  answerLog << " ObjectID=" << inMsg.readString() << std::endl;
396  for (unsigned int i = 0; i < varNo; ++i) {
397  answerLog << " VariableID=" << inMsg.readUnsignedByte();
398  bool ok = inMsg.readUnsignedByte() == RTYPE_OK;
399  answerLog << " ok=" << ok;
400  int valueDataType = inMsg.readUnsignedByte();
401  answerLog << " valueDataType=" << valueDataType;
402  readAndReportTypeDependent(inMsg, valueDataType);
403  }
404  }
405  } else {
406  answerLog << "#Error: received response with command id: " << cmdId << " but expected a subscription response (0xe0-0xef / 0x90-0x9f)" << std::endl;
407  return false;
408  }
409  } catch (std::invalid_argument& e) {
410  answerLog << "#Error while reading message:" << e.what() << std::endl;
411  return false;
412  }
413  return true;
414 }
415 
416 
417 
418 
419 
420 
421 
422 // ---------- Conversion helper
423 int
424 TraCITestClient::setValueTypeDependant(tcpip::Storage& into, std::ifstream& defFile, std::stringstream& msg) {
425  std::string dataTypeS, valueS;
426  defFile >> dataTypeS;
427  if (dataTypeS == "<airDist>") {
429  return 1;
430  } else if (dataTypeS == "<drivingDist>") {
432  return 1;
433  } else if (dataTypeS == "<objSubscription>") {
434  int beginTime, endTime, numVars;
435  defFile >> beginTime >> endTime >> numVars;
436  into.writeInt(beginTime);
437  into.writeInt(endTime);
438  into.writeInt(numVars);
439  for (int i = 0; i < numVars; ++i) {
440  int var;
441  defFile >> var;
442  into.writeUnsignedByte(var);
443  }
444  return 4 + 4 + 4 + numVars;
445  }
446  defFile >> valueS;
447  if (dataTypeS == "<int>") {
449  into.writeInt(atoi(valueS.c_str()));
450  return 4 + 1;
451  } else if (dataTypeS == "<byte>") {
453  into.writeByte(atoi(valueS.c_str()));
454  return 1 + 1;
455  } else if (dataTypeS == "<ubyte>") {
457  into.writeUnsignedByte(atoi(valueS.c_str()));
458  return 1 + 1;
459  } else if (dataTypeS == "<float>") {
461  into.writeFloat(float(atof(valueS.c_str())));
462  return 4 + 1;
463  } else if (dataTypeS == "<double>") {
465  into.writeDouble(atof(valueS.c_str()));
466  return 8 + 1;
467  } else if (dataTypeS == "<string>") {
469  into.writeString(valueS);
470  return 4 + 1 + (int) valueS.length();
471  } else if (dataTypeS == "<string*>") {
472  std::vector<std::string> slValue;
473  int number = atoi(valueS.c_str());
474  int length = 1 + 4;
475  for (int i = 0; i < number; ++i) {
476  std::string tmp;
477  defFile >> tmp;
478  slValue.push_back(tmp);
479  length += 4 + int(tmp.length());
480  }
482  into.writeStringList(slValue);
483  return length;
484  } else if (dataTypeS == "<compound>") {
485  int number = atoi(valueS.c_str());
487  into.writeInt(number);
488  int length = 1 + 4;
489  for (int i = 0; i < number; ++i) {
490  length += setValueTypeDependant(into, defFile, msg);
491  }
492  return length;
493  } else if (dataTypeS == "<color>") {
495  into.writeUnsignedByte(atoi(valueS.c_str()));
496  for (int i = 0; i < 3; ++i) {
497  defFile >> valueS;
498  into.writeUnsignedByte(atoi(valueS.c_str()));
499  }
500  return 1 + 4;
501  } else if (dataTypeS == "<position2D>") {
503  into.writeDouble(atof(valueS.c_str()));
504  defFile >> valueS;
505  into.writeDouble(atof(valueS.c_str()));
506  return 1 + 8 + 8;
507  } else if (dataTypeS == "<position3D>") {
509  into.writeDouble(atof(valueS.c_str()));
510  defFile >> valueS;
511  into.writeDouble(atof(valueS.c_str()));
512  defFile >> valueS;
513  into.writeDouble(atof(valueS.c_str()));
514  return 1 + 8 + 8 + 8;
515  } else if (dataTypeS == "<positionRoadmap>") {
517  into.writeString(valueS);
518  int length = 1 + 8 + (int) valueS.length();
519  defFile >> valueS;
520  into.writeDouble(atof(valueS.c_str()));
521  defFile >> valueS;
522  into.writeUnsignedByte(atoi(valueS.c_str()));
523  return length + 4 + 1;
524  } else if (dataTypeS == "<shape>") {
526  int number = atoi(valueS.c_str());
527  into.writeUnsignedByte(number);
528  int length = 1 + 1;
529  for (int i = 0; i < number; ++i) {
530  std::string x, y;
531  defFile >> x >> y;
532  into.writeDouble(atof(x.c_str()));
533  into.writeDouble(atof(y.c_str()));
534  length += 8 + 8;
535  }
536  return length;
537  }
538  msg << "## Unknown data type: " << dataTypeS;
539  return 0;
540 }
541 
542 
543 void
545  if (valueDataType == TYPE_UBYTE) {
546  int ubyte = inMsg.readUnsignedByte();
547  answerLog << " Unsigned Byte Value: " << ubyte << std::endl;
548  } else if (valueDataType == TYPE_BYTE) {
549  int byte = inMsg.readByte();
550  answerLog << " Byte value: " << byte << std::endl;
551  } else if (valueDataType == TYPE_INTEGER) {
552  int integer = inMsg.readInt();
553  answerLog << " Int value: " << integer << std::endl;
554  } else if (valueDataType == TYPE_FLOAT) {
555  float floatv = inMsg.readFloat();
556  if (floatv < 0.1 && floatv > 0) {
557  answerLog.setf(std::ios::scientific, std::ios::floatfield);
558  }
559  answerLog << " float value: " << floatv << std::endl;
560  answerLog.setf(std::ios::fixed , std::ios::floatfield); // use decimal format
561  answerLog.setf(std::ios::showpoint); // print decimal point
562  answerLog << std::setprecision(2);
563  } else if (valueDataType == TYPE_DOUBLE) {
564  double doublev = inMsg.readDouble();
565  answerLog << " Double value: " << doublev << std::endl;
566  } else if (valueDataType == TYPE_BOUNDINGBOX) {
567  SUMOReal lowerLeftX = inMsg.readDouble();
568  SUMOReal lowerLeftY = inMsg.readDouble();
569  SUMOReal upperRightX = inMsg.readDouble();
570  SUMOReal upperRightY = inMsg.readDouble();
571  answerLog << " BoundaryBoxValue: lowerLeft x=" << lowerLeftX
572  << " y=" << lowerLeftY << " upperRight x=" << upperRightX
573  << " y=" << upperRightY << std::endl;
574  } else if (valueDataType == TYPE_POLYGON) {
575  int length = inMsg.readUnsignedByte();
576  answerLog << " PolygonValue: ";
577  for (int i = 0; i < length; i++) {
578  SUMOReal x = inMsg.readDouble();
579  SUMOReal y = inMsg.readDouble();
580  answerLog << "(" << x << "," << y << ") ";
581  }
582  answerLog << std::endl;
583  } else if (valueDataType == POSITION_3D) {
584  SUMOReal x = inMsg.readDouble();
585  SUMOReal y = inMsg.readDouble();
586  SUMOReal z = inMsg.readDouble();
587  answerLog << " Position3DValue: " << std::endl;
588  answerLog << " x: " << x << " y: " << y
589  << " z: " << z << std::endl;
590  } else if (valueDataType == POSITION_ROADMAP) {
591  std::string roadId = inMsg.readString();
592  SUMOReal pos = inMsg.readDouble();
593  int laneId = inMsg.readUnsignedByte();
594  answerLog << " RoadMapPositionValue: roadId=" << roadId
595  << " pos=" << pos
596  << " laneId=" << laneId << std::endl;
597  } else if (valueDataType == TYPE_TLPHASELIST) {
598  int length = inMsg.readUnsignedByte();
599  answerLog << " TLPhaseListValue: length=" << length << std::endl;
600  for (int i = 0; i < length; i++) {
601  std::string pred = inMsg.readString();
602  std::string succ = inMsg.readString();
603  int phase = inMsg.readUnsignedByte();
604  answerLog << " precRoad=" << pred << " succRoad=" << succ
605  << " phase=";
606  switch (phase) {
607  case TLPHASE_RED:
608  answerLog << "red" << std::endl;
609  break;
610  case TLPHASE_YELLOW:
611  answerLog << "yellow" << std::endl;
612  break;
613  case TLPHASE_GREEN:
614  answerLog << "green" << std::endl;
615  break;
616  default:
617  answerLog << "#Error: unknown phase value" << (int)phase << std::endl;
618  return;
619  }
620  }
621  } else if (valueDataType == TYPE_STRING) {
622  std::string s = inMsg.readString();
623  answerLog << " string value: " << s << std::endl;
624  } else if (valueDataType == TYPE_STRINGLIST) {
625  std::vector<std::string> s = inMsg.readStringList();
626  answerLog << " string list value: [ " << std::endl;
627  for (std::vector<std::string>::iterator i = s.begin(); i != s.end(); ++i) {
628  if (i != s.begin()) {
629  answerLog << ", ";
630  }
631  answerLog << '"' << *i << '"';
632  }
633  answerLog << " ]" << std::endl;
634  } else if (valueDataType == TYPE_COMPOUND) {
635  int no = inMsg.readInt();
636  answerLog << " compound value with " << no << " members: [ " << std::endl;
637  for (int i = 0; i < no; ++i) {
638  int currentValueDataType = inMsg.readUnsignedByte();
639  answerLog << " valueDataType=" << currentValueDataType;
640  readAndReportTypeDependent(inMsg, currentValueDataType);
641  }
642  answerLog << " ]" << std::endl;
643  } else if (valueDataType == POSITION_2D) {
644  SUMOReal xv = inMsg.readDouble();
645  SUMOReal yv = inMsg.readDouble();
646  answerLog << " position value: (" << xv << "," << yv << ")" << std::endl;
647  } else if (valueDataType == TYPE_COLOR) {
648  int r = inMsg.readUnsignedByte();
649  int g = inMsg.readUnsignedByte();
650  int b = inMsg.readUnsignedByte();
651  int a = inMsg.readUnsignedByte();
652  answerLog << " color value: (" << r << "," << g << "," << b << "," << a << ")" << std::endl;
653  } else {
654  answerLog << "#Error: unknown valueDataType!" << std::endl;
655  }
656 }
657 
658