src/haptic/SDL_haptic.c
author Edgar Simo <bobbens@gmail.com>
Tue, 08 Jul 2008 19:55:12 +0000
branchgsoc2008_force_feedback
changeset 2507 8ef1d0f4d0c1
parent 2506 ba8e99fe92c1
child 2512 ef147ee4896c
permissions -rw-r--r--
Gain is set to max on haptic device open.
Autocenter is disabled on haptic device open.
Maximum gain can be set by SDL_HAPTIC_GAIN_MAX.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 2008 Edgar Simo
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_syshaptic.h"
    25 #include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
    26 
    27 
    28 static Uint8 SDL_numhaptics = 0;
    29 SDL_Haptic **SDL_haptics = NULL;
    30 static SDL_Haptic *default_haptic = NULL;
    31 
    32 
    33 /*
    34  * Initializes the Haptic devices.
    35  */
    36 int
    37 SDL_HapticInit(void)
    38 {  
    39    int arraylen;
    40    int status;
    41 
    42    SDL_numhaptics = 0;
    43    status = SDL_SYS_HapticInit();
    44    if (status >= 0) {
    45       arraylen = (status + 1) * sizeof(*SDL_haptics);
    46       SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
    47       if (SDL_haptics == NULL) {
    48          SDL_numhaptics = 0;
    49       } else {
    50          SDL_memset(SDL_haptics, 0, arraylen);
    51          SDL_numhaptics = status;
    52       }
    53       status = 0;
    54    }
    55    default_haptic = NULL;
    56 
    57    return status;
    58 }
    59 
    60 
    61 /*
    62  * Checks to see if the haptic device is valid
    63  */
    64 static int
    65 ValidHaptic(SDL_Haptic ** haptic)
    66 {
    67    int valid;
    68    
    69    if (*haptic == NULL) {
    70       SDL_SetError("Haptic device hasn't been opened yet");
    71       valid = 0;
    72    } else {
    73       valid = 1;
    74    }
    75    return valid;
    76 }
    77 
    78 
    79 /*
    80  * Returns the number of available devices.
    81  */
    82 int
    83 SDL_NumHaptics(void)
    84 {
    85    return SDL_numhaptics;
    86 }
    87 
    88 
    89 /*
    90  * Gets the name of a Haptic device by index.
    91  */
    92 const char *
    93 SDL_HapticName(int device_index)
    94 {
    95    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
    96       SDL_SetError("There are %d haptic devices available", SDL_numhaptics);
    97       return NULL;
    98    }
    99    return SDL_SYS_HapticName(device_index);
   100 }
   101 
   102 
   103 /*
   104  * Opens a Haptic device.
   105  */
   106 SDL_Haptic *
   107 SDL_HapticOpen(int device_index)
   108 {
   109    int i;
   110    SDL_Haptic *haptic;
   111 
   112    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   113       SDL_SetError("There are %d haptic devices available", SDL_numhaptics);
   114       return NULL;
   115    }
   116 
   117    /* If the haptic is already open, return it */
   118    for (i=0; SDL_haptics[i]; i++) {             
   119       if (device_index == SDL_haptics[i]->index) {
   120          haptic = SDL_haptics[i];
   121          ++haptic->ref_count;
   122          return haptic;
   123       }
   124    }
   125 
   126    /* Create the haptic device */
   127    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   128    if (haptic == NULL) {
   129       SDL_OutOfMemory();
   130       return NULL;
   131    }
   132 
   133    /* Initialize the haptic device */
   134    SDL_memset(haptic, 0, (sizeof *haptic));
   135    haptic->index = device_index;
   136    if (SDL_SYS_HapticOpen(haptic) < 0) {
   137       SDL_free(haptic);
   138       return NULL;
   139    }
   140 
   141    /* Disable autocenter and set gain to max. */
   142    if (haptic->supported & SDL_HAPTIC_GAIN)
   143       SDL_HapticSetGain(haptic,100);
   144    if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
   145       SDL_HapticSetAutocenter(haptic,0);
   146 
   147    /* Add haptic to list */
   148    ++haptic->ref_count;
   149    for (i=0; SDL_haptics[i]; i++)
   150       /* Skip to next haptic */ ;
   151    SDL_haptics[i] = haptic;
   152 
   153    return haptic;
   154 }
   155 
   156 
   157 /*
   158  * Returns 1 if the device has been opened.
   159  */
   160 int
   161 SDL_HapticOpened(int device_index)
   162 {
   163    int i, opened;
   164 
   165    opened = 0;
   166    for (i=0; SDL_haptics[i]; i++) {
   167       if (SDL_haptics[i]->index == (Uint8) device_index) {
   168          opened = 1;
   169          break;
   170       }
   171    }
   172    return opened;
   173 }
   174 
   175 
   176 /*
   177  * Returns the index to a haptic device.
   178  */
   179 int
   180 SDL_HapticIndex(SDL_Haptic * haptic)
   181 {
   182    if (!ValidHaptic(&haptic)) {
   183       return -1;
   184    }
   185 
   186    return haptic->index;
   187 }
   188 
   189 
   190 /*
   191  * Returns SDL_TRUE if joystick has haptic features.
   192  */
   193 int
   194 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   195 {
   196    int ret;
   197 
   198    /* Must be a valid joystick */
   199    if (!SDL_PrivateJoystickValid(&joystick)) {
   200       return -1;
   201    }
   202 
   203    ret = SDL_SYS_JoystickIsHaptic(joystick);
   204 
   205    if (ret > 0) return SDL_TRUE;
   206    else if (ret == 0) return SDL_FALSE;
   207    else return -1;
   208 }
   209 
   210 
   211 /*
   212  * Opens a haptic device from a joystick.
   213  */
   214 SDL_Haptic *
   215 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   216 {
   217    int i;
   218    SDL_Haptic *haptic;
   219 
   220    /* Must be a valid joystick */
   221    if (!SDL_PrivateJoystickValid(&joystick)) {
   222       return NULL;
   223    }
   224 
   225    /* Joystick must be haptic */
   226    if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   227       return NULL;
   228    }
   229 
   230    /* Check to see if joystick's haptic is already open */
   231    for (i=0; SDL_haptics[i]; i++) {
   232       if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i],joystick)) {
   233          haptic = SDL_haptics[i];
   234          ++haptic->ref_count;
   235          return haptic;
   236       }
   237    }
   238 
   239    /* Create the haptic device */
   240    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   241    if (haptic == NULL) {
   242       SDL_OutOfMemory();
   243       return NULL;
   244    }
   245 
   246    /* Initialize the haptic device */
   247    SDL_memset(haptic, 0, (sizeof *haptic));
   248    if (SDL_SYS_HapticOpenFromJoystick(haptic,joystick) < 0) {
   249       SDL_free(haptic);
   250       return NULL;
   251    }
   252 
   253    /* Add haptic to list */
   254    ++haptic->ref_count;
   255    for (i=0; SDL_haptics[i]; i++)
   256       /* Skip to next haptic */ ;
   257    SDL_haptics[i] = haptic;
   258 
   259    return haptic;
   260 }
   261 
   262 
   263 /*
   264  * Closes a SDL_Haptic device.
   265  */
   266 void
   267 SDL_HapticClose(SDL_Haptic * haptic)
   268 {
   269    int i;
   270 
   271    /* Must be valid */
   272    if (!ValidHaptic(&haptic)) {
   273       return;
   274    }
   275 
   276    /* Check if it's still in use */
   277    if (--haptic->ref_count < 0) {
   278       return;
   279    }
   280 
   281    /* Close it, properly removing effects if needed */
   282    for (i=0; i<haptic->neffects; i++) {
   283       if (haptic->effects[i].hweffect != NULL) {
   284          SDL_HapticDestroyEffect(haptic,i);
   285       }
   286    }
   287    SDL_SYS_HapticClose(haptic);
   288 
   289    /* Remove from the list */
   290    for (i = 0; SDL_haptics[i]; ++i) {
   291       if (haptic == SDL_haptics[i]) {
   292          SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   293                (SDL_numhaptics - i) * sizeof(haptic));
   294          break;
   295       }
   296    }
   297 
   298    /* Free */
   299    SDL_free(haptic);
   300 }
   301 
   302 /*
   303  * Cleans up after the subsystem.
   304  */
   305 void
   306 SDL_HapticQuit(void)
   307 {
   308    SDL_numhaptics = 0;
   309 
   310    SDL_SYS_HapticQuit();
   311    if (SDL_haptics != NULL) {
   312       SDL_free(SDL_haptics);
   313       SDL_haptics = NULL;
   314    }
   315 }
   316 
   317 /*
   318  * Returns the number of effects a haptic device has.
   319  */
   320 int
   321 SDL_HapticNumEffects(SDL_Haptic * haptic)
   322 {
   323    if (!ValidHaptic(&haptic)) {
   324       return -1;
   325    }
   326 
   327    return haptic->neffects;
   328 }
   329 
   330 /*
   331  * Returns supported effects by the device.
   332  */
   333 unsigned int
   334 SDL_HapticQuery(SDL_Haptic * haptic)
   335 {
   336    if (!ValidHaptic(&haptic)) {
   337       return -1;
   338    }
   339 
   340    return haptic->supported;
   341 }
   342 
   343 /*
   344  * Checks to see if the device can support the effect.
   345  */
   346 int
   347 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   348 {
   349    if (!ValidHaptic(&haptic)) {
   350       return -1;
   351    }
   352 
   353    if ((haptic->supported & effect->type) != 0)
   354       return SDL_TRUE;
   355    return SDL_FALSE;
   356 }
   357 
   358 /*
   359  * Creates a new haptic effect.
   360  */
   361 int
   362 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   363 {
   364    int i;
   365 
   366    /* Check for device validity. */
   367    if (!ValidHaptic(&haptic)) {
   368       return -1;
   369    }
   370 
   371    /* Check to see if effect is supported */
   372    if (SDL_HapticEffectSupported(haptic,effect)==SDL_FALSE) {
   373       SDL_SetError("Haptic effect not supported by haptic device.");
   374       return -1;
   375    }
   376 
   377    /* See if there's a free slot */
   378    for (i=0; i<haptic->neffects; i++) {
   379       if (haptic->effects[i].hweffect == NULL) {
   380 
   381          /* Now let the backend create the real effect */
   382          if (SDL_SYS_HapticNewEffect(haptic,&haptic->effects[i],effect) != 0) {
   383             return -1; /* Backend failed to create effect */
   384          }
   385          return i;
   386       }
   387    }
   388 
   389    SDL_SetError("Haptic device has no free space left.");
   390    return -1;
   391 }
   392 
   393 /*
   394  * Checks to see if an effect is valid.
   395  */
   396 static int
   397 ValidEffect(SDL_Haptic * haptic, int effect)
   398 {
   399    if ((effect < 0) || (effect >= haptic->neffects)) {
   400       SDL_SetError("Invalid haptic effect identifier.");
   401       return 0;
   402    }
   403    return 1;
   404 }
   405 
   406 /*
   407  * Updates an effect.
   408  */
   409 int
   410 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data)
   411 {
   412    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   413       return -1;
   414    }
   415 
   416    /* Updates the effect */
   417    if (SDL_SYS_HapticUpdateEffect(haptic,&haptic->effects[effect],data) < 0) {
   418       return -1;
   419    }
   420 
   421    return 0;
   422 }
   423 
   424 
   425 /*
   426  * Runs the haptic effect on the device.
   427  */
   428 int
   429 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect)
   430 {
   431    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   432       return -1;
   433    }
   434 
   435    /* Run the effect */
   436    if (SDL_SYS_HapticRunEffect(haptic,&haptic->effects[effect]) < 0) {
   437       return -1;
   438    }
   439 
   440    return 0;
   441 }
   442 
   443 /*
   444  * Stops the haptic effect on the device.
   445  */
   446 int
   447 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   448 {
   449    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   450       return -1;
   451    }
   452 
   453    /* Stop the effect */
   454    if (SDL_SYS_HapticStopEffect(haptic,&haptic->effects[effect]) < 0) {
   455       return -1;
   456    }
   457 
   458    return 0;
   459 }
   460 
   461 /*
   462  * Gets rid of a haptic effect.
   463  */
   464 void
   465 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   466 {
   467    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   468       return;
   469    }
   470 
   471    /* Not allocated */
   472    if (haptic->effects[effect].hweffect == NULL) {
   473       return;
   474    }
   475 
   476    SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   477 }
   478 
   479 /*
   480  * Gets the status of a haptic effect.
   481  */
   482 int
   483 SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect)
   484 {
   485    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   486       return -1;
   487    }
   488 
   489    if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   490       SDL_SetError("Haptic device does not support status queries.");
   491       return -1;
   492    }
   493 
   494    return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   495 }
   496 
   497 /*
   498  * Sets the global gain of the device.
   499  */
   500 int
   501 SDL_HapticSetGain(SDL_Haptic * haptic, int gain )
   502 {
   503    const char *env;
   504    int real_gain, max_gain;
   505 
   506    if (!ValidHaptic(&haptic)) {
   507       return -1;
   508    }
   509 
   510    if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   511       SDL_SetError("Haptic device does not support setting gain.");
   512       return -1;
   513    }
   514 
   515    if ((gain < 0) || (gain > 100)) {
   516       SDL_SetError("Haptic gain must be between 0 and 100.");
   517       return -1;
   518    }
   519 
   520    /* We use the envvar to get the maximum gain. */
   521    env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   522    if (env != NULL) {
   523       max_gain = SDL_atoi(env);
   524 
   525       /* Check for sanity. */
   526       if (max_gain < 0) max_gain = 0;
   527       else if (max_gain > 100) max_gain = 100;
   528 
   529       /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   530       real_gain = (gain * max_gain) / 100;
   531    }
   532    else {
   533       real_gain = gain;
   534    }
   535 
   536    if (SDL_SYS_HapticSetGain(haptic,real_gain) < 0) {
   537       return -1;
   538    }
   539 
   540    return 0;
   541 }
   542 
   543 /*
   544  * Makes the device autocenter, 0 disables.
   545  */
   546 int
   547 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter )
   548 {
   549    if (!ValidHaptic(&haptic)) {
   550       return -1;
   551    }
   552 
   553    if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   554       SDL_SetError("Haptic device does not support setting autocenter.");
   555       return -1;
   556    }
   557 
   558    if ((autocenter < 0) || (autocenter > 100)) {
   559       SDL_SetError("Haptic autocenter must be between 0 and 100.");
   560       return -1;
   561    }                                           
   562 
   563    if (SDL_SYS_HapticSetAutocenter(haptic,autocenter) < 0) {
   564       return -1;
   565    }
   566 
   567    return 0;
   568 }
   569 
   570