1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
#ifdef WIN32
  #include <conio.h>
  #include <windows.h>
  #include <winbase.h>
#else
  #include <unistd.h>
  #include <fcntl.h>
  #include "myconio.h"
#endif //WIN32

#include <sstream>
#include <cctype>

#include "Simulator.h"

#include "Tools/ThreadUtil.h"
#include "Tools/NaoTime.h"

#include <Messages/Framework-Representations.pb.h>

#include "Tools/Math/Common.h"
#include "PlatformInterface/Platform.h"

using namespace std;
using namespace naoth;

Simulator::Simulator(const std::string& filePath, bool backendMode, bool realTime, unsigned short port)
  : 
  backendMode(backendMode),
  realTime(realTime),
  logFileScanner(filePath),
  lastFrameTime(0),
  simulatedTime(0),
  simulatedFrameNumber(0),
  debugPort(port)
{
  // TODO: we need a better solution for it, but now it's the 
  // fastest way to provide stuff for motion
  // register basic sensor input
  registerInput<AccelerometerData>(*this);
  registerInput<SensorJointData>(*this);
  registerInput<Image>(*this);
  registerInput<ImageTop>(*this);
  registerInput<FSRData>(*this);
  registerInput<GyrometerData>(*this);
  registerInput<InertialSensorData>(*this);
  registerInput<CurrentCameraSettings>(*this);
  registerInput<ButtonData>(*this);
  registerInput<BatteryData>(*this);
  registerInput<UltraSoundReceiveData>(*this);

  registerInput<FrameInfo>(*this);

  registerInput<DebugMessageInCognition>(*this);
  registerInput<DebugMessageInMotion>(*this);
  registerOutput<DebugMessageOut>(*this);

  jumpToBegin();
}

void Simulator::open(const std::string& filePath) 
{
  logFileScanner.open(filePath);
  lastFrameTime = 0;
  //simulatedTime = 0;
  //simulatedFrameNumber = 0;

  jumpToBegin();
}

void Simulator::init()
{  
  lastFrameTime = 0;
  simulatedTime = 0;
  theDebugServer.start(debugPort);
  theDebugServer.setTimeOut(0);
}

void Simulator::printRepresentations()
{
  // list all representations included in the logfile
  std::cout << "-----------------------------------------" << std::endl;
  std::cout << "Representations contained in the logfile:" << std::endl;
  for(std::set<std::string>::iterator itIncluded = logFileScanner.getIncludedRepresentations().begin();
    itIncluded != logFileScanner.getIncludedRepresentations().end(); itIncluded++)
  {
    std::cout << *itIncluded << std::endl;
  }
  std::cout << "-----------------------------------------" << std::endl;
}

void Simulator::printHelp()
{
  cout << endl;
  cout << "Welcome to the NaoTH logfile based simulator" << endl;
  cout << "--------------------------------------------" << endl << endl;

  cout << "\"WASD\"-control" << endl;
  cout << "d - one step forward" << endl;
  cout << "a - one step back" << endl;
  cout << "w - to the beginning" << endl;
  cout << "s - to the end" << endl << endl;

  cout << "g - jump to specific frame" << endl;
  cout << "p - play to end (end by pressing p again)" << endl;
  cout << "l - play loop (end by pressing l again)" << endl;
  cout << "r - repeat a frame" << endl;
  cout << "q or x - quit/exit" << endl << endl;

  cout << "After a frame was executed you will always get a line showing you the current frame and the minimal and maximal frame number" << endl;
}//end printHelp

void Simulator::printCurrentLineInfo()
{
  if(logFileScanner.begin() == logFileScanner.end()) {
    if(backendMode) {
      cout << "The logfile seems to be empty." << std::endl;
    } else {
      cout << "The logfile seems to be empty.\t\r";
    }
    return;
  }
  
  LogFileScanner::FrameIterator begin = logFileScanner.begin();
  LogFileScanner::FrameIterator end = logFileScanner.last();

  // output some informations about the current frame
  if(backendMode) {
    cout << "[" << *currentFrame << "|" << *begin << "-" << *end << "]" << std::endl;
  } else {
    cout << "[" << *currentFrame << "|" << *begin << "-" << *end << "]\t\r";
  }
}//end printCurrentLineInfo

char Simulator::getInput()
{
  int input;
  if (backendMode) {
    input = getchar();
  } else {
    input = getch();
  }
  return static_cast<char>(std::tolower(input));
}

void Simulator::main(bool autostart)
{
  init();

  printRepresentations();
  printHelp();

  jumpToBegin();
	if (autostart){
		play(false);
	}
	else{
		char c;
		while ((c = getInput()) && c != 'q' && c != 'x')
		{
			if (c == 'd') {
				stepForward();
			}
			else if (c == 'a') {
				stepBack();
			}
			else if (c == 'w') {
				jumpToBegin();
			}
			else if (c == 's') {
				jumpToEnd();
			}
			else if (c == 'g') {
				// read jump position
				unsigned int jpos;
				cout << " goto position: ";
				cin >> jpos;
				jumpTo(jpos);
			}
			else if (c == 'p') {
				play(false);
			}
			else if (c == 'l') {
				play(true);
			}
			else if (c == 'r') {
				executeCurrentFrame();
			}
			else if (c == 'h') {
				printHelp();
				printCurrentLineInfo();
			}
		}// while
	}
  
  cout << endl << "bye bye!" << endl;
}//end main

