/src/ois/src/linux/LinuxForceFeedback.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 559 lines · 394 code · 96 blank · 69 comment · 40 complexity · 077dec65f3adf49c4034a80dd9ad4197 MD5 · raw file

  1. /*
  2. The zlib/libpng License
  3. Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
  4. This software is provided 'as-is', without any express or implied warranty. In no event will
  5. the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose, including commercial
  7. applications, and to alter it and redistribute it freely, subject to the following
  8. restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not claim that
  10. you wrote the original software. If you use this software in a product,
  11. an acknowledgment in the product documentation would be appreciated but is
  12. not required.
  13. 2. Altered source versions must be plainly marked as such, and must not be
  14. misrepresented as being the original software.
  15. 3. This notice may not be removed or altered from any source distribution.
  16. */
  17. #include "linux/LinuxForceFeedback.h"
  18. #include "OISException.h"
  19. #include <cstdlib>
  20. #include <errno.h>
  21. #include <memory.h>
  22. using namespace OIS;
  23. // 0 = No trace; 1 = Important traces; 2 = Debug traces
  24. #define OIS_LINUX_JOYFF_DEBUG 1
  25. #ifdef OIS_LINUX_JOYFF_DEBUG
  26. # include <iostream>
  27. using namespace std;
  28. #endif
  29. //--------------------------------------------------------------//
  30. LinuxForceFeedback::LinuxForceFeedback(int deviceID) :
  31. ForceFeedback(), mJoyStick(deviceID)
  32. {
  33. }
  34. //--------------------------------------------------------------//
  35. LinuxForceFeedback::~LinuxForceFeedback()
  36. {
  37. // Unload all effects.
  38. for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i )
  39. {
  40. struct ff_effect *linEffect = i->second;
  41. if( linEffect )
  42. _unload(linEffect->id);
  43. }
  44. mEffectList.clear();
  45. }
  46. //--------------------------------------------------------------//
  47. unsigned short LinuxForceFeedback::getFFMemoryLoad()
  48. {
  49. int nEffects = -1;
  50. if (ioctl(mJoyStick, EVIOCGEFFECTS, &nEffects) == -1)
  51. OIS_EXCEPT(E_General, "Unknown error reading max number of uploaded effects.");
  52. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  53. cout << "LinuxForceFeedback("<< mJoyStick
  54. << ") : Read device max number of uploaded effects : " << nEffects << endl;
  55. #endif
  56. return (unsigned short int)(nEffects > 0 ? 100.0*mEffectList.size()/nEffects : 100);
  57. }
  58. //--------------------------------------------------------------//
  59. void LinuxForceFeedback::setMasterGain(float value)
  60. {
  61. if (!mSetGainSupport)
  62. {
  63. #if (OIS_LINUX_JOYFF_DEBUG > 0)
  64. cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting master gain "
  65. << "is not supported by the device" << endl;
  66. #endif
  67. return;
  68. }
  69. struct input_event event;
  70. memset(&event, 0, sizeof(event));
  71. event.type = EV_FF;
  72. event.code = FF_GAIN;
  73. if (value < 0.0)
  74. value = 0.0;
  75. else if (value > 1.0)
  76. value = 1.0;
  77. event.value = (__s32)(value * 0xFFFFUL);
  78. #if (OIS_LINUX_JOYFF_DEBUG > 0)
  79. cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting master gain to "
  80. << value << " => " << event.value << endl;
  81. #endif
  82. if (write(mJoyStick, &event, sizeof(event)) != sizeof(event)) {
  83. OIS_EXCEPT(E_General, "Unknown error changing master gain.");
  84. }
  85. }
  86. //--------------------------------------------------------------//
  87. void LinuxForceFeedback::setAutoCenterMode(bool enabled)
  88. {
  89. if (!mSetAutoCenterSupport)
  90. {
  91. #if (OIS_LINUX_JOYFF_DEBUG > 0)
  92. cout << "LinuxForceFeedback("<< mJoyStick << ") : Setting auto-center mode "
  93. << "is not supported by the device" << endl;
  94. #endif
  95. return;
  96. }
  97. struct input_event event;
  98. memset(&event, 0, sizeof(event));
  99. event.type = EV_FF;
  100. event.code = FF_AUTOCENTER;
  101. event.value = (__s32)(enabled*0xFFFFFFFFUL);
  102. #if (OIS_LINUX_JOYFF_DEBUG > 0)
  103. cout << "LinuxForceFeedback("<< mJoyStick << ") : Toggling auto-center to "
  104. << enabled << " => 0x" << hex << event.value << dec << endl;
  105. #endif
  106. if (write(mJoyStick, &event, sizeof(event)) != sizeof(event)) {
  107. OIS_EXCEPT(E_General, "Unknown error toggling auto-center.");
  108. }
  109. }
  110. //--------------------------------------------------------------//
  111. void LinuxForceFeedback::upload( const Effect* effect )
  112. {
  113. switch( effect->force )
  114. {
  115. case OIS::Effect::ConstantForce:
  116. _updateConstantEffect(effect);
  117. break;
  118. case OIS::Effect::ConditionalForce:
  119. _updateConditionalEffect(effect);
  120. break;
  121. case OIS::Effect::PeriodicForce:
  122. _updatePeriodicEffect(effect);
  123. break;
  124. case OIS::Effect::RampForce:
  125. _updateRampEffect(effect);
  126. break;
  127. case OIS::Effect::CustomForce:
  128. //_updateCustomEffect(effect);
  129. //break;
  130. default:
  131. OIS_EXCEPT(E_NotImplemented, "Requested force not implemented yet, sorry!");
  132. break;
  133. }
  134. }
  135. //--------------------------------------------------------------//
  136. void LinuxForceFeedback::modify( const Effect* effect )
  137. {
  138. upload(effect);
  139. }
  140. //--------------------------------------------------------------//
  141. void LinuxForceFeedback::remove( const Effect* effect )
  142. {
  143. //Get the effect - if it exists
  144. EffectList::iterator i = mEffectList.find(effect->_handle);
  145. if( i != mEffectList.end() )
  146. {
  147. struct ff_effect *linEffect = i->second;
  148. if( linEffect )
  149. {
  150. _stop(effect->_handle);
  151. _unload(effect->_handle);
  152. free(linEffect);
  153. mEffectList.erase(i);
  154. }
  155. else
  156. mEffectList.erase(i);
  157. }
  158. }
  159. //--------------------------------------------------------------//
  160. // To Signed16/Unsigned15 safe conversions
  161. #define MaxUnsigned15Value 0x7FFF
  162. #define toUnsigned15(value) \
  163. (__u16)((value) < 0 ? 0 : ((value) > MaxUnsigned15Value ? MaxUnsigned15Value : (value)))
  164. #define MaxSigned16Value 0x7FFF
  165. #define MinSigned16Value -0x7FFF
  166. #define toSigned16(value) \
  167. (__s16)((value) < MinSigned16Value ? MinSigned16Value : ((value) > MaxSigned16Value ? MaxSigned16Value : (value)))
  168. // OIS to Linux duration
  169. #define LinuxInfiniteDuration 0xFFFF
  170. #define OISDurationUnitMS 1000 // OIS duration unit (microseconds), expressed in milliseconds (theLinux duration unit)
  171. // linux/input.h : All duration values are expressed in ms. Values above 32767 ms (0x7fff)
  172. // should not be used and have unspecified results.
  173. #define LinuxDuration(oisDuration) ((oisDuration) == Effect::OIS_INFINITE ? LinuxInfiniteDuration \
  174. : toUnsigned15((oisDuration)/OISDurationUnitMS))
  175. // OIS to Linux levels
  176. #define OISMaxLevel 10000
  177. #define LinuxMaxLevel 0x7FFF
  178. // linux/input.h : Valid range for the attack and fade levels is 0x0000 - 0x7fff
  179. #define LinuxPositiveLevel(oisLevel) toUnsigned15(LinuxMaxLevel*(long)(oisLevel)/OISMaxLevel)
  180. #define LinuxSignedLevel(oisLevel) toSigned16(LinuxMaxLevel*(long)(oisLevel)/OISMaxLevel)
  181. //--------------------------------------------------------------//
  182. void LinuxForceFeedback::_setCommonProperties(struct ff_effect *event,
  183. struct ff_envelope *ffenvelope,
  184. const Effect* effect, const Envelope *envelope )
  185. {
  186. memset(event, 0, sizeof(struct ff_effect));
  187. if (envelope && ffenvelope && envelope->isUsed()) {
  188. ffenvelope->attack_length = LinuxDuration(envelope->attackLength);
  189. ffenvelope->attack_level = LinuxPositiveLevel(envelope->attackLevel);
  190. ffenvelope->fade_length = LinuxDuration(envelope->fadeLength);
  191. ffenvelope->fade_level = LinuxPositiveLevel(envelope->fadeLevel);
  192. }
  193. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  194. cout << endl;
  195. if (envelope && ffenvelope)
  196. {
  197. cout << " Enveloppe :" << endl
  198. << " AttackLen : " << envelope->attackLength
  199. << " => " << ffenvelope->attack_length << endl
  200. << " AttackLvl : " << envelope->attackLevel
  201. << " => " << ffenvelope->attack_level << endl
  202. << " FadeLen : " << envelope->fadeLength
  203. << " => " << ffenvelope->fade_length << endl
  204. << " FadeLvl : " << envelope->fadeLevel
  205. << " => " << ffenvelope->fade_level << endl;
  206. }
  207. #endif
  208. event->direction = (__u16)(1 + (effect->direction*45.0+135.0)*0xFFFFUL/360.0);
  209. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  210. cout << " Direction : " << Effect::getDirectionName(effect->direction)
  211. << " => 0x" << hex << event->direction << dec << endl;
  212. #endif
  213. // TODO trigger_button 0 vs. -1
  214. event->trigger.button = effect->trigger_button; // < 0 ? 0 : effect->trigger_button;
  215. event->trigger.interval = LinuxDuration(effect->trigger_interval);
  216. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  217. cout << " Trigger :" << endl
  218. << " Button : " << effect->trigger_button
  219. << " => " << event->trigger.button << endl
  220. << " Interval : " << effect->trigger_interval
  221. << " => " << event->trigger.interval << endl;
  222. #endif
  223. event->replay.length = LinuxDuration(effect->replay_length);
  224. event->replay.delay = LinuxDuration(effect->replay_delay);
  225. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  226. cout << " Replay :" << endl
  227. << " Length : " << effect->replay_length
  228. << " => " << event->replay.length << endl
  229. << " Delay : " << effect->replay_delay
  230. << " => " << event->replay.delay << endl;
  231. #endif
  232. }
  233. //--------------------------------------------------------------//
  234. void LinuxForceFeedback::_updateConstantEffect( const Effect* eff )
  235. {
  236. struct ff_effect event;
  237. ConstantEffect *effect = static_cast<ConstantEffect*>(eff->getForceEffect());
  238. _setCommonProperties(&event, &event.u.constant.envelope, eff, &effect->envelope);
  239. event.type = FF_CONSTANT;
  240. event.id = -1;
  241. event.u.constant.level = LinuxSignedLevel(effect->level);
  242. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  243. cout << " Level : " << effect->level
  244. << " => " << event.u.constant.level << endl;
  245. #endif
  246. _upload(&event, eff);
  247. }
  248. //--------------------------------------------------------------//
  249. void LinuxForceFeedback::_updateRampEffect( const Effect* eff )
  250. {
  251. struct ff_effect event;
  252. RampEffect *effect = static_cast<RampEffect*>(eff->getForceEffect());
  253. _setCommonProperties(&event, &event.u.constant.envelope, eff, &effect->envelope);
  254. event.type = FF_RAMP;
  255. event.id = -1;
  256. event.u.ramp.start_level = LinuxSignedLevel(effect->startLevel);
  257. event.u.ramp.end_level = LinuxSignedLevel(effect->endLevel);
  258. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  259. cout << " StartLevel : " << effect->startLevel
  260. << " => " << event.u.ramp.start_level << endl
  261. << " EndLevel : " << effect->endLevel
  262. << " => " << event.u.ramp.end_level << endl;
  263. #endif
  264. _upload(&event, eff);
  265. }
  266. //--------------------------------------------------------------//
  267. void LinuxForceFeedback::_updatePeriodicEffect( const Effect* eff )
  268. {
  269. struct ff_effect event;
  270. PeriodicEffect *effect = static_cast<PeriodicEffect*>(eff->getForceEffect());
  271. _setCommonProperties(&event, &event.u.periodic.envelope, eff, &effect->envelope);
  272. event.type = FF_PERIODIC;
  273. event.id = -1;
  274. switch( eff->type )
  275. {
  276. case OIS::Effect::Square:
  277. event.u.periodic.waveform = FF_SQUARE;
  278. break;
  279. case OIS::Effect::Triangle:
  280. event.u.periodic.waveform = FF_TRIANGLE;
  281. break;
  282. case OIS::Effect::Sine:
  283. event.u.periodic.waveform = FF_SINE;
  284. break;
  285. case OIS::Effect::SawToothUp:
  286. event.u.periodic.waveform = FF_SAW_UP;
  287. break;
  288. case OIS::Effect::SawToothDown:
  289. event.u.periodic.waveform = FF_SAW_DOWN;
  290. break;
  291. // Note: No support for Custom periodic force effect for the moment
  292. //case OIS::Effect::Custom:
  293. //event.u.periodic.waveform = FF_CUSTOM;
  294. //break;
  295. default:
  296. OIS_EXCEPT(E_General, "No such available effect for Periodic force!");
  297. break;
  298. }
  299. event.u.periodic.period = LinuxDuration(effect->period);
  300. event.u.periodic.magnitude = LinuxPositiveLevel(effect->magnitude);
  301. event.u.periodic.offset = LinuxPositiveLevel(effect->offset);
  302. event.u.periodic.phase = (__u16)(effect->phase*event.u.periodic.period/36000.0); // ?????
  303. // Note: No support for Custom periodic force effect for the moment
  304. event.u.periodic.custom_len = 0;
  305. event.u.periodic.custom_data = 0;
  306. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  307. cout << " Magnitude : " << effect->magnitude
  308. << " => " << event.u.periodic.magnitude << endl
  309. << " Period : " << effect->period
  310. << " => " << event.u.periodic.period << endl
  311. << " Offset : " << effect->offset
  312. << " => " << event.u.periodic.offset << endl
  313. << " Phase : " << effect->phase
  314. << " => " << event.u.periodic.phase << endl;
  315. #endif
  316. _upload(&event, eff);
  317. }
  318. //--------------------------------------------------------------//
  319. void LinuxForceFeedback::_updateConditionalEffect( const Effect* eff )
  320. {
  321. struct ff_effect event;
  322. ConditionalEffect *effect = static_cast<ConditionalEffect*>(eff->getForceEffect());
  323. _setCommonProperties(&event, NULL, eff, NULL);
  324. switch( eff->type )
  325. {
  326. case OIS::Effect::Friction:
  327. event.type = FF_FRICTION;
  328. break;
  329. case OIS::Effect::Damper:
  330. event.type = FF_DAMPER;
  331. break;
  332. case OIS::Effect::Inertia:
  333. event.type = FF_INERTIA;
  334. break;
  335. case OIS::Effect::Spring:
  336. event.type = FF_SPRING;
  337. break;
  338. default:
  339. OIS_EXCEPT(E_General, "No such available effect for Conditional force!");
  340. break;
  341. }
  342. event.id = -1;
  343. event.u.condition[0].right_saturation = LinuxSignedLevel(effect->rightSaturation);
  344. event.u.condition[0].left_saturation = LinuxSignedLevel(effect->leftSaturation);
  345. event.u.condition[0].right_coeff = LinuxSignedLevel(effect->rightCoeff);
  346. event.u.condition[0].left_coeff = LinuxSignedLevel(effect->leftCoeff);
  347. event.u.condition[0].deadband = LinuxPositiveLevel(effect->deadband);// Unit ??
  348. event.u.condition[0].center = LinuxSignedLevel(effect->center); // Unit ?? TODO ?
  349. // TODO support for second condition
  350. event.u.condition[1] = event.u.condition[0];
  351. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  352. cout << " Condition[0] : " << endl
  353. << " RightSaturation : " << effect->rightSaturation
  354. << " => " << event.u.condition[0].right_saturation << endl
  355. << " LeftSaturation : " << effect->leftSaturation
  356. << " => " << event.u.condition[0]. left_saturation << endl
  357. << " RightCoefficient : " << effect->rightCoeff
  358. << " => " << event.u.condition[0].right_coeff << endl
  359. << " LeftCoefficient : " << effect->leftCoeff
  360. << " => " << event.u.condition[0].left_coeff << endl
  361. << " DeadBand : " << effect->deadband
  362. << " => " << event.u.condition[0].deadband << endl
  363. << " Center : " << effect->center
  364. << " => " << event.u.condition[0].center << endl;
  365. cout << " Condition[1] : Not implemented" << endl;
  366. #endif
  367. _upload(&event, eff);
  368. }
  369. //--------------------------------------------------------------//
  370. void LinuxForceFeedback::_upload( struct ff_effect* ffeffect, const Effect* effect)
  371. {
  372. struct ff_effect *linEffect = 0;
  373. //Get the effect - if it exists
  374. EffectList::iterator i = mEffectList.find(effect->_handle);
  375. //It has been created already
  376. if( i != mEffectList.end() )
  377. linEffect = i->second;
  378. if( linEffect == 0 )
  379. {
  380. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  381. cout << endl << "LinuxForceFeedback("<< mJoyStick << ") : Adding new effect : "
  382. << Effect::getEffectTypeName(effect->type) << endl;
  383. #endif
  384. //This effect has not yet been created, so create it in the device
  385. if (ioctl(mJoyStick, EVIOCSFF, ffeffect) == -1) {
  386. // TODO device full check
  387. // OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!");
  388. OIS_EXCEPT(E_General, "Unknown error creating effect (may be the device is full)->..");
  389. }
  390. // Save returned effect handle
  391. effect->_handle = ffeffect->id;
  392. // Save a copy of the uploaded effect for later simple modifications
  393. linEffect = (struct ff_effect *)calloc(1, sizeof(struct ff_effect));
  394. memcpy(linEffect, ffeffect, sizeof(struct ff_effect));
  395. mEffectList[effect->_handle] = linEffect;
  396. // Start playing the effect.
  397. _start(effect->_handle);
  398. }
  399. else
  400. {
  401. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  402. cout << endl << "LinuxForceFeedback("<< mJoyStick << ") : Replacing effect : "
  403. << Effect::getEffectTypeName(effect->type) << endl;
  404. #endif
  405. // Keep same id/handle, as this is just an update in the device.
  406. ffeffect->id = effect->_handle;
  407. // Update effect in the device.
  408. if (ioctl(mJoyStick, EVIOCSFF, ffeffect) == -1) {
  409. OIS_EXCEPT(E_General, "Unknown error updating an effect->..");
  410. }
  411. // Update local linEffect for next time.
  412. memcpy(linEffect, ffeffect, sizeof(struct ff_effect));
  413. }
  414. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  415. cout << "LinuxForceFeedback("<< mJoyStick
  416. << ") : Effect handle : " << effect->_handle << endl;
  417. #endif
  418. }
  419. //--------------------------------------------------------------//
  420. void LinuxForceFeedback::_stop( int handle) {
  421. struct input_event stop;
  422. stop.type = EV_FF;
  423. stop.code = handle;
  424. stop.value = 0;
  425. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  426. cout << endl << "LinuxForceFeedback("<< mJoyStick
  427. << ") : Stopping effect with handle " << handle << endl;
  428. #endif
  429. if (write(mJoyStick, &stop, sizeof(stop)) != sizeof(stop)) {
  430. OIS_EXCEPT(E_General, "Unknown error stopping effect->..");
  431. }
  432. }
  433. //--------------------------------------------------------------//
  434. void LinuxForceFeedback::_start( int handle) {
  435. struct input_event play;
  436. play.type = EV_FF;
  437. play.code = handle;
  438. play.value = 1; // Play once.
  439. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  440. cout << endl << "LinuxForceFeedback("<< mJoyStick
  441. << ") : Starting effect with handle " << handle << endl;
  442. #endif
  443. if (write(mJoyStick, &play, sizeof(play)) != sizeof(play)) {
  444. OIS_EXCEPT(E_General, "Unknown error playing effect->..");
  445. }
  446. }
  447. //--------------------------------------------------------------//
  448. void LinuxForceFeedback::_unload( int handle)
  449. {
  450. #if (OIS_LINUX_JOYFF_DEBUG > 1)
  451. cout << endl << "LinuxForceFeedback("<< mJoyStick
  452. << ") : Removing effect with handle " << handle << endl;
  453. #endif
  454. if (ioctl(mJoyStick, EVIOCRMFF, handle) == -1) {
  455. OIS_EXCEPT(E_General, "Unknown error removing effect->..");
  456. }
  457. }