vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Tracker_RazerHydra.C
Go to the documentation of this file.
1 
15 // Copyright Iowa State University 2011.
16 // Distributed under the Boost Software License, Version 1.0.
17 // (See accompanying file LICENSE_1_0.txt or copy at
18 // http://www.boost.org/LICENSE_1_0.txt)
19 
20 // Internal Includes
23 
24 #ifdef VRPN_USE_HID
25 #include "vrpn_HumanInterface.h" // for vrpn_HidInterface, etc
26 #include "vrpn_SendTextMessageStreamProxy.h" // for operator<<, etc
27 
28 // Library/third-party includes
29 // - none
30 
31 // Standard includes
32 #include <sstream> // for operator<<, basic_ostream, etc
33 #include <string> // for char_traits, basic_string, etc
34 #include <stddef.h> // for size_t
35 #include <stdio.h> // for fprintf, NULL, stderr
36 #include <string.h> // for memset
37 
38 
39 const unsigned int HYDRA_VENDOR = 0x1532;
40 const unsigned int HYDRA_PRODUCT = 0x0300;
41 const unsigned int HYDRA_INTERFACE = 0x0;
42 const unsigned int HYDRA_CONTROL_INTERFACE = 0x1;
43 
45 static const vrpn_uint8 HYDRA_FEATURE_REPORT[] =
46 {
47  0x00, // first byte must be report type
48  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00,
49  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55  0x00, 0x00, 0x00, 0x00, 0x06, 0x00
56 };
57 static const int HYDRA_FEATURE_REPORT_LEN = 91;
58 
60 static const vrpn_uint8 HYDRA_GAMEPAD_COMMAND[] =
61 {
62  0x00, // first byte must be report type
63  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
64  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70  0x00, 0x00, 0x00, 0x00, 0x05, 0x00
71 };
72 static const int HYDRA_GAMEPAD_COMMAND_LEN = 91;
73 
76 static const unsigned long MAXIMUM_INITIAL_WAIT_USEC = 1000000L;
77 
80 static const unsigned long MAXIMUM_WAIT_USEC = 5000000L;
81 
82 class vrpn_Tracker_RazerHydra::MyInterface : public vrpn_HidInterface
83 {
84  public:
85  MyInterface(unsigned which_interface, vrpn_Tracker_RazerHydra *hydra)
86 #ifndef _WIN32
87  // The InterfaceNumber is not supported on the mac and Linux versions -- it
88  // is always returned as -1. So we need to do this based on which
89  // device shows up first and hope that it is always the same order.
90  // On my mac, the control interface shows up first on iHid, so we
91  // try this order. If we get it wrong, then we swap things out later.
92  : vrpn_HidInterface(new vrpn_HidNthMatchAcceptor(which_interface,
93 #else
95  new vrpn_HidInterfaceNumberAcceptor(which_interface),
96 #endif
98  {
99  d_my_interface = which_interface;
100  d_hydra = hydra;
101  }
102 
103  void on_data_received(size_t bytes, vrpn_uint8 *buffer)
104  {
105  if (d_my_interface == HYDRA_CONTROL_INTERFACE)
106  {
107 #ifndef _WIN32
108  d_hydra->send_text_message(vrpn_TEXT_WARNING)
109  << "Got report on controller channel. This means that we need to swap channels. "
110  << "Swapping channels.";
111 
112  MyInterface *t = d_hydra->_ctrl;
113  d_hydra->_ctrl = d_hydra->_data;
114  d_hydra->_data = t;
115  d_hydra->_ctrl->set_interface(HYDRA_CONTROL_INTERFACE);
116  d_hydra->_data->set_interface(HYDRA_INTERFACE);
117 #else
118  fprintf(stderr, "Unexpected receipt of %d bytes on Hydra control interface!\n", static_cast<int>(bytes));
119  for (size_t i = 0; i < bytes; ++i)
120  {
121  fprintf(stderr, "%x ", buffer[i]);
122  }
123  fprintf(stderr, "\n");
124 #endif
125  }
126  else
127  {
128  if (bytes != 52)
129  {
130  d_hydra->send_text_message(vrpn_TEXT_WARNING)
131  << "Got input report of " << bytes << " bytes, expected 52! Discarding, and re-connecting to Hydra."
132 #ifdef _WIN32
133  << " Please make sure that you have completely quit the Hydra Configurator software and the Hydra system tray icon,"
134  << " since this usually indicates that the Razer software has changed the Hydra's mode behind our back."
135 #endif
136  ;
137  d_hydra->reconnect();
138  return;
139  }
140 
141  if (d_hydra->status < HYDRA_REPORTING)
142  {
143 
144  d_hydra->send_text_message(vrpn_TEXT_WARNING)
145  << "Got first motion controller report! This means everything is working properly now. "
146  << "(Took " << d_hydra->_attempt << " attempt" << (d_hydra->_attempt > 1 ? "s" : "") << " to change modes.)";
147  d_hydra->status = HYDRA_REPORTING;
148  }
149 
150  vrpn_gettimeofday(&d_hydra->_timestamp, NULL);
151  double dt = vrpn_TimevalDurationSeconds(d_hydra->_timestamp, d_hydra->vrpn_Button::timestamp);
152  d_hydra->vrpn_Button::timestamp = d_hydra->_timestamp;
153  d_hydra->vrpn_Tracker::timestamp = d_hydra->_timestamp;
154 
155  d_hydra->_report_for_sensor(0, buffer + 8, dt);
156  d_hydra->_report_for_sensor(1, buffer + 30, dt);
157 
158  d_hydra->vrpn_Analog::report_changes(vrpn_CONNECTION_LOW_LATENCY, d_hydra->_timestamp);
159  d_hydra->vrpn_Button::report_changes();
160  }
161  }
162 
163 
164  std::string getSerialNumber()
165  {
166  if (connected())
167  {
168  char buf[256];
169  memset(buf, 0, sizeof(buf));
170  int bytes = get_feature_report(sizeof(buf) - 1, reinterpret_cast<vrpn_uint8*>(buf));
171  if (bytes > 0)
172  {
173  return std::string(buf + 216, 17);
174  }
175  else
176  {
177  return "[FAILED TO GET FEATURE REPORT]";
178  }
179  }
180  else
181  {
182  return "[HYDRA CONTROL INTERFACE NOT CONNECTED]";
183  }
184  }
185 
186  void setMotionControllerMode()
187  {
189  send_feature_report(HYDRA_FEATURE_REPORT_LEN, HYDRA_FEATURE_REPORT);
190 
191  vrpn_uint8 buf[91] = {0};
192  buf[0] = 0;
193  get_feature_report(91, buf);
194  }
195 
196  void setGamepadMode()
197  {
199  send_feature_report(HYDRA_GAMEPAD_COMMAND_LEN, HYDRA_GAMEPAD_COMMAND);
200  }
201 
202  bool connected()
203  {
205  }
206 
207  void update()
208  {
210  }
211 
212  void set_interface(unsigned which_interface)
213  {
214  d_my_interface = which_interface;
215  }
216 
217  protected:
218  unsigned d_my_interface;
219  vrpn_Tracker_RazerHydra *d_hydra;
220 };
221 
223  : vrpn_Analog(name, con)
224  , vrpn_Button_Filter(name, con)
225  , vrpn_Tracker(name, con)
226  , status(HYDRA_WAITING_FOR_CONNECT)
227  , _wasInGamepadMode(false)
228  , _attempt(0)
229  , _docking_distance(0.1f)
230 {
231  // Set up the control and data channels
232  _ctrl = new MyInterface(HYDRA_CONTROL_INTERFACE, this);
233  _data = new MyInterface(HYDRA_INTERFACE, this);
234 
236  vrpn_Analog::num_channel = ANALOG_CHANNELS;
237  vrpn_Button::num_buttons = BUTTON_CHANNELS;
238  vrpn_Tracker::num_sensors = POSE_CHANNELS;
239 
241  memset(buttons, 0, sizeof(buttons));
242  memset(lastbuttons, 0, sizeof(lastbuttons));
243  memset(channel, 0, sizeof(channel));
244  memset(last, 0, sizeof(last));
245 
246  vrpn_gettimeofday(&_timestamp, NULL);
247 
248  for (int i = 0; i < vrpn_Tracker::num_sensors; ++i)
249  {
250  _calibration_done[i] = false;
251  _mirror[i] = 1;
252  _sign_x[i] = 1;
253 
254  memset(_old_position[i], 0, sizeof(q_vec_type));
255  memset(_calibration_pose_conj[i], 0, sizeof(q_type));
256  _calibration_pose_conj[i][Q_W] = 1.0;
257  }
258 }
259 
261 {
262  if (status == HYDRA_REPORTING && _wasInGamepadMode)
263  {
265  << "Hydra was in gamepad mode when we started: switching back to gamepad mode.";
266  _ctrl->setGamepadMode();
267 
268  send_text_message() << "Waiting 2 seconds for mode change to complete.";
269  vrpn_SleepMsecs(2000);
270  }
271 
272  delete _ctrl;
273 }
274 
276 {
277  // server update. We only need to call this once for all three
278  // base devices because it is in the unique base class.
279  server_mainloop();
280 
281  if (_data->connected())
282  {
283  // HID device update
284  _data->update();
285  _ctrl->update();
286 
287  // Check/update listening state during connection/handshaking
288  switch(status)
289  {
290  case HYDRA_WAITING_FOR_CONNECT:
291  _waiting_for_connect();
292  break;
293 
294  case HYDRA_LISTENING_AFTER_CONNECT:
295  _listening_after_connect();
296  break;
297 
298  case HYDRA_LISTENING_AFTER_SET_FEATURE:
299  _listening_after_set_feature();
300  break;
301 
302  case HYDRA_REPORTING:
303  default:
304  break;
305  }
306  }
307 }
308 
310 {
311  status = HYDRA_WAITING_FOR_CONNECT;
312 
313  // Reset calibration if we have to reconnect.
314  for (int i = 0; i < vrpn_Tracker::num_sensors; ++i)
315  {
316  _calibration_done[i] = false;
317  _mirror[i] = 1;
318  }
319 
320  _data->reconnect();
321  return _ctrl->reconnect();
322 }
323 
324 void vrpn_Tracker_RazerHydra::_waiting_for_connect()
325 {
326  if (status != HYDRA_WAITING_FOR_CONNECT)
327  {
328  fprintf(stderr, "vrpn_Tracker_RazerHydra::_waiting_for_connect(): bad status\n");
329  return;
330  }
331  if (_data->connected() && _ctrl->connected())
332  {
333  send_text_message(vrpn_TEXT_WARNING) << "Connected to Razer Hydra with serial number " << _ctrl->getSerialNumber();
334 
335  status = HYDRA_LISTENING_AFTER_CONNECT;
336  vrpn_gettimeofday(&_connected, NULL);
337  send_text_message() << "Listening to see if device is in motion controller mode.";
338 
340  _attempt = 0;
342  _wasInGamepadMode = false;
343  }
344 }
345 
346 void vrpn_Tracker_RazerHydra::_listening_after_connect()
347 {
348  if (status != HYDRA_LISTENING_AFTER_CONNECT)
349  {
350  fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_connect(): bad status\n");
351  return;
352  }
353  if (!_data->connected() || !_ctrl->connected())
354  {
355  fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_connect(): Data or control channel not connected\n");
356  return;
357  }
358  struct timeval now;
359  vrpn_gettimeofday(&now, NULL);
360  if (vrpn_TimevalDuration(now, _connected) > MAXIMUM_INITIAL_WAIT_USEC)
361  {
362  _enter_motion_controller_mode();
363  }
364 }
365 
366 void vrpn_Tracker_RazerHydra::_listening_after_set_feature()
367 {
368  if (status != HYDRA_LISTENING_AFTER_SET_FEATURE)
369  {
370  fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_set_feature(): bad status\n");
371  return;
372  }
373  if (!_data->connected() || !_ctrl->connected())
374  {
375  fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_set_feature(): Data or control channel not connected\n");
376  return;
377  }
378  struct timeval now;
379  vrpn_gettimeofday(&now, NULL);
380  if (vrpn_TimevalDuration(now, _set_feature) > MAXIMUM_WAIT_USEC)
381  {
383  << "Really sleepy device - won't start motion controller reports despite our earlier "
384  << _attempt << " attempt" << (_attempt > 1 ? ". " : "s. ")
385  << " Will give it another try. "
386  << "If this doesn't work, unplug and replug device and restart the VRPN server.";
387 #ifndef _WIN32
388  if ((_attempt % 2) == 0)
389  {
391  << "Switching control and data interface (mac can't tell the difference).";
392  MyInterface *t = _ctrl;
393  _ctrl = _data;
394  _data = t;
395  _ctrl->set_interface(HYDRA_CONTROL_INTERFACE);
396  _data->set_interface(HYDRA_INTERFACE);
397  }
398 #endif
399  _enter_motion_controller_mode();
400  }
401 }
402 
403 void vrpn_Tracker_RazerHydra::_enter_motion_controller_mode()
404 {
405  if ( (status != HYDRA_LISTENING_AFTER_CONNECT) &&
406  (status != HYDRA_LISTENING_AFTER_SET_FEATURE) )
407  {
408  fprintf(stderr, "vrpn_Tracker_RazerHydra::_enter_motion_controller_mode(): bad status\n");
409  return;
410  }
411  if (!_data->connected())
412  {
413  fprintf(stderr, "vrpn_Tracker_RazerHydra::_enter_motion_controller_mode(): Control channel not connected\n");
414  return;
415  }
416 
417  _attempt++;
418  _wasInGamepadMode = true;
419 
429  << "Hydra not in motion-controller mode - attempting to change modes. "
430  << "Please be sure that the left and right sensors are to the left and "
431  << "right sides of the base for automatic calibration to take place.";
432 
434  _ctrl->setMotionControllerMode();
435 
436  status = HYDRA_LISTENING_AFTER_SET_FEATURE;
437  vrpn_gettimeofday(&_set_feature, NULL);
438 }
439 
440 void vrpn_Tracker_RazerHydra::_report_for_sensor(int sensorNum, vrpn_uint8 * data, double dt)
441 {
442  if (!d_connection)
443  {
444  return;
445  }
446  static const double MM_PER_METER = 0.001;
447  static const double SCALE_INT16_TO_FLOAT_PLUSMINUS_1 = 1.0 / 32768.0;
448  static const double SCALE_UINT8_TO_FLOAT_0_TO_1 = 1.0 / 255.0;
449  const int channelOffset = sensorNum * 3;
450  // There are only 7 buttons per hydra, but the original driver code here
451  // skipped 8 per hand-held unit. We're leaving this the same to avoid
452  // clients having to remap their controls.
453  const int buttonOffset = sensorNum * 8;
454 
455  d_sensor = sensorNum;
456 
457  /*****************
458  * Decode pose
459  *****************/
460  pos[0] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * MM_PER_METER;
461  pos[1] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * MM_PER_METER;
462  pos[2] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * MM_PER_METER;
463 
464  // Switch handedness when we read the Quaternion values.
465  // We do this by inverting the Y and Z axes; it is equivalent
466  // to invert the X and W axes.
467  d_quat[Q_W] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
468  d_quat[Q_X] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
469  d_quat[Q_Y] = -vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
470  d_quat[Q_Z] = -vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
471 
472  q_normalize(d_quat, d_quat);
473 
474  // autocalibrate if docked
475  _docked[sensorNum] = q_vec_magnitude(pos) < _docking_distance;
476  if(_docked[sensorNum])
477  {
478  _calibration_done[sensorNum] = true;
479 
480  // store the base quaternion to fix up any bizarre rotations - ensures that we start x-right, y-front, z-up
481  // We invert the quaternion to undo its transformation.
482  q_invert(_calibration_pose_conj[sensorNum], d_quat);
483 
484  // initialize hemisphere tracking
485  // coordinate sanity check - sensor 0 (left): -x, -y, -z
486  // sensor 1 (right) +x, -y, -z
487  if(pos[1] > 0 || pos[2] > 0)
488  _mirror[sensorNum] = -1; // wrong hemisphere, switch
489  else
490  _mirror[sensorNum] = 1;
491 
492  q_vec_type tmp;
493  q_vec_copy(tmp, pos);
494  q_vec_scale(tmp, _mirror[sensorNum], tmp);
495 
496  // Hydra sometimes starts up with the x axis inverted (left-handed), so
497  // we catch the case here and correct for it
498  if(sensorNum == 0)
499  _sign_x[0] = (tmp[0] < 0) ? 1 : -1;
500  else
501  _sign_x[1] = (tmp[0] > 0) ? 1 : -1;
502 
503  tmp[0] *= _sign_x[sensorNum];
504 
505  q_vec_copy(_old_position[sensorNum], tmp);
506  }
507 
508  if (_calibration_done[sensorNum])
509  {
510  // apply orientation calibration, undoing the original
511  // rotation and then doing the current rotation using the
512  // calibration data.
513  q_mult(d_quat, d_quat, _calibration_pose_conj[sensorNum]);
514 
515  // apply sign correction (left/right-handed)
516  pos[0] *= _sign_x[sensorNum];
517 
518  // apply current hemisphere fix
519  q_vec_scale(pos, _mirror[sensorNum], pos);
520 
521  if(!_docked[sensorNum])
522  {
523  // check for hemisphere transition
524  q_vec_type v_direct, v_mirror, pos_inv;
525  q_vec_subtract(v_direct, pos, _old_position[sensorNum]);
526 
527  q_vec_invert(pos_inv, pos);
528  q_vec_subtract(v_mirror, pos_inv, _old_position[sensorNum]);
529 
530  double dist_direct = q_vec_magnitude(v_direct);
531  double dist_mirror = q_vec_magnitude(v_mirror);
532 
533  // too big jump, likely hemisphere switch
534  // in that case the coordinates given are mirrored symmetrically across the base
535  if (dist_direct > dist_mirror)
536  {
537  /*
538  fprintf(stdout, "%d Switched hemisphere! %3.2f %3.2f\n", sensorNum, dist_direct, dist_mirror);
539  fprintf(stdout, "\tOld: %3.2f, %3.2f, %3.2f Current: %3.2f, %3.2f, %3.2f\n",
540  _old_position[sensorNum][0], _old_position[sensorNum][1], _old_position[sensorNum][2],
541  pos[0], pos[1], pos[2]);
542  */
543 
544  q_vec_copy(pos, pos_inv);
545  _mirror[sensorNum] *= -1;
546  }
547  }
548  }
549 
550  // store the data
551  q_vec_copy(_old_position[sensorNum], pos);
552 
553  /*****************
554  * Decode buttons
555  *****************/
556 
557  vrpn_uint8 buttonBits = vrpn_unbuffer_from_little_endian<vrpn_uint8>(data);
558 
560  buttons[0 + buttonOffset] = (buttonBits & 0x20) != 0;
561 
563  buttons[1 + buttonOffset] = (buttonBits & 0x04) != 0;
564  buttons[2 + buttonOffset] = (buttonBits & 0x08) != 0;
565  buttons[3 + buttonOffset] = (buttonBits & 0x02) != 0;
566  buttons[4 + buttonOffset] = (buttonBits & 0x10) != 0;
567 
569  buttons[5 + buttonOffset] = (buttonBits & 0x01) != 0;
570 
572  buttons[6 + buttonOffset] = (buttonBits & 0x40) != 0;
573 
574 
575  /*********************
576  * Decode analog axes
577  *********************/
578 
580  channel[0 + channelOffset] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
581  channel[1 + channelOffset] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
582 
584  channel[2 + channelOffset] = vrpn_unbuffer_from_little_endian<vrpn_uint8>(data) * SCALE_UINT8_TO_FLOAT_0_TO_1;
585 
586  /************************
587  * Send report for sensor
588  ************************/
589 
590  char msgbuf[512];
591  int len = vrpn_Tracker::encode_to(msgbuf);
592  if (d_connection->pack_message(len, _timestamp, position_m_id, d_sender_id, msgbuf,
594  {
595  fprintf(stderr, "vrpn_Tracker_RazerHydra: cannot write message: tossing\n");
596  }
597 }
598 
599 #endif // VRPN_USE_HID
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
const unsigned int HYDRA_PRODUCT
Device supporting the Razer Hydra game controller as a tracker, analog device, and button device,...
void vrpn_SleepMsecs(double dMsecs)
Definition: vrpn_Shared.C:157
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
int get_feature_report(size_t bytes, vrpn_uint8 *buffer)
Call this to get a feature report from the device - first byte must be Report ID (or 0x0 for devices ...
const unsigned int HYDRA_VENDOR
virtual void on_data_received(size_t bytes, vrpn_uint8 *buffer)=0
Derived class reimplements this callback.
vrpn_Tracker_RazerHydra(const char *name, vrpn_Connection *trackercon)
vrpn_float64 pos[3]
Definition: vrpn_Tracker.h:95
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Accepts any device with the given vendor and product IDs.
Generic connection class not specific to the transport mechanism.
Accepts any device with a particular interface number. Best in conjunction with vrpn_HidBooleanAndAcc...
void send_feature_report(size_t bytes, const vrpn_uint8 *buffer)
Call this to send a feature report to the device - first byte must be Report ID (or 0x0 for devices w...
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const unsigned int HYDRA_CONTROL_INTERFACE
vrpn_int32 d_sensor
Definition: vrpn_Tracker.h:94
double vrpn_TimevalDurationSeconds(struct timeval endT, struct timeval startT)
Return the number of seconds between startT and endT as a floating-point value.
Definition: vrpn_Shared.C:135
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
Accepts the Nth device matching a given acceptor.
vrpn_Connection * d_connection
Connection that this object talks to.
virtual int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 class_of_service)
Pack a message that will be sent the next time mainloop() is called. Turn off the RELIABLE flag if yo...
vrpn_int32 num_sensors
Definition: vrpn_Tracker.h:114
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.
virtual int encode_to(char *buf)
Definition: vrpn_Tracker.C:533
Header allowing use of a output stream-style method of sending text messages from devices.
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65
vrpn_int32 d_sender_id
Sender ID registered with the connection.
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
Accepts only devices meeting two criteria. NOT SHORT-CIRCUIT. Another demonstration of acceptor compo...
vrpn_float64 d_quat[4]
Definition: vrpn_Tracker.h:95
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
Definition: vrpn_Shared.C:129
const unsigned int HYDRA_INTERFACE
virtual bool connected() const
Returns true iff the last device I/O succeeded.
vrpn_HidInterface(vrpn_HidAcceptor *acceptor)
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_int32 position_m_id
Definition: vrpn_Tracker.h:80