RflySimSDK v3.05
RflySimSDK说明文档
载入中...
搜索中...
未找到
vrpn_BaseClass.h
浏览该文件的文档.
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-----------------------------------------------------------------------------
28Answer 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
32vrpn_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
62Serial_Analog) would have to explicitly name the constructor for BaseClassUnique
63in the code and specify parameters for connection and service-name, even though
64only one such call to the BaseClassUnique's constructor would ever actually
65occur at runtime (that of Tng3 since it's located at the lowest level of the
66family tree; the rest of the calls would be ignored). This would mean inserting
67"vrpn_BaseClassUnique(name,connection)" into the initializer section of every
68constructor 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
94const int vrpn_MAX_BCADRS = 100;
96
100typedef enum {
101 vrpn_TEXT_NORMAL = 0,
102 vrpn_TEXT_WARNING = 1,
103 vrpn_TEXT_ERROR = 2
105const unsigned vrpn_MAX_TEXT_LEN = 1024;
106
107class VRPN_API vrpn_BaseClass;
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
176// SWIG does not like this declaration.
177#ifndef SWIG
178extern VRPN_API vrpn_TextPrinter &vrpn_System_TextPrinter;
179#endif
180
186class VRPN_API vrpn_BaseClassUnique {
187 friend class VRPN_API vrpn_TextPrinter;
188
189public:
191 virtual ~vrpn_BaseClassUnique();
192
194 vrpn_Connection *connectionPtr() { return d_connection; };
195
196 bool shutup; // if True, don't print the "No response from server" messages.
197
198 friend class SendTextMessageBoundCall;
200 private:
202 vrpn_TEXT_SEVERITY _severity;
203
204 public:
207 : _p(device)
208 , _severity(type)
209 {
210 }
211
212 int operator()(const char *msg) const
213 {
214 struct timeval timestamp;
215 vrpn_gettimeofday(&timestamp, NULL);
216 return _p->send_text_message(msg, timestamp, _severity);
217 }
218 };
219
220protected:
224
225 vrpn_int32 d_sender_id;
226 vrpn_int32 d_text_message_id;
227 vrpn_int32 d_ping_message_id;
228 vrpn_int32 d_pong_message_id;
229
232 // This is a wrapper for the vrpn_Connection call that registers
233 // message handlers. It should be used rather than the connection's
234 // function because this one will remember to unregister all of its handlers
235 // at object deletion time.
236 int register_autodeleted_handler(vrpn_int32 type,
237 vrpn_MESSAGEHANDLER handler,
238 void *userdata,
239 vrpn_int32 sender = vrpn_ANY_SENDER);
240
243 static int encode_text_message_to_buffer(char *buf,
244 vrpn_TEXT_SEVERITY severity,
245 vrpn_uint32 level,
246 const char *msg);
247
250 vrpn_TEXT_SEVERITY *severity,
251 vrpn_uint32 *level,
252 const char *buf);
253
255 int send_text_message(const char *msg, struct timeval timestamp,
256 vrpn_TEXT_SEVERITY type = vrpn_TEXT_NORMAL,
257 vrpn_uint32 level = 0);
258
264 send_text_message(vrpn_TEXT_SEVERITY type = vrpn_TEXT_NORMAL)
265 {
266 return SendTextMessageBoundCall(this, type);
267 }
268
272 void server_mainloop(void);
273
277 void client_mainloop(void);
278
279private:
280 struct {
281 vrpn_MESSAGEHANDLER handler;
282 vrpn_int32 sender;
283 vrpn_int32 type;
284 void *userdata;
285 } d_handler_autodeletion_record[vrpn_MAX_BCADRS];
286 int d_num_autodeletions;
287
288 int d_first_mainloop;
290 struct timeval d_time_first_ping;
292 struct timeval
293 d_time_last_warned;
294 int d_unanswered_ping;
295 int d_flatline;
296
299 static int VRPN_CALLBACK handle_ping(void *userdata, vrpn_HANDLERPARAM p);
300 static int VRPN_CALLBACK handle_pong(void *userdata, vrpn_HANDLERPARAM p);
301 static int VRPN_CALLBACK
302 handle_connection_dropped(void *userdata, vrpn_HANDLERPARAM p);
303 void initiate_ping_cycle(void);
304};
305
306//---------------------------------------------------------------
309
310class VRPN_API vrpn_BaseClass : virtual public vrpn_BaseClassUnique {
311
312public:
315 vrpn_BaseClass(const char *name, vrpn_Connection *c = NULL);
316
317 virtual ~vrpn_BaseClass();
318
325 virtual void mainloop() = 0;
326
327protected:
330 virtual int init(void);
331
334 virtual int register_senders(void);
335
338 virtual int register_types(void) = 0;
339};
340
341//---------------------------------------------------------------
342// Within VRPN (and other libraries), it is wise to avoid using the
343// Standard Template Library. This is very annoying, but required
344// by the fact that some systems have incompatible versions of STL.
345// This caused problems with any program that uses the GHOST library
346// (which had its own STL on Windows), and I've heard tell of problems
347// with other systems as well. On the other hand, nothing says that
348// we can't have our OWN template types and use them. This next type
349// is used to handle callback lists within objects. It is templated
350// over the struct that is passed to the user callback.
351// See vrpn_Button.h's usage for an example.
352
353// Disables a warning that the class requires DLL linkage to be
354// used by clients of classes that include one: The classes themselves
355// have DLL linkage, the code below asks for (but apparently does not
356// get) DLL linkage, and the DLL-linked test programs work when things
357// are as they are. Do not use this class outside of a derived class.
358#ifdef _MSC_VER
359#pragma warning(disable : 4251)
360#endif
361template <class CALLBACK_STRUCT> class VRPN_API vrpn_Callback_List {
362public:
363 typedef void(VRPN_CALLBACK *HANDLER_TYPE)(void *userdata,
364 const CALLBACK_STRUCT info);
365
367 int register_handler(void *userdata, HANDLER_TYPE handler)
368 {
369 CHANGELIST_ENTRY *new_entry;
370
371 // Ensure that the handler is non-NULL
372 if (handler == NULL) {
373 fprintf(stderr,
374 "vrpn_Callback_List::register_handler(): NULL handler\n");
375 return -1;
376 }
377
378 // Allocate and initialize the new entry
379 try {
380 new_entry = new CHANGELIST_ENTRY;
381 } catch (...) {
382 fprintf(stderr,
383 "vrpn_Callback_List::register_handler(): Out of memory\n");
384 return -1;
385 }
386 new_entry->handler = handler;
387 new_entry->userdata = userdata;
388
389 // Add this handler to the chain at the beginning (don't check to see
390 // if it is already there, since duplication is okay).
391 new_entry->next = d_change_list;
392 d_change_list = new_entry;
393
394 return 0;
395 };
396
398 int unregister_handler(void *userdata, HANDLER_TYPE handler)
399 {
400 // The pointer at *snitch points to victim
401 CHANGELIST_ENTRY *victim, **snitch;
402
403 // Find a handler with this registry in the list (any one will do,
404 // since all duplicates are the same).
405 snitch = &d_change_list;
406 victim = *snitch;
407 while ((victim != NULL) && ((victim->handler != handler) ||
408 (victim->userdata != userdata))) {
409 snitch = &((*snitch)->next);
410 victim = victim->next;
411 }
412
413 // Make sure we found one
414 if (victim == NULL) {
415 fprintf(
416 stderr,
417 "vrpn_Callback_List::unregister_handler: No such handler\n");
418 return -1;
419 }
420
421 // Remove the entry from the list
422 *snitch = victim->next;
423 try {
424 delete victim;
425 } catch (...) {
426 fprintf(stderr, "vrpn_Callback_List::unregister_handler: delete failed\n");
427 return -1;
428 }
429
430 return 0;
431 };
432
434 void call_handlers(const CALLBACK_STRUCT &info)
435 {
436 CHANGELIST_ENTRY *handler = d_change_list;
437 while (handler != NULL) {
438 handler->handler(handler->userdata, info);
439 handler = handler->next;
440 }
441 };
442
445 : d_change_list(NULL){};
446
449 : d_change_list(NULL)
450 {
451 // Copy all elements from the other list. XXX Side effect, this inverts
452 // the order
453 CHANGELIST_ENTRY *current, *next;
454 current = from.d_change_list;
455 while (current != NULL) {
456 register_handler(current->userdata, current->handler);
457 current = current->next;
458 }
459 }
460
461 void operator=(const vrpn_Callback_List& from)
462 {
463 // Delete any existing elements in the list.
464 CHANGELIST_ENTRY* current, * next;
465 current = d_change_list;
466 while (current != NULL) {
467 next = current->next;
468 try {
469 delete current;
470 }
471 catch (...) {
472 fprintf(stderr,
473 "vrpn_Callback_List::operator =: Deletion failure\n");
474 return;
475 }
476 current = next;
477 }
478
479 // Copy all elements from the other list. XXX Side effect, this inverts
480 // the order
481 current = from.d_change_list;
482 while (current != NULL) {
483 register_handler(current->userdata, current->handler);
484 current = current->next;
485 }
486 }
487
490 {
491 while (d_change_list != NULL) {
492 CHANGELIST_ENTRY *next = d_change_list->next;
493 try {
494 delete d_change_list;
495 } catch (...) {
496 fprintf(stderr, "vrpn_Callback_List::~vrpn_Callback_List: delete failed\n");
497 return;
498 }
499 d_change_list = next;
500 }
501 };
502
503protected:
504 typedef struct vrpn_CBS {
505 void *userdata;
506 HANDLER_TYPE handler;
507 struct vrpn_CBS *next;
509 CHANGELIST_ENTRY *d_change_list;
510};
511
512// End of defined VRPN_BASECLASS for vrpn_BaseClass.h
513#endif
定义 vrpn_BaseClass.h:186
vrpn_int32 d_pong_message_id
Server telling that it is there
定义 vrpn_BaseClass.h:228
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
void server_mainloop(void)
vrpn_int32 d_ping_message_id
Ask the server if they are there
定义 vrpn_BaseClass.h:227
vrpn_Connection * d_connection
Connection that this object talks to
定义 vrpn_BaseClass.h:221
SendTextMessageBoundCall send_text_message(vrpn_TEXT_SEVERITY type=vrpn_TEXT_NORMAL)
定义 vrpn_BaseClass.h:264
static int encode_text_message_to_buffer(char *buf, vrpn_TEXT_SEVERITY severity, vrpn_uint32 level, const char *msg)
int register_autodeleted_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
char * d_servicename
定义 vrpn_BaseClass.h:222
vrpn_int32 d_text_message_id
ID for text messages
定义 vrpn_BaseClass.h:226
vrpn_int32 d_sender_id
part
定义 vrpn_BaseClass.h:225
static int decode_text_message_from_buffer(char *msg, vrpn_TEXT_SEVERITY *severity, vrpn_uint32 *level, const char *buf)
Decodes the body of the text message from a buffer from the connection
vrpn_Connection * connectionPtr()
Returns a pointer to the connection this object is using
定义 vrpn_BaseClass.h:194
void client_mainloop(void)
定义 vrpn_BaseClass.h:310
virtual int register_types(void)=0
virtual int init(void)
virtual int register_senders(void)
virtual void mainloop()=0
vrpn_BaseClass(const char *name, vrpn_Connection *c=NULL)
定义 vrpn_BaseClass.h:361
vrpn_Callback_List(const vrpn_Callback_List &from)
This class requires deep copies.
定义 vrpn_BaseClass.h:448
int register_handler(void *userdata, HANDLER_TYPE handler)
Call this to add a handler to the list.
定义 vrpn_BaseClass.h:367
void call_handlers(const CALLBACK_STRUCT &info)
This will pass the referenced parameter as a const to all the callbacks.
定义 vrpn_BaseClass.h:434
vrpn_Callback_List()
The list starts out empty
定义 vrpn_BaseClass.h:444
~vrpn_Callback_List()
Clear the list upon destruction if it is not empty already
定义 vrpn_BaseClass.h:489
int unregister_handler(void *userdata, HANDLER_TYPE handler)
Call this to remove a handler from the list (if it exists)
定义 vrpn_BaseClass.h:398
Generic connection class not specific to the transport mechanism.
定义 vrpn_Connection.h:562
定义 vrpn_Thread.h:63
Structure to hold the objects that are being watched.
定义 vrpn_BaseClass.h:156
vrpn_BaseClass * obj
Object being watched
定义 vrpn_BaseClass.h:158
vrpn_TextPrinter_Watch_Entry * next
Pointer to the next one in the list
定义 vrpn_BaseClass.h:161
vrpn_TextPrinter * me
Pointer to this, because used in a static function
定义 vrpn_BaseClass.h:159
定义 vrpn_BaseClass.h:124
void set_min_level_to_print(vrpn_TEXT_SEVERITY severity, vrpn_uint32 level=0)
static int VRPN_CALLBACK text_message_handler(void *userdata, vrpn_HANDLERPARAM p)
vrpn_TextPrinter_Watch_Entry * d_first_watched_object
Head of list of objects being watched
定义 vrpn_BaseClass.h:164
int add_object(vrpn_BaseClass *o)
void set_ostream_to_use(FILE *o)
vrpn_Semaphore d_semaphore
Mutex to ensure thread safety;
定义 vrpn_BaseClass.h:153
FILE * d_ostream
Output stream to use
定义 vrpn_BaseClass.h:167
void remove_object(vrpn_BaseClass *o)
vrpn_uint32 d_level_to_print
Minimum level to print
定义 vrpn_BaseClass.h:169
vrpn_TEXT_SEVERITY d_severity_to_print
Minimum severity to print
定义 vrpn_BaseClass.h:168
定义 vrpn_BaseClass.h:504
This structure is what is passed to a vrpn_Connection message callback.
定义 vrpn_Connection.h:41
vrpn_TEXT_SEVERITY
定义 vrpn_BaseClass.h:100
const int vrpn_MAX_BCADRS
Internal value for number of BaseClass addresses
定义 vrpn_BaseClass.h:94