void Simulator::play(bool loop)
{
#ifdef WIN32
  //cerr << "Play-Support now yet enabled under Windows" << endl;
#else
  // set terminal to non-blocking...
  const int fd = fileno(stdin);
  const int fcflags = fcntl(fd,F_GETFL);
  if (fcntl(fd,F_SETFL,fcflags | O_NONBLOCK) <0)
  {
    cerr << "Could not set terminal to non-blocking mode" << endl;
    cerr << "\"Play\" capatibility not available on this terminal" << endl;
    return;
  }
#endif //WIN32

  int c = -1;
  while(c != 'l' && c != 'p' && c != '\n' && c != 's' && c != 'q' && c !='x')
  {
    // execute the frame and calculate the time to wait
    unsigned int simulatedTimeBefore = simulatedTime;
    unsigned int startTime = NaoTime::getNaoTimeInMilliSeconds();
    stepForward();
    unsigned int calculationTime = NaoTime::getNaoTimeInMilliSeconds() - startTime;
    unsigned int maxTimeToWait = realTime?simulatedTime - simulatedTimeBefore:33;

    // wait at least 5ms but max 1s
    unsigned int waitTime = Math::clamp((int)maxTimeToWait - (int)calculationTime, 5, 1000);
    ThreadUtil::sleep(waitTime);

#ifdef WIN32
    if(_kbhit()) {
      c = getInput();
    }
#else
    c = getInput();
#endif

    if(!loop && currentFrame == logFileScanner.last()) {
      break;
    }
  }//while

#ifdef WIN32
  //cerr << "Play-Support now yet enabled under Windows" << endl;
#else
  // set back to blocking
  if (fcntl(fd,F_SETFL,fcflags) <0)
  {
    cerr << "Could not set terminal to blocking mode" << endl;
    cerr << "terminating since this is a serious error" << endl;
    exit(EXIT_FAILURE);
  }
#endif //WIN32
}//end play

void Simulator::stepForward()
{
  currentFrame++;
  if(currentFrame == logFileScanner.end()) {
    jumpToBegin();
  } else {
    executeCurrentFrame();
  }
}

void Simulator::stepBack()
{
  if(currentFrame == logFileScanner.begin()) {
    jumpToEnd();
  } else {
    currentFrame--;
    executeCurrentFrame();
  }
}

void Simulator::jumpToBegin()
{
  currentFrame = logFileScanner.begin();
  executeCurrentFrame();
}

void Simulator::jumpToEnd()
{
  currentFrame = logFileScanner.end();
  currentFrame--;
  executeCurrentFrame();
}

void Simulator::jumpTo(unsigned int position)
{
  // do it the stupid way...
  bool wasFound = false;
  LogFileScanner::FrameIterator oldPos = currentFrame;
  currentFrame = logFileScanner.begin();
  while(!wasFound && currentFrame != logFileScanner.end())
  {
    if(*currentFrame == position) {
      wasFound = true;
      break;
    } else {
      currentFrame++;
    }
  }//end while

  if(wasFound) {
    executeCurrentFrame();
  } else {
    cout << "frame not found!" << endl;
    currentFrame = oldPos;
    printCurrentLineInfo();
  }
}//end jumpTo



void Simulator::executeCurrentFrame()
{
  logFileScanner.readFrame(*currentFrame, representations);
  
  //
  adjust_frame_time();
    
  // execute
  runCognition();
  runMotion();
  
  //std::cout << "end executeCurrentFrame" << std::endl;

  printCurrentLineInfo();

}//end executeCurrentFrame


void Simulator::adjust_frame_time()
{
  naothmessages::FrameInfo f;

  // default time since the last frame
  int time_delta = 33; // default time step simulating 30fps
  
  // if no FrameInfo was logged set it manually
  LogFileScanner::RepresentationData& frameData = representations["FrameInfo"];
  if(!frameData.valid)
  {
    f.set_framenumber(*currentFrame);
    lastFrameTime = 0;
  }
  else
  {
    // read the actual frame info
    f.ParseFromArray(frameData.data.data(), (int) frameData.data.size());
    unsigned int frameTime = f.time();

    // logged time since the last frame
    if(lastFrameTime != 0) {
      time_delta = (int)frameTime - (int)lastFrameTime;
    }

    // remember the current time for next cycle
    lastFrameTime = frameTime;
  }

  if(time_delta <= 0) {
    time_delta = 33; // default time step simulating 30fps
  }

  simulatedTime += time_delta;
  f.set_time(simulatedTime);

  f.set_framenumber(simulatedFrameNumber++);
  
  // write the result back
  string result = f.SerializeAsString();
  frameData.data.resize(result.size());
  std::copy ( result.begin(), result.end(), frameData.data.begin() );
  frameData.valid = true;
}//end adjust_frame_time


///// Getter/Setter /////

template<class T>
void Simulator::generalGet(T& data, std::string name) const
{
  LogFileScanner::Frame::const_iterator iter = representations.find(name); 
  if(iter != representations.end() && iter->second.valid)
  {
    std::istrstream stream(iter->second.data.data(), iter->second.data.size());
    Serializer<T>::deserialize(stream, data);
  }
}//end generalGet


///// end Getter/Setter /////

MessageQueue* Simulator::createMessageQueue(const std::string& /*name*/)
{
  // for single thread
  return new MessageQueue();
}