$search
00001 /* 00002 Aseba - an event-based framework for distributed robot control 00003 Copyright (C) 2007--2012: 00004 Stephane Magnenat <stephane at magnenat dot net> 00005 (http://stephane.magnenat.net) 00006 and other contributors, see authors.txt for details 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU Lesser General Public License as published 00010 by the Free Software Foundation, version 3 of the License. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include "../common/consts.h" 00022 #include "../msg/msg.h" 00023 #include "../utils/utils.h" 00024 #include <dashel/dashel.h> 00025 #include "../transport/dashel_plugins/dashel-plugins.h" 00026 #include <time.h> 00027 #include <iostream> 00028 #include <cstring> 00029 #include <string> 00030 #include <deque> 00031 00032 namespace Aseba 00033 { 00034 using namespace Dashel; 00035 using namespace std; 00036 00041 00044 class Player : public Hub 00045 { 00046 private: 00047 typedef deque<string> StringList; 00048 00049 bool respectTimings; 00050 int speedFactor; 00051 Stream* in; 00052 string line; 00053 UnifiedTime lastTimeStamp; 00054 UnifiedTime lastEventTime; 00055 00056 public: 00057 Player(const char* inputFile, bool respectTimings, int speedFactor) : 00058 respectTimings(respectTimings), 00059 speedFactor(speedFactor), 00060 lastTimeStamp(0) 00061 { 00062 if (inputFile) 00063 in = connect("file:" + string(inputFile) + ";mode=read"); 00064 else 00065 in = connect("stdin:"); 00066 } 00067 00068 StringList tokenize(const string& input) 00069 { 00070 StringList list; 00071 const size_t inputSize(input.size()); 00072 00073 size_t pos(0); 00074 while ((pos != string::npos) && (pos < inputSize)) 00075 { 00076 const size_t next = input.find(' ', pos); 00077 string word; 00078 if (next != string::npos) 00079 word = input.substr(pos, next-pos); 00080 else 00081 word = input.substr(pos); 00082 if (!word.empty()) 00083 list.push_back(word); 00084 pos = next + 1; 00085 } 00086 00087 return list; 00088 } 00089 00090 void sendLine() 00091 { 00092 // parse line and build user message 00093 UserMessage userMessage; 00094 00095 StringList tokenizedLine(tokenize(line)); 00096 00097 UnifiedTime timeStamp(UnifiedTime::fromRawTimeString(tokenizedLine.front())); 00098 tokenizedLine.pop_front(); 00099 00100 userMessage.source = atoi(tokenizedLine.front().c_str()); 00101 tokenizedLine.pop_front(); 00102 00103 userMessage.type = atoi(tokenizedLine.front().c_str()); 00104 tokenizedLine.pop_front(); 00105 00106 userMessage.data.reserve(size_t(atoi(tokenizedLine.front().c_str()))); 00107 tokenizedLine.pop_front(); 00108 00109 while (!tokenizedLine.empty()) 00110 { 00111 userMessage.data.push_back(atoi(tokenizedLine.front().c_str())); 00112 tokenizedLine.pop_front(); 00113 } 00114 00115 // if required, sleep 00116 if ((respectTimings) && (lastTimeStamp.value != 0)) 00117 { 00118 const UnifiedTime lostTime(UnifiedTime() - lastEventTime); 00119 const UnifiedTime deltaTimeStamp(timeStamp - lastTimeStamp); 00120 if (lostTime < deltaTimeStamp) 00121 { 00122 UnifiedTime waitTime(deltaTimeStamp - lostTime); 00123 waitTime /= speedFactor; 00124 waitTime.sleep(); 00125 } 00126 } 00127 00128 // write message on all connected streams 00129 for (StreamsSet::iterator it = dataStreams.begin(); it != dataStreams.end();++it) 00130 { 00131 Stream* destStream(*it); 00132 if (destStream != in) 00133 { 00134 userMessage.serialize(destStream); 00135 destStream->flush(); 00136 } 00137 } 00138 00139 lastEventTime = UnifiedTime(); 00140 lastTimeStamp = timeStamp; 00141 00142 line.clear(); 00143 } 00144 00145 protected: 00146 00147 void connectionCreated(Stream *stream) 00148 { 00149 //cerr << "got connection " << stream->getTargetName() << endl; 00150 } 00151 00152 void incomingData(Stream *stream) 00153 { 00154 char c(stream->read<char>()); 00155 if (stream == in) 00156 { 00157 if (c == '\n') 00158 sendLine(); 00159 else 00160 line += c; 00161 } 00162 } 00163 00164 void connectionClosed(Stream *stream, bool abnormal) 00165 { 00166 if (stream == in) 00167 stop(); 00168 } 00169 }; 00170 00172 } 00173 00174 00176 void dumpHelp(std::ostream &stream, const char *programName) 00177 { 00178 stream << "Aseba play, play recorded user messages from a file or stdin, usage:\n"; 00179 stream << programName << " [options] [targets]*\n"; 00180 stream << "Options:\n"; 00181 stream << "--fast : replay messages twice the speed of real time\n"; 00182 stream << "--faster : replay messages four times the speed of real time\n"; 00183 stream << "--fastest : replay messages as fast as possible\n"; 00184 stream << "-f INPUT_FILE : open INPUT_FILE instead of stdin\n"; 00185 stream << "-h, --help : shows this help\n"; 00186 stream << "-V, --version : shows the version number\n"; 00187 stream << "Targets are any valid Dashel targets." << std::endl; 00188 stream << "Report bugs to: aseba-dev@gna.org" << std::endl; 00189 } 00190 00192 void dumpVersion(std::ostream &stream) 00193 { 00194 stream << "Aseba play " << ASEBA_VERSION << std::endl; 00195 stream << "Aseba protocol " << ASEBA_PROTOCOL_VERSION << std::endl; 00196 stream << "Licence LGPLv3: GNU LGPL version 3 <http://www.gnu.org/licenses/lgpl.html>\n"; 00197 } 00198 00199 int main(int argc, char *argv[]) 00200 { 00201 Dashel::initPlugins(); 00202 bool respectTimings = true; 00203 int speedFactor = 1; 00204 std::vector<std::string> targets; 00205 const char* inputFile = 0; 00206 00207 int argCounter = 1; 00208 00209 while (argCounter < argc) 00210 { 00211 const char *arg = argv[argCounter]; 00212 00213 if (strcmp(arg, "--fastest") == 0) 00214 { 00215 respectTimings = false; 00216 } 00217 else if (strcmp(arg, "--fast") == 0) 00218 { 00219 speedFactor = 2; 00220 } 00221 else if (strcmp(arg, "--faster") == 0) 00222 { 00223 speedFactor = 4; 00224 } 00225 else if ((strcmp(arg, "-h") == 0) || (strcmp(arg, "--help") == 0)) 00226 { 00227 dumpHelp(std::cout, argv[0]); 00228 return 0; 00229 } 00230 else if ((strcmp(arg, "-V") == 0) || (strcmp(arg, "--version") == 0)) 00231 { 00232 dumpVersion(std::cout); 00233 return 0; 00234 } 00235 else if (strcmp(arg, "-f") == 0) 00236 { 00237 argCounter++; 00238 if (argCounter >= argc) 00239 { 00240 dumpHelp(std::cout, argv[0]); 00241 return 1; 00242 } 00243 else 00244 inputFile = argv[argCounter]; 00245 } 00246 else 00247 { 00248 targets.push_back(argv[argCounter]); 00249 } 00250 argCounter++; 00251 } 00252 00253 if (targets.empty()) 00254 targets.push_back(ASEBA_DEFAULT_TARGET); 00255 00256 try 00257 { 00258 Aseba::Player player(inputFile, respectTimings, speedFactor); 00259 for (size_t i = 0; i < targets.size(); i++) 00260 player.connect(targets[i]); 00261 player.run(); 00262 } 00263 catch(Dashel::DashelException e) 00264 { 00265 std::cerr << e.what() << std::endl; 00266 } 00267 00268 return 0; 00269 }