vrpn  07.33
Virtual Reality Peripheral Network
vrpn_DirectXFFJoystick.C
Go to the documentation of this file.
2 #if defined(_WIN32) && defined(VRPN_USE_DIRECTINPUT)
3 #include <math.h>
4 #include <algorithm> // for min
5 using std::min;
6 // vrpn_DirectXFFJoystick.C
7 // This is a driver for joysticks being used through the
8 // DirectX interface, both for input and for force feedback.
9 // The driver portions of this code are based on the Microsoft
10 // DirectInput example code from the DirectX SDK.
11 
12 #undef DEBUG
13 #undef VERBOSE
14 
15 // Defines the modes in which the box can find itself.
16 const int STATUS_BROKEN = -1; // Broken joystick
17 const int STATUS_READING = 1; // Looking for a report
18 
19 #define MAX_TIME_INTERVAL (2000000) // max time to try and reacquire
20 
21 // This creates a vrpn_CerealBox and sets it to reset mode. It opens
22 // the serial device using the code in the vrpn_Serial_Analog constructor.
23 // The box seems to autodetect the baud rate when the "T" command is sent
24 // to it.
25 vrpn_DirectXFFJoystick::vrpn_DirectXFFJoystick (const char * name, vrpn_Connection * c,
26  double readRate, double forceRate) :
27  vrpn_Analog(name, c),
28  vrpn_Button_Filter(name, c),
29  vrpn_ForceDeviceServer(name, c),
30  _read_rate(readRate),
31  _force_rate(forceRate),
32  _DirectInput(NULL),
33  _Joystick(NULL),
34  _ForceEffect(NULL),
35  _numchannels(min(12,vrpn_CHANNEL_MAX)), // Maximum available
36  _numbuttons(min(128,vrpn_BUTTON_MAX_BUTTONS)), // Maximum available
37  _numforceaxes(0) // Filles in later.
38 {
39  // Never yet sent forces.
40  _forcetime.tv_sec = 0;
41  _forcetime.tv_usec = 0;
42 
43  // Never sent a report
44  _last_report.tv_sec = 0;
45  _last_report.tv_usec = 0;
46 
47  // No nonzero previous forces.
48  _fx_1 = _fy_1 = 0.0;
49  _fx_2 = _fy_2 = 0.0;
50 
51  // In case we exit early for some reason.
52  _status = STATUS_BROKEN;
53 
54  // Set the parameters in the parent classes
55  vrpn_Button::num_buttons = _numbuttons;
56  vrpn_Analog::num_channel = _numchannels;
57  if (_numchannels < 12) {
58  fprintf(stderr,"vrpn_DirectXFFJoystick::vrpn_DirectXFFJoystick(): Not enough analog channels!\n");
59  _hWnd = NULL;
60  return;
61  }
62 
63  // Set the status of the buttons and analogs to 0 to start
64  clear_values();
65 
66  // We need a non-console window handle to give to the function if we are
67  // asking for exclusive access (I don't know why, but we do).
68  _hWnd = CreateWindow("STATIC", "JoystickWindow", WS_ICONIC, 0,0, 10,10, NULL, NULL, NULL, NULL);
69 
70  // Initialize DirectInput and set the axes to return numbers in the range
71  // -1000 to 1000. We make the same mapping for analogs and sliders, so we
72  // don't care how many this particular joystick has. This enables users of
73  // joysticks to keep the same mappings (but does not pass on the list of
74  // what is actually intalled, unfortunately).
75  // If we're using a forceDevice, then set it up as well.
76 #ifdef DEBUG
77  printf("vrpn_DirectXFFJoystick::vrpn_DirectXFFJoystick(): Window handle %ld\n", _hWnd);
78 #endif
79  if( FAILED( InitDirectJoystick() ) ) {
80  fprintf(stderr,"vrpn_DirectXFFJoystick::vrpn_DirectXFFJoystick(): Failed to open direct joystick\n");
81  _hWnd = NULL;
82  return;
83  }
84 
85  // Zero the forces on the device, if we have one.
86  if (_force_rate > 0) {
87  _fX = _fY = 0;
88  send_normalized_force(0,0);
89  }
90 
91  // Register an autodeleted handler on the "last connection dropped" system message
92  // and have it call a routine that zeroes the forces when it is called.
94 
95  // Register handlers for the force-feedback messages coming from the remote object.
96  // XXX Eventually, fill out this list. For now, we have only planes.
97  if (_force_rate > 0) {
98  if (register_autodeleted_handler(plane_message_id,
99  handle_plane_change_message, this, vrpn_ForceDevice::d_sender_id)) {
100  fprintf(stderr,"vrpn_DirectXFFJoystick:can't register plane handler\n");
101  return;
102  }
103  if (register_autodeleted_handler(forcefield_message_id,
104  handle_forcefield_change_message, this, vrpn_ForceDevice::d_sender_id)) {
105  fprintf(stderr,"vrpn_DirectXFFJoystick:can't register force handler\n");
106  return;
107  }
108  }
109 
110  // Set the mode to reading. Set time to zero, so we'll try to read
111  _status = STATUS_READING;
112  vrpn_gettimeofday(&_timestamp, NULL);
113 }
114 
115 vrpn_DirectXFFJoystick::~vrpn_DirectXFFJoystick()
116 {
117  // Remove the ForceEffect if there is one
118  if ( _ForceEffect ) {
119  send_normalized_force(0,0);
120  _ForceEffect->Release();
121  _ForceEffect = NULL;
122  }
123 
124  // Unacquire the device one last time just in case
125  // the app tried to exit while the device is still acquired.
126  if( _Joystick ) {
127  _Joystick->Unacquire();
128  _Joystick->Release();
129  _Joystick = NULL;
130  }
131 
132  // Release any DirectInput objects.
133  if ( _DirectInput ) {
134  _DirectInput->Release();
135  _DirectInput = NULL;
136  }
137 }
138 
139 HRESULT vrpn_DirectXFFJoystick::InitDirectJoystick( void )
140 {
141  HRESULT hr;
142 
143  // Register with the DirectInput subsystem and get a pointer
144  // to a IDirectInput interface we can use.
145  // Create a DInput object
146  if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,
147  IID_IDirectInput8, (VOID**)&_DirectInput, NULL ) ) ) {
148  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Cannot open DirectInput\n");
149  _status = STATUS_BROKEN;
150  return hr;
151  }
152 
153  // Look for a simple joystick we can use for this sample program; if we want force feedback,
154  // then also look for one that has this feature.
155  long device_type = DIEDFL_ATTACHEDONLY;
156  if (_force_rate > 0) { device_type |= DIEDFL_FORCEFEEDBACK; }
157  if( FAILED( hr = _DirectInput->EnumDevices( DI8DEVCLASS_GAMECTRL,
158  EnumJoysticksCallback,
159  this, device_type ) ) ) {
160  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Cannot Enumerate devices\n");
161  _status = STATUS_BROKEN;
162  return hr;
163  }
164 
165  // Make sure we got a joystick of the type we wanted
166  if( NULL == _Joystick ) {
167  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): No joystick found\n");
168  _status = STATUS_BROKEN;
169  return E_FAIL;
170  }
171 
172  // Set the data format to "simple joystick" - a predefined data format
173  //
174  // A data format specifies which controls on a device we are interested in,
175  // and how they should be reported. This tells DInput that we will be
176  // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
177  if( FAILED( hr = _Joystick->SetDataFormat( &c_dfDIJoystick2 ) ) ) {
178  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Cannot set data format\n");
179  _status = STATUS_BROKEN;
180  return hr;
181  }
182 
183  // Set the cooperative level to let DInput know how this device should
184  // interact with the system and with other DInput applications.
185  // Exclusive access is required in order to perform force feedback.
186  // Exclusive access is also required to keep other applications (like VMD)
187  // from opening the same joystick, so we'll use it all the time.
188  long access_type = DISCL_EXCLUSIVE | DISCL_BACKGROUND;
189  if( FAILED( hr = _Joystick->SetCooperativeLevel( _hWnd, access_type) ) ) {
190  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Cannot set cooperative level\n");
191  _status = STATUS_BROKEN;
192  return hr;
193  }
194 
195  // Enumerate the joystick objects. The callback function enabled user
196  // interface elements for objects that are found, and sets the min/max
197  // values property for discovered axes.
198  if( FAILED( hr = _Joystick->EnumObjects( EnumObjectsCallback, this, DIDFT_ALL ) ) ) {
199  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Cannot enumerate objects\n");
200  _status = STATUS_BROKEN;
201  return hr;
202  }
203  if (_force_rate > 0) {
204  if (_numforceaxes != 2) {
205  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Not two force axes, disabling forces\n");
206  _force_rate = 0;
207  } else {
208 #ifdef DEBUG
209  printf("vrpn_DirectXFFJoystick::InitDirectJoystick(): found %d force axes\n", _numforceaxes);
210 #endif
211  // Since we will be playing force feedback effects, we should disable the
212  // auto-centering spring.
213  DIPROPDWORD dipdw;
214  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
215  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
216  dipdw.diph.dwObj = 0;
217  dipdw.diph.dwHow = DIPH_DEVICE;
218  dipdw.dwData = FALSE;
219 
220 #ifdef DEBUG
221  printf("vrpn_DirectXFFJoystick::InitDirectJoystick(): disabling autocenter\n");
222 #endif
223  if( FAILED( hr = _Joystick->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ) ) ) {
224  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Can't disable autocenter, disabling forces\n");
225  _force_rate = 0;
226  } else {
227  // This application needs only one effect: Applying raw forces.
228  DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
229  LONG rglDirection[2] = { 0, 0 };
230  DICONSTANTFORCE cf = { 0 };
231 
232 /*
233  DIENVELOPE diEnvelope; // envelope
234  diEnvelope.dwSize = sizeof(DIENVELOPE);
235  diEnvelope.dwAttackLevel = 0;
236  diEnvelope.dwAttackTime = (DWORD)(0.005 * DI_SECONDS);
237  diEnvelope.dwFadeLevel = 0;
238  diEnvelope.dwFadeTime = (DWORD)(0.005 * DI_SECONDS);
239 */
240 
241  DIEFFECT eff;
242  ZeroMemory( &eff, sizeof(eff) );
243  eff.dwSize = sizeof(DIEFFECT);
244  eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
245 // eff.dwDuration = INFINITE;
246  eff.dwDuration = (DWORD)(0.02 * DI_SECONDS);
247  eff.dwSamplePeriod = 0;
248  eff.dwGain = DI_FFNOMINALMAX;
249  eff.dwTriggerButton = DIEB_NOTRIGGER;
250  eff.dwTriggerRepeatInterval = 0;
251  eff.cAxes = _numforceaxes;
252  eff.rgdwAxes = rgdwAxes;
253  eff.rglDirection = rglDirection;
254 // eff.lpEnvelope = &diEnvelope;
255  eff.lpEnvelope = 0;
256  eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
257  eff.lpvTypeSpecificParams = &cf;
258  eff.dwStartDelay = 0;
259 
260  // Create the prepared effect
261  if( FAILED( hr = _Joystick->CreateEffect( GUID_ConstantForce, &eff, &_ForceEffect, NULL ) ) ||
262  (_ForceEffect == NULL) ) {
263  fprintf(stderr,"vrpn_DirectXFFJoystick::InitDirectJoystick(): Can't create force effect, disabling forces\n");
264  _force_rate = 0;
265  }
266  }
267  }
268  }
269 
270  // Acquire the joystick
271  if( FAILED( hr = _Joystick->Acquire() ) ) {
272  char *reason;
273  switch (hr) {
274  case DIERR_INVALIDPARAM:
275  reason = "Invalid parameter";
276  break;
277  case DIERR_NOTINITIALIZED:
278  reason = "Not Initialized";
279  break;
280  case DIERR_OTHERAPPHASPRIO:
281  reason = "Another application has priority";
282  break;
283  default:
284  reason = "Unknown";
285  }
286  fprintf(stderr, "vrpn_DirectXFFJoystick::InitDirectJoystick(): Cannot acquire joystick because %s\n", reason);
287  _status = STATUS_BROKEN;
288  return hr;
289  }
290  return S_OK;
291 }
292 
293 //-----------------------------------------------------------------------------
294 // Desc: Called once for each enumerated joystick. If we find one, create a
295 // device interface on it so we can play with it, then tell that we
296 // don't want to hear about any more.
297 
298 BOOL CALLBACK vrpn_DirectXFFJoystick::EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
299  VOID* selfPtr )
300 {
301  vrpn_DirectXFFJoystick *me = (vrpn_DirectXFFJoystick*)(selfPtr);
302  HRESULT hr;
303 
304 #ifdef DEBUG
305  printf("vrpn_DirectXFFJoystick::EnumJoysticksCallback(): Found joystick\n");
306 #endif
307 
308  // Obtain an interface to the enumerated joystick.
309  hr = me->_DirectInput->CreateDevice( pdidInstance->guidInstance, &me->_Joystick, NULL );
310 
311  // If it failed, then we can't use this joystick. (Maybe the user unplugged
312  // it while we were in the middle of enumerating it.)
313  if( FAILED(hr) ) return DIENUM_CONTINUE;
314 
315  // Stop enumeration. Note: we're just taking the first joystick we get. You
316  // could store all the enumerated joysticks and let the user pick.
317  return DIENUM_STOP;
318 }
319 
320 //-----------------------------------------------------------------------------
321 // Desc: Callback function for enumerating objects (axes, buttons, POVs) on a
322 // joystick. This function records how many there are and scales axes
323 // min/max values.
324 //-----------------------------------------------------------------------------
325 BOOL CALLBACK vrpn_DirectXFFJoystick::EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
326  VOID* selfPtr )
327 {
328  vrpn_DirectXFFJoystick *me = (vrpn_DirectXFFJoystick*)(selfPtr);
329 
330 #ifdef DEBUG
331  printf("vrpn_DirectXFFJoystick::EnumObjectsCallback(): Found type %d object\n", pdidoi->dwType);
332 #endif
333  // For axes that are returned, set the DIPROP_RANGE property for the
334  // enumerated axis in order to scale min/max values to -1000 to 1000.
335  if (pdidoi->dwType & DIDFT_AXIS) {
336  DIPROPRANGE diprg;
337  diprg.diph.dwSize = sizeof(DIPROPRANGE);
338  diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
339  diprg.diph.dwHow = DIPH_BYID;
340  diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis
341  diprg.lMin = -1000;
342  diprg.lMax = +1000;
343 
344  // Set the range for the axis
345  if( FAILED( me->_Joystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) )
346  return DIENUM_STOP;
347  }
348 
349  // For each force-feedback actuator returned, add one to the count.
350  if (pdidoi->dwFlags & DIDOI_FFACTUATOR) {
351  me->_numforceaxes++;
352  }
353 
354  return DIENUM_CONTINUE;
355 }
356 
357 
358 void vrpn_DirectXFFJoystick::clear_values(void)
359 {
360  int i;
361 
362  for (i = 0; i < _numbuttons; i++) {
364  }
365  for (i = 0; i < _numchannels; i++) {
367  }
368 }
369 
370 // This function will send a report if any of the analog or button values
371 // have changed. This reads from the joystick _read_rate times per second, returns
372 // right away at other times.
373 // Returns 0 on success, -1 (and sets _status) on failure.
374 
375 int vrpn_DirectXFFJoystick::get_report(void)
376 {
377  HRESULT hr;
378 
379  // If it has been long enough, update the force sent to the user.
380  {
381  struct timeval now;
382  vrpn_gettimeofday(&now, NULL);
383  if (vrpn_TimevalDuration(now, _forcetime) >= 1000000.0 / _force_rate) {
384  send_normalized_force(_fX, _fY);
385  _forcetime = now;
386  }
387  }
388 
389  // If it is not time for the next read, just return
390  struct timeval reporttime;
391  vrpn_gettimeofday(&reporttime, NULL);
392  if (vrpn_TimevalDuration(reporttime, _timestamp) < 1000000.0 / _read_rate) {
393  return 0;
394  }
395 #ifdef VERBOSE
396  printf(" now: %ld:%ld, last %ld:%ld\n", reporttime.tv_sec, reporttime.tv_usec,
397  _timestamp.tv_sec, static_cast<long>(_timestamp.tv_usec));
398  printf(" DirectX joystick: Getting report\n");
399 #endif
400 
401  // Poll the joystick. If we can't poll it then try to reacquire
402  // until that times out.
403  hr = _Joystick->Poll();
404  if( FAILED(hr) ) {
405  // DInput is telling us that the input stream has been
406  // interrupted. We aren't tracking any state between polls, so
407  // we don't have any special reset that needs to be done. We
408  // just re-acquire and try again.
409  hr = _Joystick->Acquire();
410  if ( hr == DIERR_INPUTLOST ) {
411  struct timeval resettime;
412  vrpn_gettimeofday(&resettime, NULL);
413  while ( ( hr == DIERR_INPUTLOST) && (vrpn_TimevalDuration(resettime, reporttime) <= MAX_TIME_INTERVAL) ) {
414  vrpn_gettimeofday(&resettime, NULL);
415  hr = _Joystick->Acquire();
416  }
417  if (hr == DIERR_INPUTLOST) {
418  fprintf(stderr, "vrpn_DirectXFFJoystick::get_report::vrpn_DirectXFFJoystick::get_report(): Can't Acquire joystick\n");
419  _status = STATUS_BROKEN;
420  return -1;
421  }
422  reporttime = resettime;
423  }
424 
425  // hr may be DIERR_OTHERAPPHASPRIO or other errors. This
426  // may occur when the app is minimized or in the process of
427  // switching, so just try again later
428  fprintf(stderr, "Error other than INPUTLOST\n");
429  return 0;
430  }
431 
432  // Read the values from the joystick and put them into the internal structures.
433  // Map the analogs representing sliders and axes to the range (-1...1).
434  // Map the POVs to degrees by dividing by 100.
435  DIJOYSTATE2 js; // DInput joystick state
436  if( FAILED( hr = _Joystick->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) ) {
437  fprintf(stderr, "vrpn_DirectXFFJoystick::get_report(): Can't read joystick\n");
438  _status = STATUS_BROKEN;
439  return -1;
440  }
441  channel[0] = js.lX / 1000.0;
442  channel[1] = js.lY / 1000.0;
443  channel[2] = js.lZ / 1000.0;
444 
445  channel[3] = js.lRx / 1000.0;
446  channel[4] = js.lRy / 1000.0;
447  channel[5] = js.lRz / 1000.0;
448 
449  channel[6] = js.rglSlider[0] / 1000.0;
450  channel[7] = js.rglSlider[1] / 1000.0;
451 
452  channel[8] = (long)js.rgdwPOV[0] / 100.0;
453  channel[9] = (long)js.rgdwPOV[1] / 100.0;
454  channel[10] = (long)js.rgdwPOV[2] / 100.0;
455  channel[11] = (long)js.rgdwPOV[3] / 100.0;
456 
457  int i;
458  for (i = 0; i < min(128,vrpn_BUTTON_MAX_BUTTONS); i++) {
459  buttons[i] = ( (js.rgbButtons[i] & 0x80) != 0);
460  }
461 
462  // Send the new values out over the connection.
463  _timestamp = reporttime;
464  report();
465  return 0;
466 }
467 
468 void vrpn_DirectXFFJoystick::report_changes(vrpn_uint32 class_of_service)
469 {
470  vrpn_Analog::timestamp = _timestamp;
471  vrpn_Button::timestamp = _timestamp;
472 
473  vrpn_Analog::report_changes(class_of_service);
475 }
476 
477 void vrpn_DirectXFFJoystick::report(vrpn_uint32 class_of_service)
478 {
479  vrpn_Analog::timestamp = _timestamp;
480  vrpn_Button::timestamp = _timestamp;
481 
482  vrpn_Analog::report(class_of_service);
484 }
485 
486 // A force of 1 goes the the right in X and up in Y
487 void vrpn_DirectXFFJoystick::send_normalized_force(double fx, double fy)
488 {
489  // Make sure we have force capability. If not, then set our status to
490  // broken.
491  if ( (_force_rate <= 0) || (_ForceEffect == NULL) ) {
492  send_text_message("Asked to send force when no force enabled", _timestamp, vrpn_TEXT_ERROR);
493  return;
494  }
495 
496  // Set the forces to match a right-handed coordinate system
497  fx *= -1;
498 
499  // If the total force vector is more than unit length, scale down by that
500  // length.
501  double len = sqrt(fx*fx + fy*fy);
502  if (len > 1) {
503  fx /= len;
504  fy /= len;
505  }
506 
507  // This version of the driver averages the last three force commands
508  // before setting the force.
509 
510  double fx_avg = (fx + _fx_1 + _fx_2 )/3.0;
511  double fy_avg = (fy + _fy_1 + _fy_2 )/3.0;
512 
513  // Convert the force from (-1..1) into the maximum range for each axis and then send it to
514  // the device.
515 /* INT xForce = (INT)(fx * DI_FFNOMINALMAX); */
516 /* INT yForce = (INT)(fy * DI_FFNOMINALMAX); */
517 
518  INT xForce = (INT)(fx_avg * DI_FFNOMINALMAX);
519  INT yForce = (INT)(fy_avg * DI_FFNOMINALMAX);
520 
521  _fx_2 = _fx_1; _fy_2 = _fy_1;
522  _fx_1 = fx; _fy_1 = fy;
523 
524  LONG rglDirection[2]; // Direction for the force (does not carry magnitude)
525  DICONSTANTFORCE cf; // Magnitude of the force
526 
527  rglDirection[0] = xForce;
528  rglDirection[1] = yForce;
529  cf.lMagnitude = (DWORD)(sqrt( (double)xForce * (double)xForce +
530  (double)yForce * (double)yForce ));
531 
532 /*
533  DIENVELOPE diEnvelope; // envelope
534  diEnvelope.dwSize = sizeof(DIENVELOPE);
535  diEnvelope.dwAttackLevel = 0;
536  diEnvelope.dwAttackTime = (DWORD)(0.005 * DI_SECONDS);
537  diEnvelope.dwFadeLevel = 0;
538  diEnvelope.dwFadeTime = (DWORD)(0.005 * DI_SECONDS);
539 */
540 
541  DIEFFECT eff;
542  ZeroMemory( &eff, sizeof(eff) );
543  eff.dwSize = sizeof(DIEFFECT);
544  eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
545  eff.cAxes = _numforceaxes;
546  eff.rglDirection = rglDirection;
547  eff.lpEnvelope = 0;
548 // eff.lpEnvelope = &diEnvelope;
549  eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
550  eff.lpvTypeSpecificParams = &cf;
551  eff.dwStartDelay = 0;
552 
553  // Now set the new parameters and start the effect immediately.
554  if ( FAILED ( _ForceEffect->SetParameters( &eff, DIEP_DIRECTION |
555  DIEP_TYPESPECIFICPARAMS |
556  DIEP_START) ) ) {
557  send_text_message("Can't send force", _timestamp, vrpn_TEXT_ERROR);
558  return;
559  }
560 }
561 
562 
563 // This routine is called each time through the server's main loop. It will
564 // take a course of action depending on the current status of the joystick,
565 // either trying to reset it or trying to get a reading from it.
566 void vrpn_DirectXFFJoystick::mainloop()
567 {
568  // Call the generic server mainloop, since we are a server
569  server_mainloop();
570 
571  switch(_status) {
572  case STATUS_BROKEN:
573  {
574  struct timeval now;
575  vrpn_gettimeofday(&now, NULL);
576  if (vrpn_TimevalDuration(now, _last_report) > MAX_TIME_INTERVAL) {
577  send_text_message("Cannot talk to joystick", now, vrpn_TEXT_ERROR);
578  _last_report = now;
579  }
580  }
581  break;
582 
583  case STATUS_READING:
584  get_report();
585  break;
586 
587  default:
588  fprintf(stderr,"vrpn_DirectXFFJoystick: Unknown mode (internal error)\n");
589  break;
590  }
591 }
592 
593 /*XXX
594 // Set the force to match the X and Y components of the gradient of the plane.
595 int vrpn_DirectXFFJoystick::handle_plane_change_message(void *selfPtr,
596  vrpn_HANDLERPARAM p)
597 {
598  vrpn_DirectXFFJoystick *me = (vrpn_DirectXFFJoystick *)selfPtr;
599  vrpn_float32 abcd[4];
600  vrpn_float32 kspring, kdamp, fricdynamic, fricstatic;
601  vrpn_int32 plane_index, plane_recovery_cycles;
602 
603  // XXX We are ignoring the plane index and treating it as if there is
604  // only one plane.
605  decode_plane(p.buffer, p.payload_len, abcd,
606  &kspring, &kdamp, &fricdynamic, &fricstatic,
607  &plane_index, &plane_recovery_cycles);
608 
609  // If the plane normal is (0,0,0) this is a command to stop the surface
610  if ( (abcd[0] == 0) && (abcd[1] == 0) && (abcd[2] == 0) ) {
611  me->_fX = me->_fY = 0;
612  return 0;
613  }
614 
615  // Since the plane equation is (AX + BY + CZ + D = 0), the normalized A and B
616  // coefficients determine the amount of force in X and Y. We normalize by the
617  // plane's direction vector not counting D (we send the force no matter where
618  // we are with respect to the plane, since we are a 2D device in a 3D space).
619  double norm = sqrt(abcd[0]*abcd[0] + abcd[1]*abcd[1] + abcd[2]*abcd[2]);
620  me->_fX = abcd[0] / norm;
621  me->_fY = abcd[1] / norm;
622 
623  return 0;
624 }
625 XXX*/
626 
627 // Margaret Minsky's dissertation suggests using the slope of the plane,
628 // which is the equivalent of the step size in Z for a unit step in X and
629 // a unit step in Y. This turns out to be equivalent to A/C and B/C.
630 // Note that this can increase without bound, so we have to find some
631 // scaling factor and then clip if the step size in Z gets too large
632 // (clipping happens in the code that writes the value to the device
633 // when the length of the force vector exceeds 1).
634 int vrpn_DirectXFFJoystick::handle_plane_change_message(void *selfPtr,
636 {
637  vrpn_DirectXFFJoystick *me = (vrpn_DirectXFFJoystick *)selfPtr;
638  vrpn_float32 abcd[4];
639  vrpn_float32 kspring, kdamp, fricdynamic, fricstatic;
640  vrpn_int32 plane_index, plane_recovery_cycles;
641  double fscale = 0.25; // Maximum force at four times slope for 45 degrees
642 
643  // XXX We are ignoring the plane index and treating it as if there is
644  // only one plane.
645  decode_plane(p.buffer, p.payload_len, abcd,
646  &kspring, &kdamp, &fricdynamic, &fricstatic,
647  &plane_index, &plane_recovery_cycles);
648 
649  // If the plane normal is (0,0,0) this is a command to stop the surface
650  if ( (abcd[0] == 0) && (abcd[1] == 0) && (abcd[2] == 0) ) {
651  me->_fX = me->_fY = 0;
652  return 0;
653  }
654 
655  // If C is zero, then we set the forces to unit length in the direction of
656  // the vector (A, B). This preserves the direction of the force and makes it
657  // be the maximum force (would be infinite if we divided by C).
658  if (abcd[2] == 0) {
659  double len = sqrt(abcd[0]*abcd[0] + abcd[1]*abcd[1]);
660  me->_fX = abcd[0] / len;
661  me->_fY = abcd[1] / len;
662 
663  // Since the plane equation is (AX + BY + CZ + D = 0), A/C and B/C
664  // determine the amount of force in X and Y. We do not count D
665  // (we send the force no matter where we are with respect to the plane,
666  // since we are a 2D device in a 3D space).
667  } else {
668 
669  me->_fX = fscale * abcd[0] / abcd[2];
670  me->_fY = fscale * abcd[1] / abcd[2];
671  }
672 
673  return 0;
674 }
675 
676 int vrpn_DirectXFFJoystick::handle_forcefield_change_message(void *selfPtr,
678 {
679  vrpn_DirectXFFJoystick *me = (vrpn_DirectXFFJoystick *)selfPtr;
680 
681  vrpn_float32 center[3];
682  vrpn_float32 force[3];
683  vrpn_float32 jacobian[3][3];
684  vrpn_float32 radius;
685 
686  decode_forcefield(p.buffer, p.payload_len, center, force, jacobian, &radius);
687 
688  // XXX We are ignoring the center, jacobian, and radius for now. Just use the force.
689  me->_fX = force[0];
690  me->_fY = force[1];
691 
692  return 0;
693 }
694 
695 // Zero the force sent to the device when the last connection is dropped.
696 int vrpn_DirectXFFJoystick::handle_last_connection_dropped(void *selfPtr, vrpn_HANDLERPARAM)
697 {
698  vrpn_DirectXFFJoystick *me = (vrpn_DirectXFFJoystick*)selfPtr;
699  if (me->_force_rate > 0) {
700  me->_fX = me->_fY = 0;
701  me->send_normalized_force(0,0);
702  }
703  return 0;
704 }
705 
706 
707 #endif
vrpn_BaseClassUnique::register_autodeleted_handler
int register_autodeleted_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Registers a handler with the connection, and remembers to delete at destruction.
Definition: vrpn_BaseClass.C:503
vrpn_Button::report_changes
virtual void report_changes(void)
Definition: vrpn_Button.C:422
min
#define min(x, y)
Definition: vrpn_WiiMote.C:47
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_MAX_BUTTONS
const int vrpn_BUTTON_MAX_BUTTONS
Definition: vrpn_Button.h:12
vrpn_Analog::channel
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
DIRECTINPUT_VERSION
#define DIRECTINPUT_VERSION
Definition: vrpn_Configure.h:501
vrpn_dropped_last_connection
const char * vrpn_dropped_last_connection
Definition: vrpn_Connection.C:187
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
vrpn_Analog
Definition: vrpn_Analog.h:28
vrpn_Analog::timestamp
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_CHANNEL_MAX
#define vrpn_CHANNEL_MAX
Definition: vrpn_Analog.h:16
vrpn_HANDLERPARAM::payload_len
vrpn_int32 payload_len
Definition: vrpn_Connection.h:48
vrpn_Button::num_buttons
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
vrpn_Button::buttons
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
vrpn_BaseClassUnique::d_connection
vrpn_Connection * d_connection
Connection that this object talks to.
Definition: vrpn_BaseClass.h:224
vrpn_HANDLERPARAM::buffer
const char * buffer
Definition: vrpn_Connection.h:49
vrpn_Connection::register_message_type
virtual vrpn_int32 register_message_type(const char *name)
Definition: vrpn_Connection.C:5074
vrpn_TEXT_ERROR
@ vrpn_TEXT_ERROR
Definition: vrpn_BaseClass.h:103
vrpn_HANDLERPARAM
This structure is what is passed to a vrpn_Connection message callback.
Definition: vrpn_Connection.h:44
vrpn_BaseClassUnique::d_sender_id
vrpn_int32 d_sender_id
Sender ID registered with the connection.
Definition: vrpn_BaseClass.h:228
vrpn_Button::timestamp
struct timeval timestamp
Definition: vrpn_Button.h:48
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
MAX_TIME_INTERVAL
#define MAX_TIME_INTERVAL
Definition: vrpn_3DMicroscribe.C:29
vrpn_Analog::num_channel
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
vrpn_Button::lastbuttons
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
vrpn_Analog::last
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_DirectXFFJoystick.h
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
STATUS_READING
#define STATUS_READING
Definition: vrpn_3DMicroscribe.C:28
vrpn_ForceDeviceServer
Definition: vrpn_ForceDeviceServer.h:27
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