Changeset 5695 for code/trunk/src/ois/linux/LinuxForceFeedback.cpp
- Timestamp:
- Aug 30, 2009, 2:22:00 AM (16 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
/code/branches/resource2 (added) merged: 3373-3374,5594,5597,5610-5611,5614,5624,5641,5644-5646,5650-5664,5667-5672,5682-5684,5688-5691,5694
- Property svn:mergeinfo changed
-
code/trunk/src/ois/linux/LinuxForceFeedback.cpp
r1505 r5695 24 24 #include "OISException.h" 25 25 26 #include <cstdlib> 27 #include <errno.h> 28 #include <memory.h> 29 26 30 using namespace OIS; 27 31 28 //--------------------------------------------------------------// 29 LinuxForceFeedback::LinuxForceFeedback() 30 { 31 } 32 // 0 = No trace; 1 = Important traces; 2 = Debug traces 33 #define OIS_LINUX_JOYFF_DEBUG 1 34 35 #ifdef OIS_LINUX_JOYFF_DEBUG 36 # include <iostream> 37 using namespace std; 38 #endif 39 40 //--------------------------------------------------------------// 41 LinuxForceFeedback::LinuxForceFeedback(int deviceID) : 42 ForceFeedback(), mJoyStick(deviceID) 43 { 44 } 45 32 46 //--------------------------------------------------------------// 33 47 LinuxForceFeedback::~LinuxForceFeedback() 34 48 { 35 } 36 37 //--------------------------------------------------------------// 38 void LinuxForceFeedback::setMasterGain(float) 39 { 40 } 41 42 //--------------------------------------------------------------// 43 void LinuxForceFeedback::setAutoCenterMode(bool) 44 { 45 } 46 47 //--------------------------------------------------------------// 48 void LinuxForceFeedback::upload( const Effect* /*effect*/ ) 49 { 50 } 51 52 //--------------------------------------------------------------// 53 void LinuxForceFeedback::modify( const Effect* /*effect*/ ) 54 { 55 } 56 57 //--------------------------------------------------------------// 58 void LinuxForceFeedback::remove( const Effect* /*effect*/ ) 59 { 60 } 61 49 // Unload all effects. 50 for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i ) 51 { 52 struct ff_effect *linEffect = i->second; 53 if( linEffect ) 54 _unload(linEffect->id); 55 } 56 57 mEffectList.clear(); 58 } 59 60 //--------------------------------------------------------------// 61 unsigned short LinuxForceFeedback::getFFMemoryLoad() 62 { 63 int nEffects = -1; 64 if (ioctl(mJoyStick, EVIOCGEFFECTS, &nEffects) == -1) 65 OIS_EXCEPT(E_General, "Unknown error reading max number of uploaded effects."); 66 #if (OIS_LINUX_JOYFF_DEBUG > 1) 67 cout << "LinuxForceFeedback("<< mJoyStick 68 << ") : Read device max number of uploaded effects : " << nEffects << endl; 69 #endif 70 71 return (unsigned short int)(nEffects > 0 ? 100.0*mEffectList.size()/nEffects : 100); 72 } 73 74 //--------------------------------------------------------------// 75 void LinuxForceFeedback::setMasterGain(float value) 76 { 77 if (!mSetGainSupport) 78 { 79 #if (OIS_LINUX_JOYFF_DEBUG > 0) 80 cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting master gain " 81 << "is not supported by the device" << endl; 82 #endif 83 return; 84 } 85 86 struct input_event event; 87 88 memset(&event, 0, sizeof(event)); 89 event.type = EV_FF; 90 event.code = FF_GAIN; 91 if (value < 0.0) 92 value = 0.0; 93 else if (value > 1.0) 94 value = 1.0; 95 event.value = (__s32)(value * 0xFFFFUL); 96 97 #if (OIS_LINUX_JOYFF_DEBUG > 0) 98 cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting master gain to " 99 << value << " => " << event.value << endl; 100 #endif 101 102 if (write(mJoyStick, &event, sizeof(event)) != sizeof(event)) { 103 OIS_EXCEPT(E_General, "Unknown error changing master gain."); 104 } 105 } 106 107 //--------------------------------------------------------------// 108 void LinuxForceFeedback::setAutoCenterMode(bool enabled) 109 { 110 if (!mSetAutoCenterSupport) 111 { 112 #if (OIS_LINUX_JOYFF_DEBUG > 0) 113 cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting auto-center mode " 114 << "is not supported by the device" << endl; 115 #endif 116 return; 117 } 118 119 struct input_event event; 120 121 memset(&event, 0, sizeof(event)); 122 event.type = EV_FF; 123 event.code = FF_AUTOCENTER; 124 event.value = (__s32)(enabled*0xFFFFFFFFUL); 125 126 #if (OIS_LINUX_JOYFF_DEBUG > 0) 127 cout << "LinuxForceFeedback("<< mJoyStick << ") : Toggling auto-center to " 128 << enabled << " => 0x" << hex << event.value << dec << endl; 129 #endif 130 131 if (write(mJoyStick, &event, sizeof(event)) != sizeof(event)) { 132 OIS_EXCEPT(E_General, "Unknown error toggling auto-center."); 133 } 134 } 135 136 //--------------------------------------------------------------// 137 void LinuxForceFeedback::upload( const Effect* effect ) 138 { 139 switch( effect->force ) 140 { 141 case OIS::Effect::ConstantForce: 142 _updateConstantEffect(effect); 143 break; 144 case OIS::Effect::ConditionalForce: 145 _updateConditionalEffect(effect); 146 break; 147 case OIS::Effect::PeriodicForce: 148 _updatePeriodicEffect(effect); 149 break; 150 case OIS::Effect::RampForce: 151 _updateRampEffect(effect); 152 break; 153 case OIS::Effect::CustomForce: 154 //_updateCustomEffect(effect); 155 //break; 156 default: 157 OIS_EXCEPT(E_NotImplemented, "Requested force not implemented yet, sorry!"); 158 break; 159 } 160 } 161 162 //--------------------------------------------------------------// 163 void LinuxForceFeedback::modify( const Effect* effect ) 164 { 165 upload(effect); 166 } 167 168 //--------------------------------------------------------------// 169 void LinuxForceFeedback::remove( const Effect* effect ) 170 { 171 //Get the effect - if it exists 172 EffectList::iterator i = mEffectList.find(effect->_handle); 173 if( i != mEffectList.end() ) 174 { 175 struct ff_effect *linEffect = i->second; 176 if( linEffect ) 177 { 178 _stop(effect->_handle); 179 180 _unload(effect->_handle); 181 182 free(linEffect); 183 184 mEffectList.erase(i); 185 } 186 else 187 mEffectList.erase(i); 188 } 189 } 190 191 //--------------------------------------------------------------// 192 // To Signed16/Unsigned15 safe conversions 193 #define MaxUnsigned15Value 0x7FFF 194 #define toUnsigned15(value) \ 195 (__u16)((value) < 0 ? 0 : ((value) > MaxUnsigned15Value ? MaxUnsigned15Value : (value))) 196 197 #define MaxSigned16Value 0x7FFF 198 #define MinSigned16Value -0x7FFF 199 #define toSigned16(value) \ 200 (__s16)((value) < MinSigned16Value ? MinSigned16Value : ((value) > MaxSigned16Value ? MaxSigned16Value : (value))) 201 202 // OIS to Linux duration 203 #define LinuxInfiniteDuration 0xFFFF 204 #define OISDurationUnitMS 1000 // OIS duration unit (microseconds), expressed in milliseconds (theLinux duration unit) 205 206 // linux/input.h : All duration values are expressed in ms. Values above 32767 ms (0x7fff) 207 // should not be used and have unspecified results. 208 #define LinuxDuration(oisDuration) ((oisDuration) == Effect::OIS_INFINITE ? LinuxInfiniteDuration \ 209 : toUnsigned15((oisDuration)/OISDurationUnitMS)) 210 211 212 // OIS to Linux levels 213 #define OISMaxLevel 10000 214 #define LinuxMaxLevel 0x7FFF 215 216 // linux/input.h : Valid range for the attack and fade levels is 0x0000 - 0x7fff 217 #define LinuxPositiveLevel(oisLevel) toUnsigned15(LinuxMaxLevel*(long)(oisLevel)/OISMaxLevel) 218 219 #define LinuxSignedLevel(oisLevel) toSigned16(LinuxMaxLevel*(long)(oisLevel)/OISMaxLevel) 220 221 222 //--------------------------------------------------------------// 223 void LinuxForceFeedback::_setCommonProperties(struct ff_effect *event, 224 struct ff_envelope *ffenvelope, 225 const Effect* effect, const Envelope *envelope ) 226 { 227 memset(event, 0, sizeof(struct ff_effect)); 228 229 if (envelope && ffenvelope && envelope->isUsed()) { 230 ffenvelope->attack_length = LinuxDuration(envelope->attackLength); 231 ffenvelope->attack_level = LinuxPositiveLevel(envelope->attackLevel); 232 ffenvelope->fade_length = LinuxDuration(envelope->fadeLength); 233 ffenvelope->fade_level = LinuxPositiveLevel(envelope->fadeLevel); 234 } 235 236 #if (OIS_LINUX_JOYFF_DEBUG > 1) 237 cout << endl; 238 if (envelope && ffenvelope) 239 { 240 cout << " Enveloppe :" << endl 241 << " AttackLen : " << envelope->attackLength 242 << " => " << ffenvelope->attack_length << endl 243 << " AttackLvl : " << envelope->attackLevel 244 << " => " << ffenvelope->attack_level << endl 245 << " FadeLen : " << envelope->fadeLength 246 << " => " << ffenvelope->fade_length << endl 247 << " FadeLvl : " << envelope->fadeLevel 248 << " => " << ffenvelope->fade_level << endl; 249 } 250 #endif 251 252 event->direction = (__u16)(1 + (effect->direction*45.0+135.0)*0xFFFFUL/360.0); 253 254 #if (OIS_LINUX_JOYFF_DEBUG > 1) 255 cout << " Direction : " << Effect::getDirectionName(effect->direction) 256 << " => 0x" << hex << event->direction << dec << endl; 257 #endif 258 259 // TODO trigger_button 0 vs. -1 260 event->trigger.button = effect->trigger_button; // < 0 ? 0 : effect->trigger_button; 261 event->trigger.interval = LinuxDuration(effect->trigger_interval); 262 263 #if (OIS_LINUX_JOYFF_DEBUG > 1) 264 cout << " Trigger :" << endl 265 << " Button : " << effect->trigger_button 266 << " => " << event->trigger.button << endl 267 << " Interval : " << effect->trigger_interval 268 << " => " << event->trigger.interval << endl; 269 #endif 270 271 event->replay.length = LinuxDuration(effect->replay_length); 272 event->replay.delay = LinuxDuration(effect->replay_delay); 273 274 #if (OIS_LINUX_JOYFF_DEBUG > 1) 275 cout << " Replay :" << endl 276 << " Length : " << effect->replay_length 277 << " => " << event->replay.length << endl 278 << " Delay : " << effect->replay_delay 279 << " => " << event->replay.delay << endl; 280 #endif 281 } 282 283 //--------------------------------------------------------------// 284 void LinuxForceFeedback::_updateConstantEffect( const Effect* eff ) 285 { 286 struct ff_effect event; 287 288 ConstantEffect *effect = static_cast<ConstantEffect*>(eff->getForceEffect()); 289 290 _setCommonProperties(&event, &event.u.constant.envelope, eff, &effect->envelope); 291 292 event.type = FF_CONSTANT; 293 event.id = -1; 294 295 event.u.constant.level = LinuxSignedLevel(effect->level); 296 297 #if (OIS_LINUX_JOYFF_DEBUG > 1) 298 cout << " Level : " << effect->level 299 << " => " << event.u.constant.level << endl; 300 #endif 301 302 _upload(&event, eff); 303 } 304 305 //--------------------------------------------------------------// 306 void LinuxForceFeedback::_updateRampEffect( const Effect* eff ) 307 { 308 struct ff_effect event; 309 310 RampEffect *effect = static_cast<RampEffect*>(eff->getForceEffect()); 311 312 _setCommonProperties(&event, &event.u.constant.envelope, eff, &effect->envelope); 313 314 event.type = FF_RAMP; 315 event.id = -1; 316 317 event.u.ramp.start_level = LinuxSignedLevel(effect->startLevel); 318 event.u.ramp.end_level = LinuxSignedLevel(effect->endLevel); 319 320 #if (OIS_LINUX_JOYFF_DEBUG > 1) 321 cout << " StartLevel : " << effect->startLevel 322 << " => " << event.u.ramp.start_level << endl 323 << " EndLevel : " << effect->endLevel 324 << " => " << event.u.ramp.end_level << endl; 325 #endif 326 327 _upload(&event, eff); 328 } 329 330 //--------------------------------------------------------------// 331 void LinuxForceFeedback::_updatePeriodicEffect( const Effect* eff ) 332 { 333 struct ff_effect event; 334 335 PeriodicEffect *effect = static_cast<PeriodicEffect*>(eff->getForceEffect()); 336 337 _setCommonProperties(&event, &event.u.periodic.envelope, eff, &effect->envelope); 338 339 event.type = FF_PERIODIC; 340 event.id = -1; 341 342 switch( eff->type ) 343 { 344 case OIS::Effect::Square: 345 event.u.periodic.waveform = FF_SQUARE; 346 break; 347 case OIS::Effect::Triangle: 348 event.u.periodic.waveform = FF_TRIANGLE; 349 break; 350 case OIS::Effect::Sine: 351 event.u.periodic.waveform = FF_SINE; 352 break; 353 case OIS::Effect::SawToothUp: 354 event.u.periodic.waveform = FF_SAW_UP; 355 break; 356 case OIS::Effect::SawToothDown: 357 event.u.periodic.waveform = FF_SAW_DOWN; 358 break; 359 // Note: No support for Custom periodic force effect for the moment 360 //case OIS::Effect::Custom: 361 //event.u.periodic.waveform = FF_CUSTOM; 362 //break; 363 default: 364 OIS_EXCEPT(E_General, "No such available effect for Periodic force!"); 365 break; 366 } 367 368 event.u.periodic.period = LinuxDuration(effect->period); 369 event.u.periodic.magnitude = LinuxPositiveLevel(effect->magnitude); 370 event.u.periodic.offset = LinuxPositiveLevel(effect->offset); 371 event.u.periodic.phase = (__u16)(effect->phase*event.u.periodic.period/36000.0); // ????? 372 373 // Note: No support for Custom periodic force effect for the moment 374 event.u.periodic.custom_len = 0; 375 event.u.periodic.custom_data = 0; 376 377 #if (OIS_LINUX_JOYFF_DEBUG > 1) 378 cout << " Magnitude : " << effect->magnitude 379 << " => " << event.u.periodic.magnitude << endl 380 << " Period : " << effect->period 381 << " => " << event.u.periodic.period << endl 382 << " Offset : " << effect->offset 383 << " => " << event.u.periodic.offset << endl 384 << " Phase : " << effect->phase 385 << " => " << event.u.periodic.phase << endl; 386 #endif 387 388 _upload(&event, eff); 389 } 390 391 //--------------------------------------------------------------// 392 void LinuxForceFeedback::_updateConditionalEffect( const Effect* eff ) 393 { 394 struct ff_effect event; 395 396 ConditionalEffect *effect = static_cast<ConditionalEffect*>(eff->getForceEffect()); 397 398 _setCommonProperties(&event, NULL, eff, NULL); 399 400 switch( eff->type ) 401 { 402 case OIS::Effect::Friction: 403 event.type = FF_FRICTION; 404 break; 405 case OIS::Effect::Damper: 406 event.type = FF_DAMPER; 407 break; 408 case OIS::Effect::Inertia: 409 event.type = FF_INERTIA; 410 break; 411 case OIS::Effect::Spring: 412 event.type = FF_SPRING; 413 break; 414 default: 415 OIS_EXCEPT(E_General, "No such available effect for Conditional force!"); 416 break; 417 } 418 419 event.id = -1; 420 421 event.u.condition[0].right_saturation = LinuxSignedLevel(effect->rightSaturation); 422 event.u.condition[0].left_saturation = LinuxSignedLevel(effect->leftSaturation); 423 event.u.condition[0].right_coeff = LinuxSignedLevel(effect->rightCoeff); 424 event.u.condition[0].left_coeff = LinuxSignedLevel(effect->leftCoeff); 425 event.u.condition[0].deadband = LinuxPositiveLevel(effect->deadband);// Unit ?? 426 event.u.condition[0].center = LinuxSignedLevel(effect->center); // Unit ?? TODO ? 427 428 // TODO support for second condition 429 event.u.condition[1] = event.u.condition[0]; 430 431 #if (OIS_LINUX_JOYFF_DEBUG > 1) 432 cout << " Condition[0] : " << endl 433 << " RightSaturation : " << effect->rightSaturation 434 << " => " << event.u.condition[0].right_saturation << endl 435 << " LeftSaturation : " << effect->leftSaturation 436 << " => " << event.u.condition[0]. left_saturation << endl 437 << " RightCoefficient : " << effect->rightCoeff 438 << " => " << event.u.condition[0].right_coeff << endl 439 << " LeftCoefficient : " << effect->leftCoeff 440 << " => " << event.u.condition[0].left_coeff << endl 441 << " DeadBand : " << effect->deadband 442 << " => " << event.u.condition[0].deadband << endl 443 << " Center : " << effect->center 444 << " => " << event.u.condition[0].center << endl; 445 cout << " Condition[1] : Not implemented" << endl; 446 #endif 447 _upload(&event, eff); 448 } 449 450 //--------------------------------------------------------------// 451 void LinuxForceFeedback::_upload( struct ff_effect* ffeffect, const Effect* effect) 452 { 453 struct ff_effect *linEffect = 0; 454 455 //Get the effect - if it exists 456 EffectList::iterator i = mEffectList.find(effect->_handle); 457 //It has been created already 458 if( i != mEffectList.end() ) 459 linEffect = i->second; 460 461 if( linEffect == 0 ) 462 { 463 #if (OIS_LINUX_JOYFF_DEBUG > 1) 464 cout << endl << "LinuxForceFeedback("<< mJoyStick << ") : Adding new effect : " 465 << Effect::getEffectTypeName(effect->type) << endl; 466 #endif 467 468 //This effect has not yet been created, so create it in the device 469 if (ioctl(mJoyStick, EVIOCSFF, ffeffect) == -1) { 470 // TODO device full check 471 // OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!"); 472 OIS_EXCEPT(E_General, "Unknown error creating effect (may be the device is full)->.."); 473 } 474 475 // Save returned effect handle 476 effect->_handle = ffeffect->id; 477 478 // Save a copy of the uploaded effect for later simple modifications 479 linEffect = (struct ff_effect *)calloc(1, sizeof(struct ff_effect)); 480 memcpy(linEffect, ffeffect, sizeof(struct ff_effect)); 481 482 mEffectList[effect->_handle] = linEffect; 483 484 // Start playing the effect. 485 _start(effect->_handle); 486 } 487 else 488 { 489 #if (OIS_LINUX_JOYFF_DEBUG > 1) 490 cout << endl << "LinuxForceFeedback("<< mJoyStick << ") : Replacing effect : " 491 << Effect::getEffectTypeName(effect->type) << endl; 492 #endif 493 494 // Keep same id/handle, as this is just an update in the device. 495 ffeffect->id = effect->_handle; 496 497 // Update effect in the device. 498 if (ioctl(mJoyStick, EVIOCSFF, ffeffect) == -1) { 499 OIS_EXCEPT(E_General, "Unknown error updating an effect->.."); 500 } 501 502 // Update local linEffect for next time. 503 memcpy(linEffect, ffeffect, sizeof(struct ff_effect)); 504 } 505 506 #if (OIS_LINUX_JOYFF_DEBUG > 1) 507 cout << "LinuxForceFeedback("<< mJoyStick 508 << ") : Effect handle : " << effect->_handle << endl; 509 #endif 510 } 511 512 //--------------------------------------------------------------// 513 void LinuxForceFeedback::_stop( int handle) { 514 struct input_event stop; 515 516 stop.type = EV_FF; 517 stop.code = handle; 518 stop.value = 0; 519 520 #if (OIS_LINUX_JOYFF_DEBUG > 1) 521 cout << endl << "LinuxForceFeedback("<< mJoyStick 522 << ") : Stopping effect with handle " << handle << endl; 523 #endif 524 525 if (write(mJoyStick, &stop, sizeof(stop)) != sizeof(stop)) { 526 OIS_EXCEPT(E_General, "Unknown error stopping effect->.."); 527 } 528 } 529 530 //--------------------------------------------------------------// 531 void LinuxForceFeedback::_start( int handle) { 532 struct input_event play; 533 534 play.type = EV_FF; 535 play.code = handle; 536 play.value = 1; // Play once. 537 538 #if (OIS_LINUX_JOYFF_DEBUG > 1) 539 cout << endl << "LinuxForceFeedback("<< mJoyStick 540 << ") : Starting effect with handle " << handle << endl; 541 #endif 542 543 if (write(mJoyStick, &play, sizeof(play)) != sizeof(play)) { 544 OIS_EXCEPT(E_General, "Unknown error playing effect->.."); 545 } 546 } 547 548 //--------------------------------------------------------------// 549 void LinuxForceFeedback::_unload( int handle) 550 { 551 #if (OIS_LINUX_JOYFF_DEBUG > 1) 552 cout << endl << "LinuxForceFeedback("<< mJoyStick 553 << ") : Removing effect with handle " << handle << endl; 554 #endif 555 556 if (ioctl(mJoyStick, EVIOCRMFF, handle) == -1) { 557 OIS_EXCEPT(E_General, "Unknown error removing effect->.."); 558 } 559 }
Note: See TracChangeset
for help on using the changeset viewer.