vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
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
5using 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.
16const int STATUS_BROKEN = -1; // Broken joystick
17const 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.
25vrpn_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),
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.
93 register_autodeleted_handler(d_connection->register_message_type(vrpn_dropped_last_connection), handle_last_connection_dropped, this);
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
115vrpn_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
139HRESULT 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
298BOOL 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//-----------------------------------------------------------------------------
325BOOL 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
358void 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
375int 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
468void 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
477void 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
487void 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.
566void 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.
595int 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}
625XXX*/
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).
634int 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
676int 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.
696int 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_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
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
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_int32 d_sender_id
Sender ID registered with the connection.
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:66
vrpn_int32 num_buttons
Definition: vrpn_Button.h:48
struct timeval timestamp
Definition: vrpn_Button.h:49
virtual void report_changes(void)
Definition: vrpn_Button.C:423
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.
This structure is what is passed to a vrpn_Connection message callback.
const char * buffer
vrpn_int32 payload_len
#define MAX_TIME_INTERVAL
#define STATUS_READING
#define vrpn_CHANNEL_MAX
Definition: vrpn_Analog.h:16
@ vrpn_TEXT_ERROR
const int vrpn_BUTTON_MAX_BUTTONS
Definition: vrpn_Button.h:13
#define DIRECTINPUT_VERSION
const char * vrpn_dropped_last_connection
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
Definition: vrpn_Shared.C:138
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:99
#define min(x, y)
Definition: vrpn_WiiMote.C:47