vrpn  07.33
Virtual Reality Peripheral Network
vrpn_FileConnection.h
Go to the documentation of this file.
1 #ifndef VRPN_FILE_CONNECTION_H
2 #define VRPN_FILE_CONNECTION_H
3 
4 // {{{ vrpn_File_Connection
5 //
6 // Tom Hudson, June 1998
7 
8 // This class *reads* a file written out by vrpn_Connection's logging hooks.
9 
10 // The interface exactly matches that of vrpn_Connection. To do things that
11 // are meaningful on log replay but not on live networks, create a
12 // vrpn_File_Controller and pass your vrpn_File_Connection to its constructor,
13 // or just ask the Connection for its file connection pointer and do the
14 // operations directly on the FileConnection if the pointer is non-NULL.
15 
16 // Logfiles are recorded as *sent*, not as translated by the receiver,
17 // so we still need to have all the correct names for senders and types
18 // registered.
19 
20 // September 1998: by default preloads the entire log file on startup.
21 // This causes a delay (nontrivial for large logs) but should help smooth
22 // playback.
23 // }}}
24 
25 #include <stdio.h> // for NULL, FILE
26 
27 #include "vrpn_Configure.h" // for VRPN_API, VRPN_CALLBACK
28 #include "vrpn_Connection.h" // for vrpn_LOGLIST (ptr only), etc
29 #include "vrpn_Shared.h" // for timeval
30 #include "vrpn_Types.h" // for vrpn_float32, vrpn_int32, etc
31 
32 struct timeval;
33 
34 // Global variable used to indicate whether File Connections should
35 // pre-load all of their records into memory when opened. This is the
36 // default behavior, but fails on very large files that eat up all
37 // of the memory. This defaults to "true". User code should set this
38 // to "false" before calling vrpn_get_connection_by_name() or creating
39 // a new vrpn_File_Connection object if it wants that file connection
40 // to not preload. The value is only checked at connection creation time;
41 // the connection behaves consistently once created. This operation is
42 // useful for applications that load large data files and don't want to
43 // wait for them to pre-load.
44 
46 
47 // Global variable used to indicate whether File Connections should
48 // keep already-read messages stored in memory. If not, then we have
49 // to re-load the file starting at the beginning on rewind. This
50 // defaults to "true". User code should set this
51 // to "false" before calling vrpn_get_connection_by_name() or creating
52 // a new vrpn_File_Connection object if it wants that file connection
53 // to not preload. The value is only checked at connection creation time;
54 // the connection behaves consistently once created. This operation is
55 // useful for applications that read through large data files and
56 // don't have enough memory to keep them in memory at once, or for applications
57 // that read through only once and have no need to go back and check.
58 
60 
61 // Global variable used to indicate whether File Connections should
62 // play through all system messages and get to the first user message
63 // when opened or reset to the beginning. This defaults to "true".
64 // User code should set this
65 // to "false" before calling vrpn_get_connection_by_name() or creating
66 // a new vrpn_File_Connection object if it wants that file connection
67 // to not preload. The value is only checked at connection creation time;
68 // the connection behaves consistently once created. Leaving this true
69 // can help with offsets in time that happen at the beginning of files.
70 
72 
74 public:
75  vrpn_File_Connection(const char *station_name,
76  const char *local_in_logfile_name = NULL,
77  const char *local_out_logfile_name = NULL);
78  virtual ~vrpn_File_Connection(void);
79 
80  virtual int mainloop(const timeval *timeout = NULL);
81 
82  // returns the elapsed time in the file
83  virtual int time_since_connection_open(timeval *elapsed_time);
84 
85  // returns the current time in the file since the epoch (UTC time).
86  virtual timeval get_time() { return d_time; }
87 
89 
90  // Pretend to send pending report, really just clear the buffer.
91  virtual int send_pending_reports(void);
92 
93  // {{{ fileconnections-specific methods (playback control)
94 public:
95  // XXX the following should not be public if we want vrpn_File_Connection
96  // to have the same interface as vrpn_Connection
97  //
98  // If so handler functions for messages for these operations
99  // should be made, and functions added to vrpn_File_Controller which
100  // generate the messages. This seemed like it would be messy
101  // since most of these functions have return values
102 
103  // rate of 0.0 is paused, 1.0 is normal speed
104  void set_replay_rate(vrpn_float32 rate)
105  {
106  d_filetime_accum.set_replay_rate(rate);
107  }
108 
109  vrpn_float32 get_replay_rate() { return d_filetime_accum.replay_rate(); }
110 
111  // resets to the beginning of the file
112  // returns 0 on success
113  int reset(void);
114 
115  // returns 1 if we're at the end of file
116  int eof();
117 
118  // end_time for play_to_time() is an elapsed time
119  // returns -1 on error or EOF, 0 on success
120  int play_to_time(vrpn_float64 end_time);
121  int play_to_time(timeval end_time);
122 
123  // end_filetime is an absolute time, corresponding to the
124  // timestamps of the entries in the file,
125  // returns -1 on error or EOF, 0 on success
126  int play_to_filetime(const timeval end_filetime);
127 
128  // plays the next entry, returns -1 or error or EOF, 0 otherwise
129  int playone();
130 
131  // plays at most one entry, but won't play past end_filetime
132  // returns 0 on success, 1 if at end_filetime, -1 on error or EOF
133  int playone_to_filetime(timeval end_filetime);
134 
135  // returns the elapsed time of the file
136  timeval get_length();
137  double get_length_secs();
138 
139  // returns the timestamp of the earliest in time user message
140  timeval get_lowest_user_timestamp();
141 
142  // returns the timestamp of the greatest-in-time user message
143  timeval get_highest_user_timestamp();
144 
145  // returns the name of the file
146  const char *get_filename();
147 
148  // jump_to_time sets the current position to the given elapsed time
149  // return 1 if we got to the specified time and 0 if we didn't
150  int jump_to_time(vrpn_float64 newtime);
151  int jump_to_time(timeval newtime);
152 
153  // jump_to_filetime sets the current position to the given absolute time
154  // return 1 if we got to the specified time and 0 if we didn't
155  int jump_to_filetime(timeval absolute_time);
156 
157  // Limits the number of messages played out on any one call to mainloop.
158  // 0 => no limit.
159  // Used to stop continuous callback-handling when messages arrive
160  // at a very high rate (such as from a vrpn_Imager) or to make sure
161  // that we are able to pause after each frame in frame-by-frame
162  // playback for tracking analysis programs.
163  void limit_messages_played_back(vrpn_uint32 max_playback)
164  {
165  Jane_stop_this_crazy_thing(max_playback);
166  };
167 
168  // }}}
169  // {{{ tokens for VRPN control messages (data members)
170 protected:
171  vrpn_int32 d_controllerId;
172 
174  vrpn_int32 d_reset_type;
176  // long d_jump_to_time_type;
177 
178  // }}}
179  // {{{ time-keeping
180 protected:
181  timeval d_last_told; // Last time we printed error about no open file.
182  timeval d_time; // current time in file
183  timeval d_start_time; // time of first record in file
184  timeval d_earliest_user_time; // time of first user message
186  timeval d_highest_user_time; // time of last user message
188 
189  // finds the timestamps of the earliest and highest-time user messages
190  void find_superlative_user_times();
191 
192  // these are to be used internally when jumping around in the
193  // stream (e.g., for finding the earliest and latest timed
194  // user messages). They assume
195  // 1) that only functions such as advance_currentLogEntry,
196  // read_entry and manual traversal of d_logHead/d_logTail
197  // will be used.
198  // the functions return false if they don't save or restore the bookmark
200  public:
203  bool valid;
204  timeval oldTime;
205  long int file_pos; // ftell result
206  vrpn_LOGLIST *oldCurrentLogEntryPtr; // just a pointer, useful for accum
207  // or preload
208  vrpn_LOGLIST *oldCurrentLogEntryCopy; // a deep copy, useful for
209  // no-accum, no-preload
210  };
211  bool store_stream_bookmark();
212  bool return_to_bookmark();
214 
215  // wallclock time at the (beginning of the) last call
216  // to mainloop that played back an event
217  timeval d_last_time; // XXX remove
218 
220  // accumulates the amount of time that we will advance
221  // filetime by when we next play back messages.
222  timeval d_filetime_accum_since_last_playback;
223 
224  // wallclock time when d_filetime_accum_since_last_playback
225  // was last updated
226  timeval d_time_of_last_accum;
227 
228  // scale factor between stream time and wallclock time
229  vrpn_float32 d_replay_rate;
230 
231  public:
233 
234  // return accumulated time since last reset
235  const timeval &accumulated(void)
236  {
237  return d_filetime_accum_since_last_playback;
238  }
239 
240  // return last time accumulate_to was called
241  const timeval &time_of_last_accum(void) { return d_time_of_last_accum; }
242 
243  vrpn_float32 replay_rate(void) { return d_replay_rate; }
244 
245  // add (d_replay_rate * (now_time - d_time_of_last_accum))
246  // to d_filetime_accum_since_last_playback
247  // then set d_time_of_last_accum to now_time
248  void accumulate_to(const timeval &now_time);
249 
250  // if current rate is non-zero, then time is accumulated
251  // before d_replay_rate is set to new_rate
252  void set_replay_rate(vrpn_float32 new_rate);
253 
254  // set d_time_of_last_accum to now_time
255  // and set d_filetime_accum_since_last_playback to zero
256  void reset_at_time(const timeval &now_time);
257  };
259 
260  // }}}
261  // {{{ actual mechanics of the logfile
262 protected:
263  char *d_fileName;
264  FILE *d_file;
265 
266  void play_to_user_message();
267 
268  // helper function for mainloop()
269  int need_to_play(timeval filetime);
270 
271  // checks the cookie at
272  // the head of the log file;
273  // exit on error!
274  virtual int read_cookie(void);
275 
276  virtual int read_entry(void); // appends entry to d_logTail
277  // returns 0 on success, 1 on EOF, -1 on error
278 
279  // Steps the currentLogEntry pointer forward one.
280  // It handles both cases of preload and non-preload.
281  // returns 0 on success, 1 on EOF, -1 on error
282  virtual int advance_currentLogEntry(void);
283 
284  virtual int close_file(void);
285 
286  // }}}
287  // {{{ handlers for VRPN control messages that might come from
288  // a File Controller object that wants to control this
289  // File Connection.
290 protected:
291  static int VRPN_CALLBACK handle_set_replay_rate(void *, vrpn_HANDLERPARAM);
292  static int VRPN_CALLBACK handle_reset(void *, vrpn_HANDLERPARAM);
293  static int VRPN_CALLBACK handle_play_to_time(void *, vrpn_HANDLERPARAM);
294 
295  // }}}
296  // {{{ Maintains a doubly-linked list structure that keeps
297  // copies of the messages from the file in memory. If
298  // d_accumulate is false, then there is only ever one entry
299  // in memory (d_currentLogEntry == d_logHead == d_logTail).
300  // If d_preload is true, then all of the records from the file
301  // are read into the list in the constructor and we merely step
302  // through memory when playing the streamfile. If d_preload is
303  // false and d_accumulate is true, then we have all of the
304  // records up the d_currentLogEntry in memory (d_logTail points
305  // to d_currentLogEntry but not to the last entry in the file
306  // until we get to the end of the file).
307  // The d_currentLogEntry should always be non-NULL unless we are
308  // past the end of all messages... we will either have preloaded
309  // all of them or else the read routine will attempt to load the
310  // next message each time one is played. The constructor fills it
311  // in with the first message, which makes it non-NULL initially.
312  // HOWEVER, if there are no user messages and we're asked to skip
313  // to the first user message then it can be NULL right after the
314  // constructor is called.
315 protected:
316  vrpn_LOGLIST *d_logHead; // the first read-in record
317  vrpn_LOGLIST *d_logTail; // the last read-in record
318  vrpn_LOGLIST *d_currentLogEntry; // Message that we've just loaded, or are
319  // at right now
320  vrpn_LOGLIST *d_startEntry; // potentially after initial system messages
321  bool d_preload; // Should THIS File Connection pre-load?
322  bool d_accumulate; // Should THIS File Connection accumulate?
323  // }}}
324 };
325 
326 #endif // VRPN_FILE_CONNECTION_H
virtual int mainloop(const struct timeval *timeout=NULL)=0
Call each time through program main loop to handle receiving any incoming messages and sending any pa...
virtual vrpn_File_Connection * get_File_Connection(void)
vrpn_File_Connection implements this as "return this" so it can be used to detect a File_Connection a...
class VRPN_API vrpn_File_Connection
vrpn_float32 get_replay_rate()
virtual timeval get_time()
returns the current time in the connection (since the epoch – UTC time).
void set_replay_rate(vrpn_float32 rate)
virtual int send_pending_reports(void)=0
send pending report, clear the buffer. This function was protected, now is public, so we can use it to send out intermediate results without calling mainloop
void Jane_stop_this_crazy_thing(vrpn_uint32 stop_looking_after)
This function should be seldom used. It is here for the case of the vrpn_Imager, whose servers do not...
Generic connection class not specific to the transport mechanism.
#define VRPN_CALLBACK
virtual int time_since_connection_open(struct timeval *elapsed_time)
Returns the time since the connection opened. Some subclasses may redefine time.
FileTime_Accumulator d_filetime_accum
vrpn_FileBookmark d_bookmark
#define VRPN_API
VRPN_API bool vrpn_FILE_CONNECTIONS_SHOULD_ACCUMULATE
This structure is what is passed to a vrpn_Connection message callback.
void limit_messages_played_back(vrpn_uint32 max_playback)
VRPN_API bool vrpn_FILE_CONNECTIONS_SHOULD_SKIP_TO_USER_MESSAGES
VRPN_API bool vrpn_FILE_CONNECTIONS_SHOULD_PRELOAD
vrpn_LOGLIST * d_currentLogEntry
Placed here so vrpn_FileConnection can use it too.