vrpn  07.33
Virtual Reality Peripheral Network
vrpn_ImmersionBox.C
Go to the documentation of this file.
1 // vrpn_ImmersionBox.C
2 // This is a driver for an Immersion Corporation Immersion Box controller.
3 // This box is a serial-line device that allows the user to connect
4 // analog inputs, digital inputs, digital outputs, and digital
5 // encoders and read from them over RS-232.
6 //
7 // This code is based on the ImmersionBox code previously written as part
8 // of the vrpn library
9 
10 #include <math.h> // for floor
11 #include <stdio.h> // for fprintf, stderr, printf
12 #include <string.h> // for NULL, strcpy
13 
14 #include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR
15 #include "vrpn_ImmersionBox.h"
16 #include "vrpn_Serial.h"
17 #include "vrpn_Shared.h" // for timeval, vrpn_gettimeofday
18 
19 #undef VERBOSE
20 
21 // low-level stuff
22 static const unsigned char CMD_BASIC = static_cast<unsigned char>(0xC0); // mask for command
23 static const unsigned char CMD_HOMEREF = static_cast<unsigned char>(0xC1);
24 static const unsigned char CMD_HOMEPOS = static_cast<unsigned char>(0xC2);
25 static const unsigned char CMD_SETHOME = static_cast<unsigned char>(0xC3);
26 static const unsigned char CMD_BAUDSET = static_cast<unsigned char>(0xC4);
27 static const unsigned char CMD_ENDSESS = static_cast<unsigned char>(0xC5);
28 static const unsigned char CMD_GETMAXS = static_cast<unsigned char>(0xC6);
29 static const unsigned char CMD_SETPARM = static_cast<unsigned char>(0xC7);
30 static const unsigned char CMD_GETNAME = static_cast<unsigned char>(0xC8);
31 static const unsigned char CMD_GETPRID = static_cast<unsigned char>(0xC9);
32 static const unsigned char CMD_GETMODL = static_cast<unsigned char>(0xCA);
33 static const unsigned char CMD_GETSERN = static_cast<unsigned char>(0xCB);
34 static const unsigned char CMD_GETCOMM = static_cast<unsigned char>(0xCC);
35 static const unsigned char CMD_GETPERF = static_cast<unsigned char>(0xCD);
36 static const unsigned char CMD_GETVERS = static_cast<unsigned char>(0xCE);
37 static const unsigned char CMD_GETMOTN = static_cast<unsigned char>(0xCF);
38 static const unsigned char CMD_SETHREF = static_cast<unsigned char>(0xD0);
39 static const unsigned char CMD_FACREST = static_cast<unsigned char>(0xD1);
40 static const unsigned char CMD_INSMARK = static_cast<unsigned char>(0xD2);
41 
42 static const double PAUSE_RESET = .015;
43 static const double PAUSE_END = .015;
44 static const double PAUSE_RESTORE = 2.0;
45 static const double PAUSE_BYTE = .015;
46 
47 // Defines the modes in which the box can find itself.
48 #define STATUS_RESETTING (-1) // Resetting the box
49 #define STATUS_SYNCING (0) // Looking for the first character of report
50 #define STATUS_READING (1) // Looking for the rest of the report
51 
52 /* Strings for establishing connection */
53 char S_INITIALIZE[5] = "IMMC";
54 char S_START[6] = "BEGIN";
55 char S_END[4] = "END";
56 
57 #define MAX_TIME_INTERVAL (2000000) // max time between reports (usec)
58 
59 static void pause (double delay) {
60  if (delay < 0)
61  delay = 0;
62  unsigned long interval = (long) floor(1000000.0 * delay);
63 
64  struct timeval start, now;
65  vrpn_gettimeofday (&start, NULL);
66 
67  do {
68  vrpn_gettimeofday (&now, NULL);
69  } while (vrpn_TimevalDuration(now, start) < interval);
70 
71 }
72 
73 // This creates a vrpn_ImmersionBox and sets it to reset mode. It opens
74 // the serial device using the code in the vrpn_Serial_Analog constructor.
75 // The box will autodetect the baud rate when the "IMMC" command is sent
76 // to it.
77 
79  vrpn_Connection * c,
80  const char * port,
81  int baud,
82  const int numbuttons,
83  const int numchannels,
84  const int numencoders):
85  vrpn_Serial_Analog(name, c, port, baud),
86  vrpn_Button_Filter(name, c),
87  vrpn_Dial(name, c),
88  _numbuttons(numbuttons),
89  _numchannels(numchannels),
90  _numencoders(numencoders)
91 {
92 
93 
94  // Verify the validity of the parameters
95  if (_numbuttons > MAX_IBUTTONS) {
96  fprintf(stderr,"vrpn_ImmersionBox: Can only support %d buttons, not %d\n", MAX_IBUTTONS, _numbuttons);
98  }
100  fprintf(stderr,"vrpn_ImmersionBox: Can only support %d analog channels, not %d\n", MAX_ICHANNELS, _numchannels);
102  }
103  if (_numencoders > MAX_IENCODERS) {
104  fprintf(stderr,"vrpn_ImmersionBox: Can only support %d encoders, not %d\n", MAX_IENCODERS, _numencoders);
106  }
107 
108  // explicitly clear the identification variables
109  iname[0] = 0;
110  comment[0] = 0;
111  serial[0] = 0;
112  id[0] = 0;
113  model[0] = 0;
114  vers[0] = 0;
115  parmf[0] = 0;
116 
117  // Set the parameters in the parent classes
121 
122  // Set the status of the buttons, analogs and encoders to 0 to start
123  clear_values();
124 
125  // Set the mode to reset
127 }
128 
130 {
131  int i;
132 
133  for (i = 0; i < _numbuttons; i++) {
135  }
136  for (i = 0; i < _numchannels; i++) {
138  }
139  for (i = 0; i < _numencoders; i++) {
140  vrpn_Dial::dials[i] = 0.0;
141  }
142 }
143 
144 // This routine will reset the ImmersionBox, asking it to send the requested number
145 // of analogs, buttons and encoders.
146 // It verifies that it can communicate with the device and checks the version of
147 // the device.
148 
150 {
151 
152  //-----------------------------------------------------------------------
153  // Set the values back to zero for all buttons, analogs and encoders
154  clear_values();
155 
156  //-----------------------------------------------------------------------
157  // sending an end at this time will force the ibox into the reset mode, if it
158  // was not already. if the ibox is in the power up mode, nothing will happen because
159  // it 'should' be waiting to sync up the baudrate
160 
161  // try to synchronize for 2 seconds
162 
163  if (syncBaudrate (10.0)) {
164  printf("vrpn_ImmersionBox found\n");
165  } else {
166  return -1;
167  }
168 
169  if (0 == sendIboxCommand((char) CMD_GETNAME, (char *) &iname, .1)) {
170  fprintf(stderr,"problems with ibox command CMD_GETNAME\n");
171  return -1;
172  }
173  if (0 == sendIboxCommand((char) CMD_GETPRID, (char *) &id, .1)) {
174  fprintf(stderr,"problems with ibox command CMD_GETPRID\n");
175  return -1;
176  }
177  if (0 == sendIboxCommand((char) CMD_GETMODL, (char *) &model, .1)){
178  fprintf(stderr,"problems with ibox command CMD_GETMODL\n");
179  return -1;
180  }
181  if (0 == sendIboxCommand((char) CMD_GETSERN, (char *) &serial, .1)){
182  fprintf(stderr,"problems with ibox command CMD_GETSERN\n");
183  return -1;
184  }
185  if (0 == sendIboxCommand((char) CMD_GETCOMM, (char *) &comment, .1)){
186  fprintf(stderr,"problems with ibox command CMD_GETCOMM\n");
187  return -1;
188  }
189  if (0 == sendIboxCommand((char) CMD_GETPERF, (char *) &parmf, .1)){
190  fprintf(stderr,"problems with ibox command CMD_GETPERF\n");
191  return -1;
192  }
193  if (0 == sendIboxCommand((char) CMD_GETVERS, (char *) &vers, .1)){
194  fprintf(stderr,"problems with ibox command CMD_GETVERS\n");
195  return -1;
196  }
197 
198 #ifdef VERBOSE
199  printf("%s\n%s\n%s\n%s\n%s\n%s\n", iname, id, serial, comment, parmf, vers);
200 #endif
201 
202  //-----------------------------------------------------------------------
203  // Compute the proper string to initialize the device based on how many
204  // of each type of input/output that is selected.
205 
206  setupCommand (0, _numchannels, _numencoders);
207 
208  unsigned char command[26] = "";
209  command[0] = 0xcf;
210  command[1] = 0x0;
211  command[2] = (unsigned char) 10; // milliseconds between reports
212  command[3] = commandByte;
213 
214  for (int i = 4; i < 25;i++)
215  command[i] = 0x0;
216 
217  //-----------------------------------------------------------------------
218 
219  int result = vrpn_write_characters(serial_fd, (const unsigned char *) command, 25);
220 
221  // Ask the box to send a report, ensure echo received
222  if (result < 25) {
223  fprintf(stderr,"vrpnImmersionBox::reset: could not write command\n");
224  return -1;
225  }
226 
227  pause (.1);
228 
229  // look for command echo
230  result = vrpn_read_available_characters(serial_fd, (unsigned char *) command, 1);
231 
232  if (result <= 0 || command[0] != 0xcf) {
233  fprintf(stderr,"vrpnImmersionBox::reset: no command echo\n");
234  return -1;
235  }
236 
237  // flush the input buffer
239 
240  printf("ImmersionBox reset complete.\n");
241 
243  vrpn_gettimeofday(&timestamp, NULL); // Set watchdog now
244  return 0;
245 }
246 
247 // This function will read characters until it has a full report, then
248 // put that report into the time, analog, button and encoder fields and call
249 // the report methods on these. The time stored is that of
250 // the first character received as part of the report.
251 //
252 // Reports start with the header packetHeader followed by dataRecordLength bytes
253 //
254 // If we get a report that is not valid, we assume that we have lost a
255 // character or something and re-synchronize by flushing the buffer
256 //
257 // The routine that calls this one
258 // makes sure we get a full reading often enough (ie, it is responsible
259 // for doing the watchdog timing to make sure the box hasn't simply
260 // stopped sending characters).
261 // Returns 1 if got a full report, 0 otherwise.
262 
264 {
265  unsigned char responseString[MAX_IBOX_STRING];
266  int i;
267  unsigned int buttonBits = 0;
268 
269  struct timeval timeout;
270  timeout.tv_sec = 0;
271  timeout.tv_usec = 100000;
272 
274 
275  // process as long as we can get characters
277  // if not a record start, skip it
278  if (buffer[0] != dataPacketHeader) {
279  continue;
280  }
281  // we got a good one... we're reading now
283  break;
284  }
285 
286  // we broke out.. if we're not reading, then we have nothing to do
287  if (STATUS_READING != status) {
288  return 0;
289  }
290 
291 
292  // we're reading now, get the report
293 
294  // get the expected number of data record bytes
296  (unsigned char *) responseString,
297  dataRecordLength,
298  &timeout );
299 
300  if (result < dataRecordLength) {
302  return 0;
303  }
304 
305  // parse the report here
306  buttonBits = responseString[0];
307 
308  for (i = 0; i < _numbuttons; i++) {
310  vrpn_Button::buttons[i] = static_cast<unsigned char>(buttonBits & (1 << i));
311  }
312 
313 #if VERBOSE
314  if (vrpn_Button::buttons[3])
315  cerr << "left button pressed " << endl;
316 #endif
317 
318  // if we processed timer bits we would do so here
319 
320  // here is where we decode the analog stuff
321  for (i = 0; i < _numchannels; i++) {
323  }
324 
325  // here is where we convert the angle encoders
326  for (i = 0; i < _numencoders; i++) {
327  vrpn_Dial::dials[i] = 0.0;
328  }
329 
330  report_changes();
331  vrpn_gettimeofday(&timestamp, NULL); // Set watchdog now
332 
333  return 1;
334 }
335 
336 void vrpn_ImmersionBox::report_changes(vrpn_uint32 class_of_service)
337 {
341 
342  vrpn_Analog::report_changes(class_of_service);
345 }
346 
347 void vrpn_ImmersionBox::report(vrpn_uint32 class_of_service)
348 {
352 
353  vrpn_Analog::report(class_of_service);
356 }
357 
358 // This routine is called each time through the server's main loop. It will
359 // take a course of action depending on the current status of the cerealbox,
360 // either trying to reset it or trying to get a reading from it.
362 {
363  server_mainloop();
364 
365  switch(status) {
366  case STATUS_RESETTING:
367  reset();
368  break;
369 
370  case STATUS_SYNCING:
371  case STATUS_READING:
372  {
373  // It turns out to be important to get the report before checking
374  // to see if it has been too long since the last report. This is
375  // because there is the possibility that some other device running
376  // in the same server may have taken a long time on its last pass
377  // through mainloop(). Trackers that are resetting do this. When
378  // this happens, you can get an infinite loop -- where one tracker
379  // resets and causes the other to timeout, and then it returns the
380  // favor. By checking for the report here, we reset the timestamp
381  // if there is a report ready (ie, if THIS device is still operating).
382  while (get_report()) {}; // Get multiple reports if available
383  struct timeval current_time;
384  vrpn_gettimeofday(&current_time, NULL);
385  if ( vrpn_TimevalDuration(current_time,timestamp) > MAX_TIME_INTERVAL) {
386  fprintf(stderr,"Tracker failed to read... current_time=%ld:%ld, timestamp=%ld:%ld\n",
387  current_time.tv_sec, static_cast<long>(current_time.tv_usec),
388  timestamp.tv_sec, static_cast<long>(timestamp.tv_usec));
389  send_text_message("Too long since last report, resetting", current_time, vrpn_TEXT_ERROR);
391  }
392  }
393  break;
394 
395  default:
396  fprintf(stderr,"vrpn_ImmersionBox: Unknown mode (internal error)\n");
397  break;
398  }
399 }
400 
401 // utility routine (optionally) to send commands to the ibox,
402 // (optionally) to return results,
403 // (optionally) delaying between sending the command and receiving the results
404 
405 int vrpn_ImmersionBox::sendIboxCommand (char cmd, char * returnString, double delay)
406 {
407  struct timeval timeout;
408  timeout.tv_sec = 0;
409  timeout.tv_usec = 15000;
410  char command[2];
411  char responseString [MAX_IBOX_STRING+1];
412  int result;
413 
414  if (cmd) {
415  command[0] = cmd;
416  result = vrpn_write_characters(serial_fd, (const unsigned char *) command, 1);
417  if (delay > 0)
418  pause (delay);
419 
420  if (NULL == returnString)
421  // if we are not anticipating a return, go back now
422  return result;
423  }
424 
425  // read the response to the command
426  result = vrpn_read_available_characters(serial_fd, (unsigned char *) responseString, MAX_IBOX_STRING, &timeout );
427 
428  if (result <= 0)
429  return 0;
430 
431  // since we're looking for a response, we need to ensure the command was properly
432  // echoed back... To begin with, bit 7 must be set
433  if (!(responseString[0] & 0x80))
434  return 0;
435 
436  // the bits, excepting bit 7 must match
437  if ((responseString[0] & 0x7f) != (cmd & 0x7f))
438  return 0;
439 
440  // copy the remainder of the response into the response
441  strcpy (returnString, &responseString[1]);
442 
443  return 1;
444 }
445 
446 
447 // sync the baud rate on the ibox.
448 // seconds determines how long the process is permitted to continue
449 int vrpn_ImmersionBox::syncBaudrate (double seconds) {
450 
451  struct timeval miniDelay;
452  miniDelay.tv_sec = 0;
453  miniDelay.tv_usec = 50000;
454 
455  unsigned long maxDelay = 1000000L * (long) seconds;
456  struct timeval start_time;
457  vrpn_gettimeofday(&start_time, NULL);
458 
459  int loggedOn = 0;
460  unsigned char responseString[8];
461  unsigned char * matchString = (unsigned char *) S_INITIALIZE ; // IMMC
462  int index, numRead;
463 
464  if (serial_fd < 0)
465  return 0;
467  vrpn_write_characters(serial_fd, (const unsigned char *)"E", 1);
468  pause (0.01);
469 
470  while (!loggedOn) {
471  struct timeval current_time;
472  vrpn_gettimeofday(&current_time, NULL);
473  if (vrpn_TimevalDuration(current_time, start_time) > maxDelay ) {
474  // if we've timed out, go back unhappy
475  fprintf(stderr,"vrpn_ImmersionBox::syncBaudrate timeout expired: %lf secs \n", seconds);
476  break; // out of while loop
477  }
478 
479  // send "IMMC"
480  if (4 != vrpn_write_characters(serial_fd, matchString, 4)) {
481  fprintf(stderr,"vrpn_ImmersionBox::syncBaudrate could not write to serial port\n");
482  break; // out of while loop
483  }
484 
485  pause (0.015);
486 
487  // wait for 4 characters
488  numRead = vrpn_read_available_characters(serial_fd, responseString, 4, &miniDelay);
489 
490  if (numRead <= 0)
491  continue;
492 
493  // get 4 characters, hopefully "IMMC"
494  for (index = 0; index < 4; index++) {
495  // get a character, check for failure
496  if (responseString[index] != matchString[index])
497  break;
498  }
499 
500  // if we got all four, we're done
501  if (4 == index)
502  loggedOn = 1;
503  }
504 
505  if (!loggedOn)
506  return 0;
507 
508  // now begin the session && ensure that its an ibox we're talking to
509  matchString = (unsigned char *) "IBOX";
510  vrpn_write_characters(serial_fd, (const unsigned char *)"BEGIN", 5);
511  numRead = vrpn_read_available_characters(serial_fd, responseString, 4, &miniDelay);
512 
513  if (numRead <= 0)
514  return 0;
515 
516  // check 4 characters, hopefully "IBOX"
517  for (index = 0; index < 4; index++) {
518  // get a character, check for failure
519  if (responseString[index] != matchString[index])
520  return 0;
521  }
523  return 1;
524 }
PAUSE_END
#define PAUSE_END
Definition: vrpn_Tng3.C:25
vrpn_Serial_Analog
Definition: vrpn_Analog.h:63
vrpn_Dial::report
virtual void report(void)
Definition: vrpn_Dial.C:82
vrpn_ImmersionBox::_numchannels
int _numchannels
Definition: vrpn_ImmersionBox.h:36
vrpn_Button::report_changes
virtual void report_changes(void)
Definition: vrpn_Button.C:422
vrpn_Analog::status
int status
Definition: vrpn_Analog.h:43
vrpn_BaseClass.h
vrpn_TimevalDuration
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
Definition: vrpn_Shared.C:129
vrpn_Button_Filter::report_changes
virtual void report_changes(void)
Definition: vrpn_Button.C:382
vrpn_Analog::channel
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
S_INITIALIZE
char S_INITIALIZE[5]
Definition: vrpn_ImmersionBox.C:53
S_END
char S_END[4]
Definition: vrpn_ImmersionBox.C:55
vrpn_Serial_Analog::buffer
unsigned char buffer[1024]
Definition: vrpn_Analog.h:75
vrpn_Analog::report
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report whether something has changed or not (for servers) Optionally, tell what time to stamp ...
Definition: vrpn_Analog.C:94
S_START
char S_START[6]
Definition: vrpn_ImmersionBox.C:54
vrpn_Analog::timestamp
struct timeval timestamp
Definition: vrpn_Analog.h:41
PAUSE_RESTORE
#define PAUSE_RESTORE
Definition: vrpn_Tng3.C:26
vrpn_ImmersionBox.h
vrpn_ImmersionBox::_numbuttons
int _numbuttons
Definition: vrpn_ImmersionBox.h:35
vrpn_Serial.h
vrpn_Serial: Pulls all the serial port routines into one file to make porting to new operating system...
vrpn_Button::num_buttons
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
MAX_IENCODERS
#define MAX_IENCODERS
Definition: vrpn_ImmersionBox.h:59
PAUSE_RESET
#define PAUSE_RESET
Definition: vrpn_Tng3.C:24
vrpn_Button::buttons
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
MAX_IBUTTONS
#define MAX_IBUTTONS
Definition: vrpn_ImmersionBox.h:61
vrpn_TEXT_ERROR
Definition: vrpn_BaseClass.h:103
vrpn_flush_input_buffer
int vrpn_flush_input_buffer(int comm)
Throw out any characters within the input buffer.
Definition: vrpn_Serial.C:435
vrpn_Dial
Definition: vrpn_Dial.h:21
STATUS_SYNCING
#define STATUS_SYNCING
Definition: vrpn_ImmersionBox.C:49
vrpn_Shared.h
vrpn_ImmersionBox::_numencoders
int _numencoders
Definition: vrpn_ImmersionBox.h:37
vrpn_Button::timestamp
struct timeval timestamp
Definition: vrpn_Button.h:48
vrpn_Dial::dials
vrpn_float64 dials[vrpn_DIAL_MAX]
Definition: vrpn_Dial.h:26
vrpn_Dial::report_changes
virtual void report_changes(void)
Definition: vrpn_Dial.C:54
STATUS_READING
#define STATUS_READING
Definition: vrpn_ImmersionBox.C:50
PAUSE_BYTE
#define PAUSE_BYTE
Definition: vrpn_Tng3.C:27
vrpn_Serial_Analog::serial_fd
int serial_fd
Definition: vrpn_Analog.h:72
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_ImmersionBox::get_report
virtual int get_report(void)
Definition: vrpn_ImmersionBox.C:263
vrpn_Analog::num_channel
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
vrpn_ImmersionBox::vrpn_ImmersionBox
vrpn_ImmersionBox(const char *name, vrpn_Connection *c, const char *port, int baud, const int numbuttons, const int numchannels, const int numencoders)
Definition: vrpn_ImmersionBox.C:78
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
MAX_TIME_INTERVAL
#define MAX_TIME_INTERVAL
Definition: vrpn_ImmersionBox.C:57
vrpn_Button::lastbuttons
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
STATUS_RESETTING
#define STATUS_RESETTING
Definition: vrpn_ImmersionBox.C:48
vrpn_read_available_characters
int vrpn_read_available_characters(int comm, unsigned char *buffer, size_t bytes)
Definition: vrpn_Serial.C:512
vrpn_ImmersionBox::_status
int _status
Definition: vrpn_ImmersionBox.h:34
vrpn_Analog::last
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_ImmersionBox::timestamp
struct timeval timestamp
Definition: vrpn_ImmersionBox.h:43
MAX_IBOX_STRING
#define MAX_IBOX_STRING
Definition: vrpn_ImmersionBox.h:62
vrpn_ImmersionBox::clear_values
virtual void clear_values(void)
Definition: vrpn_ImmersionBox.C:129
MAX_ICHANNELS
#define MAX_ICHANNELS
Definition: vrpn_ImmersionBox.h:60
vrpn_write_characters
int vrpn_write_characters(int comm, const unsigned char *buffer, size_t bytes)
Write the buffer to the serial port.
Definition: vrpn_Serial.C:643
vrpn_ImmersionBox::mainloop
virtual void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_ImmersionBox.C:361
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_Analog::report_changes
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Definition: vrpn_Analog.C:71
vrpn_Dial::num_dials
vrpn_int32 num_dials
Definition: vrpn_Dial.h:27
vrpn_Dial::timestamp
struct timeval timestamp
Definition: vrpn_Dial.h:28
vrpn_ImmersionBox::reset
virtual int reset(void)
Definition: vrpn_ImmersionBox.C:149
vrpn_BaseClassUnique::server_mainloop
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
Definition: vrpn_BaseClass.C:603
vrpn_Button_Filter
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65