Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Aug 22, 2009, 11:16:34 PM (15 years ago)
Author:
rgrieder
Message:

Updated OIS library (still 1.2, but CVS version).
There have been some little fixes and support for force feedback on Linux (but this doesn't concern us for now…)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/branches/resource2/src/ois/linux/LinuxForceFeedback.cpp

    r1505 r5668  
    2424#include "OISException.h"
    2525
     26#include <cstdlib>
     27#include <errno.h>
     28#include <memory.h>
     29
    2630using namespace OIS;
    2731
    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//--------------------------------------------------------------//
     41LinuxForceFeedback::LinuxForceFeedback(int deviceID) :
     42        ForceFeedback(), mJoyStick(deviceID)
     43{
     44}
     45
    3246//--------------------------------------------------------------//
    3347LinuxForceFeedback::~LinuxForceFeedback()
    3448{
    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//--------------------------------------------------------------//
     61unsigned 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//--------------------------------------------------------------//
     75void 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//--------------------------------------------------------------//
     108void 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//--------------------------------------------------------------//
     137void 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//--------------------------------------------------------------//
     163void LinuxForceFeedback::modify( const Effect* effect )
     164{
     165        upload(effect);
     166}
     167
     168//--------------------------------------------------------------//
     169void 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//--------------------------------------------------------------//
     223void 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//--------------------------------------------------------------//
     284void 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//--------------------------------------------------------------//
     306void 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//--------------------------------------------------------------//
     331void 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//--------------------------------------------------------------//
     392void 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//--------------------------------------------------------------//
     451void 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//--------------------------------------------------------------//
     513void 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//--------------------------------------------------------------//
     531void 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//--------------------------------------------------------------//
     549void 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.