vrpn 07.35
Virtual Reality Peripheral Network
 
Loading...
Searching...
No Matches
vrpn_Tracker_RazerHydra.C
Go to the documentation of this file.
1
14
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 <utility>
35#include <stddef.h> // for size_t
36#include <stdio.h> // for fprintf, NULL, stderr
37#include <string.h> // for memset
38
39
40const unsigned int HYDRA_VENDOR = 0x1532;
41const unsigned int HYDRA_PRODUCT = 0x0300;
42const unsigned int HYDRA_INTERFACE = 0x0;
43const unsigned int HYDRA_CONTROL_INTERFACE = 0x1;
44
46static const vrpn_uint8 HYDRA_FEATURE_REPORT[] =
47{
48 0x00, // first byte must be report type
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x03, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x06, 0x00
57};
58static const int HYDRA_FEATURE_REPORT_LEN = 91;
59
61static const vrpn_uint8 HYDRA_GAMEPAD_COMMAND[] =
62{
63 0x00, // first byte must be report type
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x05, 0x00
72};
73static const int HYDRA_GAMEPAD_COMMAND_LEN = 91;
74
77static const unsigned long MAXIMUM_INITIAL_WAIT_USEC = 1000000L;
78
81static const unsigned long MAXIMUM_WAIT_USEC = 5000000L;
82
83#ifdef _WIN32
84#define VRPN_HAVE_RELIABLE_INTERFACE_NUMBER
85#endif
86
87static vrpn_HidAcceptor * makeHydraInterfaceAcceptor(unsigned whichInterface) {
89 try {
92#ifdef VRPN_HAVE_RELIABLE_INTERFACE_NUMBER
93 vrpn::OwningPtr<vrpn_HidAcceptor> interfaceAcceptor(
94 new vrpn_HidInterfaceNumberAcceptor(whichInterface));
95
98 interfaceAcceptor.release(), productAcceptor.release()));
99#else
100 // The InterfaceNumber is not supported on the mac and Linux versions -- it
101 // is always returned as -1. So we need to do this based on which
102 // device shows up first and hope that it is always the same order.
103 // On my mac, the control interface shows up first on iHid, so we
104 // try this order. If we get it wrong, then we swap things out later.
105
107 ret.reset(new vrpn_HidNthMatchAcceptor(whichInterface,
108 productAcceptor.release()));
109#endif
110 } catch (...) { return NULL; }
111 return ret.release();
112}
113
114class vrpn_Tracker_RazerHydra::MyInterface : public vrpn_HidInterface
115{
116 MyInterface(unsigned which_interface, vrpn_Tracker_RazerHydra *hydra,
117 hid_device *dev = NULL)
118 : vrpn_HidInterface(makeHydraInterfaceAcceptor(which_interface),
120 {
121 d_my_interface = which_interface;
122 d_hydra = hydra;
123 }
124 MyInterface(unsigned which_interface, vrpn_Tracker_RazerHydra *hydra,
125 const char *path)
126 : vrpn_HidInterface(path, makeHydraInterfaceAcceptor(which_interface),
128 {
129 d_my_interface = which_interface;
130 d_hydra = hydra;
131 }
132public:
138 static MyInterface *make(unsigned which_interface,
140 hid_device *dev = NULL)
141 {
142 MyInterface *ret;
143 try { ret = new MyInterface(which_interface, &hydra, dev); }
144 catch (...) { return NULL; }
145 return ret;
146 }
147 static MyInterface *make(unsigned which_interface,
149 const char *path)
150 {
151 MyInterface *ret;
152 try { ret = new MyInterface(which_interface, &hydra, path); }
153 catch (...) { return NULL; }
154 return ret;
155 }
156
157 void on_data_received(size_t bytes, vrpn_uint8 *buffer)
158 {
159 if (d_my_interface == HYDRA_CONTROL_INTERFACE)
160 {
161#ifdef VRPN_HAVE_RELIABLE_INTERFACE_NUMBER
162 fprintf(stderr, "Unexpected receipt of %d bytes on Hydra control interface!\n", static_cast<int>(bytes));
163 for (size_t i = 0; i < bytes; ++i)
164 {
165 fprintf(stderr, "%x ", buffer[i]);
166 }
167 fprintf(stderr, "\n");
168#else
169 d_hydra->send_text_message(vrpn_TEXT_WARNING)
170 << "Got report on controller channel. This means that we need to swap channels. "
171 << "Swapping channels.";
172 d_hydra->_swap_channels();
173#endif
174 }
175 else
176 {
177 if (bytes != 52)
178 {
179 d_hydra->send_text_message(vrpn_TEXT_WARNING)
180 << "Got input report of " << bytes << " bytes, expected 52! Discarding, and re-connecting to Hydra."
181#ifdef _WIN32
182 << " Please make sure that you have completely quit the Hydra Configurator software and the Hydra system tray icon,"
183 << " since this usually indicates that the Razer software has changed the Hydra's mode behind our back."
184#endif
185 ;
186 d_hydra->reconnect();
187 return;
188 }
189
190 if (d_hydra->status < HYDRA_REPORTING)
191 {
192
193 d_hydra->send_text_message(vrpn_TEXT_WARNING)
194 << "Got first motion controller report! This means everything is working properly now. "
195 << "(Took " << d_hydra->_attempt << " attempt" << (d_hydra->_attempt > 1 ? "s" : "") << " to change modes.)";
196 d_hydra->status = HYDRA_REPORTING;
197 }
198
199 vrpn_gettimeofday(&d_hydra->_timestamp, NULL);
200 double dt = vrpn_TimevalDurationSeconds(d_hydra->_timestamp, d_hydra->vrpn_Button::timestamp);
201 d_hydra->vrpn_Button::timestamp = d_hydra->_timestamp;
202 d_hydra->vrpn_Tracker::timestamp = d_hydra->_timestamp;
203
204 d_hydra->_report_for_sensor(0, buffer + 8, dt);
205 d_hydra->_report_for_sensor(1, buffer + 30, dt);
206
207 d_hydra->vrpn_Analog::report_changes(vrpn_CONNECTION_LOW_LATENCY, d_hydra->_timestamp);
208 d_hydra->vrpn_Button::report_changes();
209 }
210 }
211
212
213 std::string getSerialNumber()
214 {
215 if (connected())
216 {
217 char buf[256];
218 memset(buf, 0, sizeof(buf));
219 int bytes = get_feature_report(sizeof(buf) - 1, reinterpret_cast<vrpn_uint8*>(buf));
220 if (bytes > 0)
221 {
222 return std::string(buf + 216, 17);
223 }
224 else
225 {
226 return "[FAILED TO GET FEATURE REPORT]";
227 }
228 }
229 else
230 {
231 return "[HYDRA CONTROL INTERFACE NOT CONNECTED]";
232 }
233 }
234
235 void setMotionControllerMode()
236 {
238 send_feature_report(HYDRA_FEATURE_REPORT_LEN, HYDRA_FEATURE_REPORT);
239
240 vrpn_uint8 buf[91] = {0};
241 buf[0] = 0;
242 get_feature_report(91, buf);
243 }
244
245 void setGamepadMode()
246 {
248 send_feature_report(HYDRA_GAMEPAD_COMMAND_LEN, HYDRA_GAMEPAD_COMMAND);
249 }
250
251 bool connected()
252 {
254 }
255
256 void update()
257 {
259 }
260
261 void set_interface(unsigned which_interface)
262 {
263 d_my_interface = which_interface;
264 }
265
266 void reset_acceptor()
267 {
268 if (m_acceptor)
269 m_acceptor->reset();
270 }
271
272 protected:
273 unsigned d_my_interface;
275};
276
278 vrpn_Connection *con)
279 : vrpn_Analog(name, con)
280 , vrpn_Button_Filter(name, con)
281 , vrpn_Tracker(name, con)
282 , status(HYDRA_WAITING_FOR_CONNECT)
284 , _wasInGamepadMode(false)
285 , _attempt(0)
286 , _docking_distance(0.1f)
287{
288 // Set up the control and data channels
289 _ctrl.reset(MyInterface::make(HYDRA_CONTROL_INTERFACE, *this));
290 _data.reset(MyInterface::make(HYDRA_INTERFACE, *this));
291 _shared_init();
292}
293
295 hid_device *ctrl_dev,
296 hid_device *data_dev,
297 vrpn_Connection *con)
298 : vrpn_Analog(name, con)
299 , vrpn_Button_Filter(name, con)
300 , vrpn_Tracker(name, con)
301 , status(HYDRA_WAITING_FOR_CONNECT)
303 , _wasInGamepadMode(false)
304 , _attempt(0)
305 , _docking_distance(0.1f)
306{
307 // Set up the control and data channels. Convienently, the factory function
308 // handles the null device cases fine.
309 _ctrl.reset(MyInterface::make(HYDRA_CONTROL_INTERFACE, *this, ctrl_dev));
310 _data.reset(MyInterface::make(HYDRA_INTERFACE, *this, data_dev));
311 _shared_init();
312}
314 const char *ctrl_dev_path,
315 const char *data_dev_path,
316 vrpn_Connection *con)
317 : vrpn_Analog(name, con)
318 , vrpn_Button_Filter(name, con)
319 , vrpn_Tracker(name, con)
320 , status(HYDRA_WAITING_FOR_CONNECT)
322 , _wasInGamepadMode(false)
323 , _attempt(0)
324 , _docking_distance(0.1f)
325{
326 // Set up the control and data channels.
327 _ctrl.reset(
328 MyInterface::make(HYDRA_CONTROL_INTERFACE, *this, ctrl_dev_path));
329 _data.reset(MyInterface::make(HYDRA_INTERFACE, *this, data_dev_path));
330 _shared_init();
331}
332
333void vrpn_Tracker_RazerHydra::_shared_init() {
335 vrpn_Analog::num_channel = ANALOG_CHANNELS;
336 vrpn_Button::num_buttons = BUTTON_CHANNELS;
337 vrpn_Tracker::num_sensors = POSE_CHANNELS;
338
340 memset(buttons, 0, sizeof(buttons));
341 memset(lastbuttons, 0, sizeof(lastbuttons));
342 memset(channel, 0, sizeof(channel));
343 memset(last, 0, sizeof(last));
344
345 vrpn_gettimeofday(&_timestamp, NULL);
346
347 for (int i = 0; i < vrpn_Tracker::num_sensors; ++i)
348 {
349 _calibration_done[i] = false;
350 _mirror[i] = 1;
351 _sign_x[i] = 1;
352
353 memset(_old_position[i], 0, sizeof(q_vec_type));
354 memset(_calibration_pose_conj[i], 0, sizeof(q_type));
355 _calibration_pose_conj[i][Q_W] = 1.0;
356 }
357}
358
360{
361 if (status == HYDRA_REPORTING && _wasInGamepadMode)
362 {
364 << "Hydra was in gamepad mode when we started: switching back to gamepad mode.";
365 _ctrl->setGamepadMode();
366
367 send_text_message() << "Waiting 2 seconds for mode change to complete.";
368 vrpn_SleepMsecs(2000);
369 }
370}
371
373{
374 // server update. We only need to call this once for all three
375 // base devices because it is in the unique base class.
377
378 if (!_data->connected()) {
379 reconnect();
380 return;
381 }
382
383 // HID device update
384 _data->update();
385 _ctrl->update();
386
387 // Check/update listening state during connection/handshaking
388 switch(status)
389 {
390 case HYDRA_WAITING_FOR_CONNECT:
391 _waiting_for_connect();
392 break;
393
394 case HYDRA_LISTENING_AFTER_CONNECT:
395 _listening_after_connect();
396 break;
397
398 case HYDRA_LISTENING_AFTER_SET_FEATURE:
399 _listening_after_set_feature();
400 break;
401
402 case HYDRA_REPORTING:
403 default:
404 break;
405 }
406}
407
409{
410 status = HYDRA_WAITING_FOR_CONNECT;
411
412 // Reset calibration if we have to reconnect.
413 for (int i = 0; i < vrpn_Tracker::num_sensors; ++i)
414 {
415 _calibration_done[i] = false;
416 _mirror[i] = 1;
417 }
418
419 _data->reset_acceptor();
420 _data->reconnect();
421 _ctrl->reset_acceptor();
422 return _ctrl->reconnect();
423}
424
427void vrpn_Tracker_RazerHydra::_swap_channels() {
428 swap(_ctrl, _data);
429 _ctrl->set_interface(HYDRA_CONTROL_INTERFACE);
430 _data->set_interface(HYDRA_INTERFACE);
431}
432
433void vrpn_Tracker_RazerHydra::_waiting_for_connect()
434{
435 if (status != HYDRA_WAITING_FOR_CONNECT)
436 {
437 fprintf(stderr, "vrpn_Tracker_RazerHydra::_waiting_for_connect(): bad status\n");
438 return;
439 }
440 if (_data->connected() && _ctrl->connected())
441 {
442 send_text_message(vrpn_TEXT_WARNING) << "Connected to Razer Hydra with serial number " << _ctrl->getSerialNumber();
443
444 status = HYDRA_LISTENING_AFTER_CONNECT;
445 vrpn_gettimeofday(&_connected, NULL);
446 send_text_message() << "Listening to see if device is in motion controller mode.";
447
449 _attempt = 0;
451 _wasInGamepadMode = false;
452 }
453}
454
455void vrpn_Tracker_RazerHydra::_listening_after_connect()
456{
457 if (status != HYDRA_LISTENING_AFTER_CONNECT)
458 {
459 fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_connect(): bad status\n");
460 return;
461 }
462 if (!_data->connected() || !_ctrl->connected())
463 {
464 fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_connect(): Data or control channel not connected\n");
465 return;
466 }
467 struct timeval now;
468 vrpn_gettimeofday(&now, NULL);
469 if (vrpn_TimevalDuration(now, _connected) > MAXIMUM_INITIAL_WAIT_USEC)
470 {
471 _enter_motion_controller_mode();
472 }
473}
474
475void vrpn_Tracker_RazerHydra::_listening_after_set_feature()
476{
477 if (status != HYDRA_LISTENING_AFTER_SET_FEATURE)
478 {
479 fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_set_feature(): bad status\n");
480 return;
481 }
482 if (!_data->connected() || !_ctrl->connected())
483 {
484 fprintf(stderr, "vrpn_Tracker_RazerHydra::_listening_after_set_feature(): Data or control channel not connected\n");
485 return;
486 }
487 struct timeval now;
488 vrpn_gettimeofday(&now, NULL);
489 if (vrpn_TimevalDuration(now, _set_feature) > MAXIMUM_WAIT_USEC)
490 {
492 << "Really sleepy device - won't start motion controller reports despite our earlier "
493 << _attempt << " attempt" << (_attempt > 1 ? ". " : "s. ")
494 << " Will give it another try. "
495 << "If this doesn't work, unplug and replug device and restart the VRPN server.";
496#ifndef VRPN_HAVE_RELIABLE_INTERFACE_NUMBER
497 if ((_attempt % 2) == 0)
498 {
500 << "Switching control and data interface (some systems can't "
501 "tell the difference) and trying again to wake it.";
502 _swap_channels();
503 }
504#endif
505 _enter_motion_controller_mode();
506 }
507}
508
509void vrpn_Tracker_RazerHydra::_enter_motion_controller_mode()
510{
511 if ( (status != HYDRA_LISTENING_AFTER_CONNECT) &&
512 (status != HYDRA_LISTENING_AFTER_SET_FEATURE) )
513 {
514 fprintf(stderr, "vrpn_Tracker_RazerHydra::_enter_motion_controller_mode(): bad status\n");
515 return;
516 }
517 if (!_data->connected())
518 {
519 fprintf(stderr, "vrpn_Tracker_RazerHydra::_enter_motion_controller_mode(): Control channel not connected\n");
520 return;
521 }
522
523 _attempt++;
524 _wasInGamepadMode = true;
525
533
535 << "Hydra not in motion-controller mode - attempting to change modes. "
536 << "Please be sure that the left and right sensors are to the left and "
537 << "right sides of the base for automatic calibration to take place.";
538
540 _ctrl->setMotionControllerMode();
541
542 status = HYDRA_LISTENING_AFTER_SET_FEATURE;
543 vrpn_gettimeofday(&_set_feature, NULL);
544}
545
546void vrpn_Tracker_RazerHydra::_report_for_sensor(int sensorNum, vrpn_uint8 * data, double /*dt*/)
547{
548 if (!d_connection) {
549 return;
550 }
551 static const double MM_PER_METER = 0.001;
552 static const double SCALE_INT16_TO_FLOAT_PLUSMINUS_1 = 1.0 / 32768.0;
553 static const double SCALE_UINT8_TO_FLOAT_0_TO_1 = 1.0 / 255.0;
554 const int channelOffset = sensorNum * 3;
555 // There are only 7 buttons per hydra, but the original driver code here
556 // skipped 8 per hand-held unit. We're leaving this the same to avoid
557 // clients having to remap their controls.
558 const int buttonOffset = sensorNum * 8;
559
560 d_sensor = sensorNum;
561
562 /*****************
563 * Decode pose
564 *****************/
565 pos[0] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * MM_PER_METER;
566 pos[1] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * MM_PER_METER;
567 pos[2] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * MM_PER_METER;
568
569 // Switch handedness when we read the Quaternion values.
570 // We do this by inverting the Y and Z axes; it is equivalent
571 // to invert the X and W axes.
572 d_quat[Q_W] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
573 d_quat[Q_X] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
574 d_quat[Q_Y] = -vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
575 d_quat[Q_Z] = -vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
576
577 q_normalize(d_quat, d_quat);
578
579 // autocalibrate if docked
580 _docked[sensorNum] = q_vec_magnitude(pos) < _docking_distance;
581 if(_docked[sensorNum]) {
582 _calibration_done[sensorNum] = true;
583
584 // store the base quaternion to fix up any bizarre rotations - ensures that we start x-right, y-front, z-up
585 // We invert the quaternion to undo its transformation.
586 q_invert(_calibration_pose_conj[sensorNum], d_quat);
587
588 // initialize hemisphere tracking
589 // coordinate sanity check - sensor 0 (left): -x, -y, -z
590 // sensor 1 (right) +x, -y, -z
591 if(pos[1] > 0 || pos[2] > 0) {
592 _mirror[sensorNum] = -1; // wrong hemisphere, switch
593 } else {
594 _mirror[sensorNum] = 1;
595 }
596
597 q_vec_type tmp;
598 q_vec_copy(tmp, pos);
599 q_vec_scale(tmp, _mirror[sensorNum], tmp);
600
601 // Hydra sometimes starts up with the x axis inverted (left-handed), so
602 // we catch the case here and correct for it
603 if(sensorNum == 0)
604 _sign_x[0] = (tmp[0] < 0) ? 1 : -1;
605 else
606 _sign_x[1] = (tmp[0] > 0) ? 1 : -1;
607
608 tmp[0] *= _sign_x[sensorNum];
609
610 q_vec_copy(_old_position[sensorNum], tmp);
611 }
612
613 if (_calibration_done[sensorNum]) {
614 // apply orientation calibration, undoing the original
615 // rotation and then doing the current rotation using the
616 // calibration data.
617 q_mult(d_quat, d_quat, _calibration_pose_conj[sensorNum]);
618
619 // apply sign correction (left/right-handed)
620 pos[0] *= _sign_x[sensorNum];
621
622 // apply current hemisphere fix
623 q_vec_scale(pos, _mirror[sensorNum], pos);
624
625 if(!_docked[sensorNum]) {
626 // check for hemisphere transition
627 q_vec_type v_direct, v_mirror, pos_inv;
628 q_vec_subtract(v_direct, pos, _old_position[sensorNum]);
629
630 q_vec_invert(pos_inv, pos);
631 q_vec_subtract(v_mirror, pos_inv, _old_position[sensorNum]);
632
633 double dist_direct = q_vec_magnitude(v_direct);
634 double dist_mirror = q_vec_magnitude(v_mirror);
635
636 // too big jump, likely hemisphere switch
637 // in that case the coordinates given are mirrored symmetrically across the base
638 if (dist_direct > dist_mirror) {
639 /*
640 fprintf(stdout, "%d Switched hemisphere! %3.2f %3.2f\n", sensorNum, dist_direct, dist_mirror);
641 fprintf(stdout, "\tOld: %3.2f, %3.2f, %3.2f Current: %3.2f, %3.2f, %3.2f\n",
642 _old_position[sensorNum][0], _old_position[sensorNum][1], _old_position[sensorNum][2],
643 pos[0], pos[1], pos[2]);
644 */
645
646 q_vec_copy(pos, pos_inv);
647 _mirror[sensorNum] *= -1;
648 }
649 }
650 }
651
652 // store the data
653 q_vec_copy(_old_position[sensorNum], pos);
654
655 /*****************
656 * Decode buttons
657 *****************/
658
659 vrpn_uint8 buttonBits = vrpn_unbuffer_from_little_endian<vrpn_uint8>(data);
660
662 buttons[0 + buttonOffset] = (buttonBits & 0x20) != 0;
663
665 buttons[1 + buttonOffset] = (buttonBits & 0x04) != 0;
666 buttons[2 + buttonOffset] = (buttonBits & 0x08) != 0;
667 buttons[3 + buttonOffset] = (buttonBits & 0x02) != 0;
668 buttons[4 + buttonOffset] = (buttonBits & 0x10) != 0;
669
671 buttons[5 + buttonOffset] = (buttonBits & 0x01) != 0;
672
674 buttons[6 + buttonOffset] = (buttonBits & 0x40) != 0;
675
676 /*********************
677 * Decode analog axes
678 *********************/
679
681 channel[0 + channelOffset] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
682 channel[1 + channelOffset] = vrpn_unbuffer_from_little_endian<vrpn_int16>(data) * SCALE_INT16_TO_FLOAT_PLUSMINUS_1;
683
685 channel[2 + channelOffset] = vrpn_unbuffer_from_little_endian<vrpn_uint8>(data) * SCALE_UINT8_TO_FLOAT_0_TO_1;
686
687 /************************
688 * Send report for sensor
689 ************************/
690
691 char msgbuf[512];
692 int len = vrpn_Tracker::encode_to(msgbuf);
693 if (d_connection->pack_message(len, _timestamp, position_m_id, d_sender_id, msgbuf,
695 {
696 fprintf(stderr, "vrpn_Tracker_RazerHydra: cannot write message: tossing\n");
697 }
698}
699
700#endif // VRPN_USE_HID
A unique-ownership smart pointer, with the ability to transfer ownership, but only explicitly (aka,...
void reset(pointer p=pointer())
Deletes the owned object, if any, and takes ownership of a new object, if one is passed.
pointer release()
Returns the held pointer without performing the delete action.
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:39
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:38
vrpn_Analog(const char *name, vrpn_Connection *c=NULL)
Definition vrpn_Analog.C:14
vrpn_int32 num_channel
Definition vrpn_Analog.h:40
vrpn_Connection * d_connection
Connection that this object talks to.
vrpn_int32 d_sender_id
Sender ID registered with the connection.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
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.
vrpn_Button_Filter(const char *, vrpn_Connection *c=NULL)
vrpn_int32 num_buttons
Definition vrpn_Button.h:48
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:46
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:45
Generic connection class not specific to the transport mechanism.
Accepts only devices meeting two criteria. NOT SHORT-CIRCUIT. Another demonstration of acceptor compo...
Accepts any device with a particular interface number. Best in conjunction with vrpn_HidBooleanAndAcc...
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 ...
vrpn_HidInterface(vrpn_HidAcceptor *acceptor, vrpn_uint16 vendor=0, vrpn_uint16 product=0, hid_device *device=NULL)
Constructor If we already have a HID device from some other source, it can be passed and we'll take o...
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...
vrpn_HidAcceptor * m_acceptor
This is the HidAcceptor we use when reconnecting.
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
virtual bool connected() const
Returns true iff the last device I/O succeeded.
Accepts the Nth device matching a given acceptor.
Accepts any device with the given vendor and product IDs.
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
vrpn_Tracker_RazerHydra(const char *name, vrpn_Connection *con=NULL)
virtual int encode_to(char *buf)
vrpn_float64 d_quat[4]
vrpn_Tracker(const char *name, vrpn_Connection *c=NULL, const char *tracker_cfg_file_name=NULL)
vrpn_int32 d_sensor
vrpn_float64 pos[3]
vrpn_int32 num_sensors
vrpn_int32 position_m_id
@ vrpn_TEXT_WARNING
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
struct hid_device_ hid_device
Header allowing use of a output stream-style method of sending text messages from devices.
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
double vrpn_TimevalDurationSeconds(struct timeval endT, struct timeval startT)
Return the number of seconds between startT and endT as a floating-point value.
void vrpn_SleepMsecs(double dMilliSecs)
#define vrpn_gettimeofday
Definition vrpn_Shared.h:99
const unsigned int HYDRA_PRODUCT
const unsigned int HYDRA_VENDOR
const unsigned int HYDRA_CONTROL_INTERFACE
const unsigned int HYDRA_INTERFACE