vrpn  07.33
Virtual Reality Peripheral Network
vrpn_BaseClass.h
Go to the documentation of this file.
1 
16 #ifndef VRPN_BASECLASS
17 #define VRPN_BASECLASS
18 
19 #include <stdio.h> // for NULL, fprintf, stderr, FILE
20 
21 #include "vrpn_Configure.h" // for VRPN_API, VRPN_CALLBACK
22 #include "vrpn_Connection.h"
23 #include "vrpn_Shared.h" // for timeval, vrpn_gettimeofday
24 #include "vrpn_Types.h" // for vrpn_int32, vrpn_uint32
25 
26 /*
27 -----------------------------------------------------------------------------
28 Answer to the question:
29  "Why is there both a UNIQUE and NON-UNIQUE base class?",
30  or
31  "Why can't everything from vrpn_BaseClass be moved into
32 vrpn_BaseClassUnique?"
33 
34  The first reason is that removing vrpn_BaseClass would require the
35  vrpn_BaseClassUnique constructor to take a name and connection object as
36  parameters, which would cause some problems due to the way virtual base
37  classes are implemented in C++.
38 
39  Any class that inherits from a virtual base (either directly or several
40  generations removed) must provide an explicit call to the constructor
41  of the virtual base. This is done because the virtual base constructor
42  is invoked from the very first class in the constructor chain.
43 
44  Take for example vrpn_Tng3, which inherits vrpn_Button and vrpn_Serial_Analog
45  (and thus vrpn_Analog). Creating a new instance of a vrpn_Tng3 object will
46  call the constructors in this order:
47  Tng3
48  BaseClassUnique (because it is a virtual base)
49  Button
50  BaseClass (coming from Button)
51  Serial_Analog
52  Analog
53  BaseClass (coming from Analog)
54 
55  Right now, BaseClassUnique's constructor has no parameters. So the
56  Tng3 constructor does not have to explicitly invoke BaseClassUnique, although
57  implicitly it will call BaseClassUnique's 0-parameter constructor before
58  doing anything else. But if BaseClass is eliminated, then BaseClassUnique's
59  constructor must do the work of creating the connection and copying the
60  service name. So BaseClassUnique's constructor must now take a couple
61  parameters, which means that every class (including Tng3, Button, Analog, and
62 Serial_Analog) would have to explicitly name the constructor for BaseClassUnique
63 in the code and specify parameters for connection and service-name, even though
64 only one such call to the BaseClassUnique's constructor would ever actually
65 occur at runtime (that of Tng3 since it's located at the lowest level of the
66 family tree; the rest of the calls would be ignored). This would mean inserting
67 "vrpn_BaseClassUnique(name,connection)" into the initializer section of every
68 constructor in *every* class under the BaseClassUnique subtree.
69 
70  The second reason we have both a unique and non-unique base class is that
71  the "register_types" virtual function must be called several times for
72  multiply-inherited devices, with a different virtual target in each case.
73  Presently, register_types() is called from vrpn_BaseClass::init().
74  init() may be called multiple times using a different vftable entry for
75  register_types() each time (e.g. for the Tng3 it will refer once to
76  vrpn_Analog::register_types() and once to vrpn_Button::register_types()).
77  Both init() and the pure-virtual declaration of register_types() are found
78  in BaseClass. Moving init() up into BaseClassUnique instead of BaseClass
79  means that register_types() would have to move up as well. And if
80  register_types() is declared in the virtual base class, BaseClassUnique,
81  it can only have one virtual target.
82 
83  So it might appear that vrpn_BaseClass has no data members and would
84  therefore be easy to eliminate. However it actually does have a data
85  member: the vftable entry for "register_types". And this data member
86  *must* be duplicated in the case of multiply-inherited device because a
87  single object will need several distinct virtual targets for
88  "register_types".
89 
90  [Jeff Feasel 19 May 2005]
91 -----------------------------------------------------------------------------
92 */
93 
94 const int vrpn_MAX_BCADRS = 100;
96 
100 typedef enum {
103  vrpn_TEXT_ERROR = 2
105 const unsigned vrpn_MAX_TEXT_LEN = 1024;
106 
108 
111 // It is a system class, with one instance of it in existence. Each object in
112 // the system registers with this class when it is constructed. By default,
113 // this class prints all Warning and Error messages to stdout, prefaced by
114 // "vrpn Warning(0) from MUMBLE: ", where the 0 indicates the level of the
115 // message and Warning the severity, and MUMBLE the name of the object that sent
116 // the message. The user could create their own TextPrinter, and attach whatever
117 // objects they want to it.
118 // NOTE: Because there is a vrpn_System_TextPrinter that all vrpn_BaseClass
119 // objects talk to, and because those objects may be in multiple threads, the
120 // vrpn_TextPrinter class has to be thread-safe. This requires all user-
121 // callable methods to be thread-safe because the destructor may be called
122 // during a method call.
123 
125 public:
127  ~vrpn_TextPrinter();
128 
135  int add_object(vrpn_BaseClass *o);
136 
140  void remove_object(vrpn_BaseClass *o);
141 
144  void set_min_level_to_print(vrpn_TEXT_SEVERITY severity,
145  vrpn_uint32 level = 0);
146 
149  void set_ostream_to_use(FILE *o);
150 
151 protected:
154 
157  public:
163  };
166 
167  FILE *d_ostream;
169  vrpn_uint32 d_level_to_print;
170 
173  static int VRPN_CALLBACK
174  text_message_handler(void *userdata, vrpn_HANDLERPARAM p);
175 };
177 
185 
186 public:
188  virtual ~vrpn_BaseClassUnique();
189 
191  vrpn_Connection *connectionPtr() { return d_connection; };
192 
193  bool shutup; // if True, don't print the "No response from server" messages.
194 
197  private:
199  vrpn_TEXT_SEVERITY _severity;
200 
201  public:
203  vrpn_TEXT_SEVERITY type)
204  : _p(device)
205  , _severity(type)
206  {
207  }
208 
210  : _p(other._p)
211  , _severity(other._severity)
212  {
213  }
214 
215  int operator()(const char *msg) const
216  {
217  struct timeval timestamp;
218  vrpn_gettimeofday(&timestamp, NULL);
219  return _p->send_text_message(msg, timestamp, _severity);
220  }
221  };
222 
223 protected:
226 
228  vrpn_int32 d_sender_id;
229  vrpn_int32 d_text_message_id;
230  vrpn_int32 d_ping_message_id;
231  vrpn_int32 d_pong_message_id;
232 
235  // This is a wrapper for the vrpn_Connection call that registers
236  // message handlers. It should be used rather than the connection's
237  // function because this one will remember to unregister all of its handlers
238  // at object deletion time.
239  int register_autodeleted_handler(vrpn_int32 type,
240  vrpn_MESSAGEHANDLER handler,
241  void *userdata,
242  vrpn_int32 sender = vrpn_ANY_SENDER);
243 
246  static int encode_text_message_to_buffer(char *buf,
247  vrpn_TEXT_SEVERITY severity,
248  vrpn_uint32 level,
249  const char *msg);
250 
252  static int decode_text_message_from_buffer(char *msg,
253  vrpn_TEXT_SEVERITY *severity,
254  vrpn_uint32 *level,
255  const char *buf);
256 
258  int send_text_message(const char *msg, struct timeval timestamp,
260  vrpn_uint32 level = 0);
261 
268  {
269  return SendTextMessageBoundCall(this, type);
270  }
271 
275  void server_mainloop(void);
276 
280  void client_mainloop(void);
281 
282 private:
283  struct {
285  vrpn_int32 sender;
286  vrpn_int32 type;
287  void *userdata;
288  } d_handler_autodeletion_record[vrpn_MAX_BCADRS];
289  int d_num_autodeletions;
290 
291  int d_first_mainloop;
292  struct timeval d_time_first_ping;
294  struct timeval
296  d_time_last_warned;
297  int d_unanswered_ping;
298  int d_flatline;
299 
302  static int VRPN_CALLBACK handle_ping(void *userdata, vrpn_HANDLERPARAM p);
303  static int VRPN_CALLBACK handle_pong(void *userdata, vrpn_HANDLERPARAM p);
304  static int VRPN_CALLBACK
305  handle_connection_dropped(void *userdata, vrpn_HANDLERPARAM p);
306  void initiate_ping_cycle(void);
307 };
308 
309 //---------------------------------------------------------------
312 
314 
315 public:
318  vrpn_BaseClass(const char *name, vrpn_Connection *c = NULL);
319 
320  virtual ~vrpn_BaseClass();
321 
328  virtual void mainloop() = 0;
329 
330 protected:
333  virtual int init(void);
334 
337  virtual int register_senders(void);
338 
341  virtual int register_types(void) = 0;
342 };
343 
344 //---------------------------------------------------------------
345 // Within VRPN (and other libraries), it is wise to avoid using the
346 // Standard Template Library. This is very annoying, but required
347 // by the fact that some systems have incompatible versions of STL.
348 // This caused problems with any program that uses the GHOST library
349 // (which had its own STL on Windows), and I've heard tell of problems
350 // with other systems as well. On the other hand, nothing says that
351 // we can't have our OWN template types and use them. This next type
352 // is used to handle callback lists within objects. It is templated
353 // over the struct that is passed to the user callback.
354 // See vrpn_Button.h's usage for an example.
355 
356 // Disables a warning that the class requires DLL linkage to be
357 // used by clients of classes that include one: The classes themselves
358 // have DLL linkage, the code below asks for (but apparently does not
359 // get) DLL linkage, and the DLL-linked test programs work when things
360 // are as they are. Do not use this class outside of a derived class.
361 #ifdef _MSC_VER
362 #pragma warning(disable : 4251)
363 #endif
364 template <class CALLBACK_STRUCT> class VRPN_API vrpn_Callback_List {
365 public:
366  typedef void(VRPN_CALLBACK *HANDLER_TYPE)(void *userdata,
367  const CALLBACK_STRUCT info);
368 
370  void operator=(const vrpn_Callback_List &from)
371  {
372  // Delete any existing elements in the list.
373  CHANGELIST_ENTRY *current, *next;
374  current = d_change_list;
375  while (current != NULL) {
376  next = current->next;
377  delete current;
378  current = next;
379  }
380 
381  // Copy all elements from the other list. XXX Side effect, this inverts
382  // the order
383  current = from.d_change_list;
384  while (current != NULL) {
385  register_handler(current->userdata, current->handler);
386  current = current->next;
387  }
388  }
389 
391  int register_handler(void *userdata, HANDLER_TYPE handler)
392  {
393  CHANGELIST_ENTRY *new_entry;
394 
395  // Ensure that the handler is non-NULL
396  if (handler == NULL) {
397  fprintf(stderr,
398  "vrpn_Callback_List::register_handler(): NULL handler\n");
399  return -1;
400  }
401 
402  // Allocate and initialize the new entry
403  if ((new_entry = new CHANGELIST_ENTRY) == NULL) {
404  fprintf(stderr,
405  "vrpn_Callback_List::register_handler(): Out of memory\n");
406  return -1;
407  }
408  new_entry->handler = handler;
409  new_entry->userdata = userdata;
410 
411  // Add this handler to the chain at the beginning (don't check to see
412  // if it is already there, since duplication is okay).
413  new_entry->next = d_change_list;
414  d_change_list = new_entry;
415 
416  return 0;
417  };
418 
420  int unregister_handler(void *userdata, HANDLER_TYPE handler)
421  {
422  // The pointer at *snitch points to victim
423  CHANGELIST_ENTRY *victim, **snitch;
424 
425  // Find a handler with this registry in the list (any one will do,
426  // since all duplicates are the same).
427  snitch = &d_change_list;
428  victim = *snitch;
429  while ((victim != NULL) && ((victim->handler != handler) ||
430  (victim->userdata != userdata))) {
431  snitch = &((*snitch)->next);
432  victim = victim->next;
433  }
434 
435  // Make sure we found one
436  if (victim == NULL) {
437  fprintf(
438  stderr,
439  "vrpn_Callback_List::unregister_handler: No such handler\n");
440  return -1;
441  }
442 
443  // Remove the entry from the list
444  *snitch = victim->next;
445  delete victim;
446 
447  return 0;
448  };
449 
451  void call_handlers(const CALLBACK_STRUCT &info)
452  {
453  CHANGELIST_ENTRY *handler = d_change_list;
454  while (handler != NULL) {
455  handler->handler(handler->userdata, info);
456  handler = handler->next;
457  }
458  };
459 
462  : d_change_list(NULL){};
463 
466  {
467  while (d_change_list != NULL) {
468  CHANGELIST_ENTRY *next = d_change_list->next;
469  delete d_change_list;
470  d_change_list = next;
471  }
472  };
473 
474 protected:
475  typedef struct vrpn_CBS {
476  void *userdata;
477  HANDLER_TYPE handler;
478  struct vrpn_CBS *next;
481 };
482 
483 // End of defined VRPN_BASECLASS for vrpn_BaseClass.h
484 #endif
vrpn_BaseClassUnique::d_ping_message_id
vrpn_int32 d_ping_message_id
Ask the server if they are there.
Definition: vrpn_BaseClass.h:230
vrpn_MAX_TEXT_LEN
const unsigned vrpn_MAX_TEXT_LEN
Definition: vrpn_BaseClass.h:105
vrpn_System_TextPrinter
VRPN_API vrpn_TextPrinter vrpn_System_TextPrinter
Definition of the system TextPrinter object that prints messages for all created objects.
Definition: vrpn_BaseClass.C:15
vrpn_Types.h
vrpn_Semaphore
Definition: vrpn_Shared.h:487
vrpn_BaseClassUnique::userdata
void * userdata
Definition: vrpn_BaseClass.h:287
vrpn_Callback_List
Definition: vrpn_BaseClass.h:364
vrpn_TextPrinter::d_level_to_print
vrpn_uint32 d_level_to_print
Minimum level to print.
Definition: vrpn_BaseClass.h:169
CHANGELIST_ENTRY::next
struct vrpn_CBS * next
Definition: vrpn_BaseClass.h:478
vrpn_BaseClassUnique::d_text_message_id
vrpn_int32 d_text_message_id
ID for text messages.
Definition: vrpn_BaseClass.h:229
vrpn_Callback_List::register_handler
int register_handler(void *userdata, HANDLER_TYPE handler)
Call this to add a handler to the list.
Definition: vrpn_BaseClass.h:391
vrpn_Callback_List::vrpn_Callback_List
vrpn_Callback_List()
The list starts out empty.
Definition: vrpn_BaseClass.h:461
CHANGELIST_ENTRY::userdata
void * userdata
Definition: vrpn_BaseClass.h:476
vrpn_TextPrinter::d_severity_to_print
vrpn_TEXT_SEVERITY d_severity_to_print
Minimum severity to print.
Definition: vrpn_BaseClass.h:168
vrpn_BaseClassUnique::SendTextMessageBoundCall
Definition: vrpn_BaseClass.h:196
vrpn_BaseClassUnique::d_connection
vrpn_Connection * d_connection
Connection that this object talks to.
Definition: vrpn_BaseClass.h:224
vrpn_TEXT_ERROR
@ vrpn_TEXT_ERROR
Definition: vrpn_BaseClass.h:103
vrpn_BaseClassUnique::send_text_message
SendTextMessageBoundCall send_text_message(vrpn_TEXT_SEVERITY type=vrpn_TEXT_NORMAL)
Returns an object you can stream into to send a text message from the device like send_text_message(v...
Definition: vrpn_BaseClass.h:267
vrpn_BaseClass
class VRPN_API vrpn_BaseClass
Definition: vrpn_BaseClass.h:107
vrpn_HANDLERPARAM
This structure is what is passed to a vrpn_Connection message callback.
Definition: vrpn_Connection.h:44
vrpn_Shared.h
vrpn_BaseClassUnique
INTERNAL class to hold members that there should only be one copy of even when a class inherits from ...
Definition: vrpn_BaseClass.h:183
vrpn_TEXT_WARNING
@ vrpn_TEXT_WARNING
Definition: vrpn_BaseClass.h:102
vrpn_BaseClassUnique::d_sender_id
vrpn_int32 d_sender_id
Sender ID registered with the connection.
Definition: vrpn_BaseClass.h:228
vrpn_TextPrinter::d_semaphore
vrpn_Semaphore d_semaphore
Mutex to ensure thread safety;.
Definition: vrpn_BaseClass.h:153
vrpn_BaseClass::mainloop
virtual void mainloop()=0
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
vrpn_TextPrinter::vrpn_TextPrinter_Watch_Entry::me
vrpn_TextPrinter * me
Pointer to this, because used in a static function.
Definition: vrpn_BaseClass.h:159
vrpn_BaseClassUnique::shutup
bool shutup
Definition: vrpn_BaseClass.h:191
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_BaseClassUnique::connectionPtr
vrpn_Connection * connectionPtr()
Returns a pointer to the connection this object is using.
Definition: vrpn_BaseClass.h:191
vrpn_Connection.h
CHANGELIST_ENTRY::handler
HANDLER_TYPE handler
Definition: vrpn_BaseClass.h:477
vrpn_TextPrinter::vrpn_TextPrinter_Watch_Entry::obj
vrpn_BaseClass * obj
Object being watched.
Definition: vrpn_BaseClass.h:158
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
vrpn_Callback_List::operator=
void operator=(const vrpn_Callback_List &from)
This class requires deep copies.
Definition: vrpn_BaseClass.h:370
CHANGELIST_ENTRY
Definition: vrpn_BaseClass.h:475
vrpn_ANY_SENDER
const int vrpn_ANY_SENDER
vrpn_ANY_SENDER can be used to register callbacks on a given message type from any sender.
Definition: vrpn_Connection.h:77
vrpn_BaseClass::register_types
virtual int register_types(void)=0
Register the types of messages this device sends/receives. Return 0 on success, -1 on fail.
vrpn_TextPrinter::d_ostream
FILE * d_ostream
Output stream to use.
Definition: vrpn_BaseClass.h:167
vrpn_MESSAGEHANDLER
int(VRPN_CALLBACK * vrpn_MESSAGEHANDLER)(void *userdata, vrpn_HANDLERPARAM p)
Type of a message handler for vrpn_Connection messages.
Definition: vrpn_Connection.h:53
vrpn_BaseClassUnique::SendTextMessageBoundCall::SendTextMessageBoundCall
SendTextMessageBoundCall(vrpn_BaseClassUnique *device, vrpn_TEXT_SEVERITY type)
Definition: vrpn_BaseClass.h:202
VRPN_CALLBACK
#define VRPN_CALLBACK
Definition: vrpn_Configure.h:647
vrpn_TEXT_NORMAL
@ vrpn_TEXT_NORMAL
Definition: vrpn_BaseClass.h:101
vrpn_TextPrinter::vrpn_TextPrinter_Watch_Entry
Structure to hold the objects that are being watched.
Definition: vrpn_BaseClass.h:156
vrpn_BaseClassUnique::SendTextMessageBoundCall::operator()
int operator()(const char *msg) const
Definition: vrpn_BaseClass.h:215
vrpn_TEXT_SEVERITY
vrpn_TEXT_SEVERITY
Since the sending of text messages has been pulled into the base class (so that every object can send...
Definition: vrpn_BaseClass.h:100
vrpn_BaseClassUnique::SendTextMessageBoundCall::SendTextMessageBoundCall
SendTextMessageBoundCall(SendTextMessageBoundCall const &other)
Definition: vrpn_BaseClass.h:209
vrpn_BaseClassUnique::send_text_message
int send_text_message(const char *msg, struct timeval timestamp, vrpn_TEXT_SEVERITY type=vrpn_TEXT_NORMAL, vrpn_uint32 level=0)
Sends a NULL-terminated text message from the device d_sender_id.
Definition: vrpn_BaseClass.C:568
vrpn_BaseClassUnique::d_servicename
char * d_servicename
Name of this device, not including the connection part.
Definition: vrpn_BaseClass.h:225
vrpn_TextPrinter
Class that handles text/warning/error printing for all objects in the system.
Definition: vrpn_BaseClass.h:124
vrpn_Callback_List::call_handlers
void call_handlers(const CALLBACK_STRUCT &info)
This will pass the referenced parameter as a const to all the callbacks.
Definition: vrpn_BaseClass.h:451
vrpn_Configure.h
vrpn_Callback_List::~vrpn_Callback_List
~vrpn_Callback_List()
Clear the list upon destruction if it is not empty already.
Definition: vrpn_BaseClass.h:465
vrpn_BaseClassUnique::d_pong_message_id
vrpn_int32 d_pong_message_id
Server telling that it is there.
Definition: vrpn_BaseClass.h:231
vrpn_Callback_List::unregister_handler
int unregister_handler(void *userdata, HANDLER_TYPE handler)
Call this to remove a handler from the list (if it exists)
Definition: vrpn_BaseClass.h:420
vrpn_TextPrinter::vrpn_TextPrinter_Watch_Entry::next
vrpn_TextPrinter_Watch_Entry * next
Pointer to the next one in the list.
Definition: vrpn_BaseClass.h:161
vrpn_BaseClassUnique::type
vrpn_int32 type
Definition: vrpn_BaseClass.h:286
VRPN_API
#define VRPN_API
Definition: vrpn_Configure.h:646
vrpn_TextPrinter::d_first_watched_object
vrpn_TextPrinter_Watch_Entry * d_first_watched_object
Head of list of objects being watched.
Definition: vrpn_BaseClass.h:164
vrpn_BaseClass
Class from which all user-level (and other) classes that communicate with vrpn_Connections should der...
Definition: vrpn_BaseClass.h:313
vrpn_Callback_List::d_change_list
CHANGELIST_ENTRY * d_change_list
Definition: vrpn_BaseClass.h:480
vrpn_MAX_BCADRS
const int vrpn_MAX_BCADRS
Internal value for number of BaseClass addresses.
Definition: vrpn_BaseClass.h:94
vrpn_BaseClassUnique::handler
vrpn_MESSAGEHANDLER handler
Definition: vrpn_BaseClass.h:284
vrpn_BaseClassUnique::sender
vrpn_int32 sender
Definition: vrpn_BaseClass.h:285