test/testhaptic.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 16 Aug 2014 16:47:42 -0400
changeset 9070 8973a237f360
parent 8741 d5b21f813734
child 9072 0c1a46c018aa
permissions -rw-r--r--
Haptic: Fix the saturation and deadband parameters' available range.

There was a misconception that Linux's saturation and deadband parameters -
on which the corresponding SDL parameters were based - use only half of the
possible range.

Thanks, Elias!

Partially fixes Bugzilla #2686.
     1 /*
     2 Copyright (c) 2008, Edgar Simo Serra
     3 All rights reserved.
     4 
     5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     6 
     7     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     8     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
     9     * Neither the name of the Simple Directmedia Layer (SDL) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    10 
    11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    12 */
    13 
    14 /*
    15  * includes
    16  */
    17 #include <stdlib.h>
    18 #include <string.h>             /* strstr */
    19 #include <ctype.h>              /* isdigit */
    20 
    21 #include "SDL.h"
    22 
    23 #ifndef SDL_HAPTIC_DISABLED
    24 
    25 #include "SDL_haptic.h"
    26 
    27 static SDL_Haptic *haptic;
    28 
    29 
    30 /*
    31  * prototypes
    32  */
    33 static void abort_execution(void);
    34 static void HapticPrintSupported(SDL_Haptic * haptic);
    35 
    36 
    37 /**
    38  * @brief The entry point of this force feedback demo.
    39  * @param[in] argc Number of arguments.
    40  * @param[in] argv Array of argc arguments.
    41  */
    42 int
    43 main(int argc, char **argv)
    44 {
    45     int i;
    46     char *name;
    47     int index;
    48     SDL_HapticEffect efx[5];
    49     int id[5];
    50     int nefx;
    51     unsigned int supported;
    52 
    53     /* Enable standard application logging */
    54     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
    55 
    56     name = NULL;
    57     index = -1;
    58     if (argc > 1) {
    59         name = argv[1];
    60         if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
    61             SDL_Log("USAGE: %s [device]\n"
    62                    "If device is a two-digit number it'll use it as an index, otherwise\n"
    63                    "it'll use it as if it were part of the device's name.\n",
    64                    argv[0]);
    65             return 0;
    66         }
    67 
    68         i = strlen(name);
    69         if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) {
    70             index = atoi(name);
    71             name = NULL;
    72         }
    73     }
    74 
    75     /* Initialize the force feedbackness */
    76     SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
    77              SDL_INIT_HAPTIC);
    78     SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics());
    79     if (SDL_NumHaptics() > 0) {
    80         /* We'll just use index or the first force feedback device found */
    81         if (name == NULL) {
    82             i = (index != -1) ? index : 0;
    83         }
    84         /* Try to find matching device */
    85         else {
    86             for (i = 0; i < SDL_NumHaptics(); i++) {
    87                 if (strstr(SDL_HapticName(i), name) != NULL)
    88                     break;
    89             }
    90 
    91             if (i >= SDL_NumHaptics()) {
    92                 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n",
    93                        name);
    94                 return 1;
    95             }
    96         }
    97 
    98         haptic = SDL_HapticOpen(i);
    99         if (haptic == NULL) {
   100             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
   101                    SDL_GetError());
   102             return 1;
   103         }
   104         SDL_Log("Device: %s\n", SDL_HapticName(i));
   105         HapticPrintSupported(haptic);
   106     } else {
   107         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n");
   108         return 1;
   109     }
   110 
   111     /* We only want force feedback errors. */
   112     SDL_ClearError();
   113 
   114     /* Create effects. */
   115     memset(&efx, 0, sizeof(efx));
   116     nefx = 0;
   117     supported = SDL_HapticQuery(haptic);
   118 
   119     SDL_Log("\nUploading effects\n");
   120     /* First we'll try a SINE effect. */
   121     if (supported & SDL_HAPTIC_SINE) {
   122         SDL_Log("   effect %d: Sine Wave\n", nefx);
   123         efx[nefx].type = SDL_HAPTIC_SINE;
   124         efx[nefx].periodic.period = 1000;
   125         efx[nefx].periodic.magnitude = 0x4000;
   126         efx[nefx].periodic.length = 5000;
   127         efx[nefx].periodic.attack_length = 1000;
   128         efx[nefx].periodic.fade_length = 1000;
   129         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
   130         if (id[nefx] < 0) {
   131             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
   132             abort_execution();
   133         }
   134         nefx++;
   135     }
   136     /* Now we'll try a SAWTOOTHUP */
   137     if (supported & SDL_HAPTIC_SAWTOOTHUP) {
   138         SDL_Log("   effect %d: Sawtooth Up\n", nefx);
   139         efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP;
   140         efx[nefx].periodic.period = 500;
   141         efx[nefx].periodic.magnitude = 0x5000;
   142         efx[nefx].periodic.length = 5000;
   143         efx[nefx].periodic.attack_length = 1000;
   144         efx[nefx].periodic.fade_length = 1000;
   145         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
   146         if (id[nefx] < 0) {
   147             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
   148             abort_execution();
   149         }
   150         nefx++;
   151     }
   152     /* Now the classical constant effect. */
   153     if (supported & SDL_HAPTIC_CONSTANT) {
   154         SDL_Log("   effect %d: Constant Force\n", nefx);
   155         efx[nefx].type = SDL_HAPTIC_CONSTANT;
   156         efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR;
   157         efx[nefx].constant.direction.dir[0] = 20000;    /* Force comes from the south-west. */
   158         efx[nefx].constant.length = 5000;
   159         efx[nefx].constant.level = 0x6000;
   160         efx[nefx].constant.attack_length = 1000;
   161         efx[nefx].constant.fade_length = 1000;
   162         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
   163         if (id[nefx] < 0) {
   164             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
   165             abort_execution();
   166         }
   167         nefx++;
   168     }
   169     /* The cute spring effect. */
   170     if (supported & SDL_HAPTIC_SPRING) {
   171         SDL_Log("   effect %d: Condition Spring\n", nefx);
   172         efx[nefx].type = SDL_HAPTIC_SPRING;
   173         efx[nefx].condition.length = 5000;
   174         for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
   175             efx[nefx].condition.right_sat[i] = 0xFFFF;
   176             efx[nefx].condition.left_sat[i] = 0xFFFF;
   177             efx[nefx].condition.right_coeff[i] = 0x2000;
   178             efx[nefx].condition.left_coeff[i] = 0x2000;
   179             efx[nefx].condition.center[i] = 0x1000;     /* Displace the center for it to move. */
   180         }
   181         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
   182         if (id[nefx] < 0) {
   183             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
   184             abort_execution();
   185         }
   186         nefx++;
   187     }
   188     /* The pretty awesome inertia effect. */
   189     if (supported & SDL_HAPTIC_INERTIA) {
   190         SDL_Log("   effect %d: Condition Inertia\n", nefx);
   191         efx[nefx].type = SDL_HAPTIC_INERTIA;
   192         efx[nefx].condition.length = 5000;
   193         for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
   194             efx[nefx].condition.right_sat[i] = 0xFFFF;
   195             efx[nefx].condition.left_sat[i] = 0xFFFF;
   196             efx[nefx].condition.right_coeff[i] = 0x2000;
   197             efx[nefx].condition.left_coeff[i] = 0x2000;
   198             efx[nefx].condition.deadband[i] = 0x1000;    /* 1/16th of axis-range around the center is 'dead'. */
   199         }
   200         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
   201         if (id[nefx] < 0) {
   202             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
   203             abort_execution();
   204         }
   205         nefx++;
   206     }
   207 
   208     /* Finally we'll try a left/right effect. */
   209     if (supported & SDL_HAPTIC_LEFTRIGHT) {
   210         SDL_Log("   effect %d: Left/Right\n", nefx);
   211         efx[nefx].type = SDL_HAPTIC_LEFTRIGHT;
   212         efx[nefx].leftright.length = 5000;
   213         efx[nefx].leftright.large_magnitude = 0x3000;
   214         efx[nefx].leftright.small_magnitude = 0xFFFF;
   215         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
   216         if (id[nefx] < 0) {
   217             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
   218             abort_execution();
   219         }
   220         nefx++;
   221     }
   222 
   223 
   224     SDL_Log
   225         ("\nNow playing effects for 5 seconds each with 1 second delay between\n");
   226     for (i = 0; i < nefx; i++) {
   227         SDL_Log("   Playing effect %d\n", i);
   228         SDL_HapticRunEffect(haptic, id[i], 1);
   229         SDL_Delay(6000);        /* Effects only have length 5000 */
   230     }
   231 
   232     /* Quit */
   233     if (haptic != NULL)
   234         SDL_HapticClose(haptic);
   235     SDL_Quit();
   236 
   237     return 0;
   238 }
   239 
   240 
   241 /*
   242  * Cleans up a bit.
   243  */
   244 static void
   245 abort_execution(void)
   246 {
   247     SDL_Log("\nAborting program execution.\n");
   248 
   249     SDL_HapticClose(haptic);
   250     SDL_Quit();
   251 
   252     exit(1);
   253 }
   254 
   255 
   256 /*
   257  * Displays information about the haptic device.
   258  */
   259 static void
   260 HapticPrintSupported(SDL_Haptic * haptic)
   261 {
   262     unsigned int supported;
   263 
   264     supported = SDL_HapticQuery(haptic);
   265     SDL_Log("   Supported effects [%d effects, %d playing]:\n",
   266            SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic));
   267     if (supported & SDL_HAPTIC_CONSTANT)
   268         SDL_Log("      constant\n");
   269     if (supported & SDL_HAPTIC_SINE)
   270         SDL_Log("      sine\n");
   271     /* !!! FIXME: put this back when we have more bits in 2.1 */
   272     /* if (supported & SDL_HAPTIC_SQUARE)
   273         SDL_Log("      square\n"); */
   274     if (supported & SDL_HAPTIC_TRIANGLE)
   275         SDL_Log("      triangle\n");
   276     if (supported & SDL_HAPTIC_SAWTOOTHUP)
   277         SDL_Log("      sawtoothup\n");
   278     if (supported & SDL_HAPTIC_SAWTOOTHDOWN)
   279         SDL_Log("      sawtoothdown\n");
   280     if (supported & SDL_HAPTIC_RAMP)
   281         SDL_Log("      ramp\n");
   282     if (supported & SDL_HAPTIC_FRICTION)
   283         SDL_Log("      friction\n");
   284     if (supported & SDL_HAPTIC_SPRING)
   285         SDL_Log("      spring\n");
   286     if (supported & SDL_HAPTIC_DAMPER)
   287         SDL_Log("      damper\n");
   288     if (supported & SDL_HAPTIC_INERTIA)
   289         SDL_Log("      inertia\n");
   290     if (supported & SDL_HAPTIC_CUSTOM)
   291         SDL_Log("      custom\n");
   292     if (supported & SDL_HAPTIC_LEFTRIGHT)
   293         SDL_Log("      left/right\n");
   294     SDL_Log("   Supported capabilities:\n");
   295     if (supported & SDL_HAPTIC_GAIN)
   296         SDL_Log("      gain\n");
   297     if (supported & SDL_HAPTIC_AUTOCENTER)
   298         SDL_Log("      autocenter\n");
   299     if (supported & SDL_HAPTIC_STATUS)
   300         SDL_Log("      status\n");
   301 }
   302 
   303 #else
   304 
   305 int
   306 main(int argc, char *argv[])
   307 {
   308     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Haptic support.\n");
   309     exit(1);
   310 }
   311 
   312 #endif