Home | History | Annotate | Download | only in test
      1 /*
      2   Copyright (C) 1997-2014 Sam Lantinga <slouken (at) libsdl.org>
      3 
      4   This software is provided 'as-is', without any express or implied
      5   warranty.  In no event will the authors be held liable for any damages
      6   arising from the use of this software.
      7 
      8   Permission is granted to anyone to use this software for any purpose,
      9   including commercial applications, and to alter it and redistribute it
     10   freely.
     11 */
     12 /*
     13 Copyright (c) 2008, Edgar Simo Serra
     14 All rights reserved.
     15 
     16 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     17 
     18     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     19     * 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.
     20     * 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.
     21 
     22 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.
     23 */
     24 
     25 /*
     26  * includes
     27  */
     28 #include <stdlib.h>
     29 #include <string.h>             /* strstr */
     30 #include <ctype.h>              /* isdigit */
     31 
     32 #include "SDL.h"
     33 
     34 #ifndef SDL_HAPTIC_DISABLED
     35 
     36 #include "SDL_haptic.h"
     37 
     38 static SDL_Haptic *haptic;
     39 
     40 
     41 /*
     42  * prototypes
     43  */
     44 static void abort_execution(void);
     45 static void HapticPrintSupported(SDL_Haptic * haptic);
     46 
     47 
     48 /**
     49  * @brief The entry point of this force feedback demo.
     50  * @param[in] argc Number of arguments.
     51  * @param[in] argv Array of argc arguments.
     52  */
     53 int
     54 main(int argc, char **argv)
     55 {
     56     int i;
     57     char *name;
     58     int index;
     59     SDL_HapticEffect efx[5];
     60     int id[5];
     61     int nefx;
     62     unsigned int supported;
     63 
     64     /* Enable standard application logging */
     65     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
     66 
     67     name = NULL;
     68     index = -1;
     69     if (argc > 1) {
     70         name = argv[1];
     71         if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
     72             SDL_Log("USAGE: %s [device]\n"
     73                    "If device is a two-digit number it'll use it as an index, otherwise\n"
     74                    "it'll use it as if it were part of the device's name.\n",
     75                    argv[0]);
     76             return 0;
     77         }
     78 
     79         i = strlen(name);
     80         if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) {
     81             index = atoi(name);
     82             name = NULL;
     83         }
     84     }
     85 
     86     /* Initialize the force feedbackness */
     87     SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
     88              SDL_INIT_HAPTIC);
     89     SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics());
     90     if (SDL_NumHaptics() > 0) {
     91         /* We'll just use index or the first force feedback device found */
     92         if (name == NULL) {
     93             i = (index != -1) ? index : 0;
     94         }
     95         /* Try to find matching device */
     96         else {
     97             for (i = 0; i < SDL_NumHaptics(); i++) {
     98                 if (strstr(SDL_HapticName(i), name) != NULL)
     99                     break;
    100             }
    101 
    102             if (i >= SDL_NumHaptics()) {
    103                 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n",
    104                        name);
    105                 return 1;
    106             }
    107         }
    108 
    109         haptic = SDL_HapticOpen(i);
    110         if (haptic == NULL) {
    111             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
    112                    SDL_GetError());
    113             return 1;
    114         }
    115         SDL_Log("Device: %s\n", SDL_HapticName(i));
    116         HapticPrintSupported(haptic);
    117     } else {
    118         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n");
    119         return 1;
    120     }
    121 
    122     /* We only want force feedback errors. */
    123     SDL_ClearError();
    124 
    125     /* Create effects. */
    126     memset(&efx, 0, sizeof(efx));
    127     nefx = 0;
    128     supported = SDL_HapticQuery(haptic);
    129 
    130     SDL_Log("\nUploading effects\n");
    131     /* First we'll try a SINE effect. */
    132     if (supported & SDL_HAPTIC_SINE) {
    133         SDL_Log("   effect %d: Sine Wave\n", nefx);
    134         efx[nefx].type = SDL_HAPTIC_SINE;
    135         efx[nefx].periodic.period = 1000;
    136         efx[nefx].periodic.magnitude = 0x4000;
    137         efx[nefx].periodic.length = 5000;
    138         efx[nefx].periodic.attack_length = 1000;
    139         efx[nefx].periodic.fade_length = 1000;
    140         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    141         if (id[nefx] < 0) {
    142             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    143             abort_execution();
    144         }
    145         nefx++;
    146     }
    147     /* Now we'll try a SAWTOOTHUP */
    148     if (supported & SDL_HAPTIC_SAWTOOTHUP) {
    149         SDL_Log("   effect %d: Sawtooth Up\n", nefx);
    150         efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP;
    151         efx[nefx].periodic.period = 500;
    152         efx[nefx].periodic.magnitude = 0x5000;
    153         efx[nefx].periodic.length = 5000;
    154         efx[nefx].periodic.attack_length = 1000;
    155         efx[nefx].periodic.fade_length = 1000;
    156         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    157         if (id[nefx] < 0) {
    158             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    159             abort_execution();
    160         }
    161         nefx++;
    162     }
    163     /* Now the classical constant effect. */
    164     if (supported & SDL_HAPTIC_CONSTANT) {
    165         SDL_Log("   effect %d: Constant Force\n", nefx);
    166         efx[nefx].type = SDL_HAPTIC_CONSTANT;
    167         efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR;
    168         efx[nefx].constant.direction.dir[0] = 20000;    /* Force comes from the south-west. */
    169         efx[nefx].constant.length = 5000;
    170         efx[nefx].constant.level = 0x6000;
    171         efx[nefx].constant.attack_length = 1000;
    172         efx[nefx].constant.fade_length = 1000;
    173         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    174         if (id[nefx] < 0) {
    175             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    176             abort_execution();
    177         }
    178         nefx++;
    179     }
    180     /* The cute spring effect. */
    181     if (supported & SDL_HAPTIC_SPRING) {
    182         SDL_Log("   effect %d: Condition Spring\n", nefx);
    183         efx[nefx].type = SDL_HAPTIC_SPRING;
    184         efx[nefx].condition.length = 5000;
    185         for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
    186             efx[nefx].condition.right_sat[i] = 0x7FFF;
    187             efx[nefx].condition.left_sat[i] = 0x7FFF;
    188             efx[nefx].condition.right_coeff[i] = 0x2000;
    189             efx[nefx].condition.left_coeff[i] = 0x2000;
    190             efx[nefx].condition.center[i] = 0x1000;     /* Displace the center for it to move. */
    191         }
    192         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    193         if (id[nefx] < 0) {
    194             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    195             abort_execution();
    196         }
    197         nefx++;
    198     }
    199     /* The pretty awesome inertia effect. */
    200     if (supported & SDL_HAPTIC_INERTIA) {
    201         SDL_Log("   effect %d: Condition Inertia\n", nefx);
    202         efx[nefx].type = SDL_HAPTIC_SPRING;
    203         efx[nefx].condition.length = 5000;
    204         for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
    205             efx[nefx].condition.right_sat[i] = 0x7FFF;
    206             efx[nefx].condition.left_sat[i] = 0x7FFF;
    207             efx[nefx].condition.right_coeff[i] = 0x2000;
    208             efx[nefx].condition.left_coeff[i] = 0x2000;
    209         }
    210         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    211         if (id[nefx] < 0) {
    212             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    213             abort_execution();
    214         }
    215         nefx++;
    216     }
    217 
    218     /* Finally we'll try a left/right effect. */
    219     if (supported & SDL_HAPTIC_LEFTRIGHT) {
    220         SDL_Log("   effect %d: Left/Right\n", nefx);
    221         efx[nefx].type = SDL_HAPTIC_LEFTRIGHT;
    222         efx[nefx].leftright.length = 5000;
    223         efx[nefx].leftright.large_magnitude = 0x3000;
    224         efx[nefx].leftright.small_magnitude = 0xFFFF;
    225         id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    226         if (id[nefx] < 0) {
    227             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    228             abort_execution();
    229         }
    230         nefx++;
    231     }
    232 
    233 
    234     SDL_Log
    235         ("\nNow playing effects for 5 seconds each with 1 second delay between\n");
    236     for (i = 0; i < nefx; i++) {
    237         SDL_Log("   Playing effect %d\n", i);
    238         SDL_HapticRunEffect(haptic, id[i], 1);
    239         SDL_Delay(6000);        /* Effects only have length 5000 */
    240     }
    241 
    242     /* Quit */
    243     if (haptic != NULL)
    244         SDL_HapticClose(haptic);
    245     SDL_Quit();
    246 
    247     return 0;
    248 }
    249 
    250 
    251 /*
    252  * Cleans up a bit.
    253  */
    254 static void
    255 abort_execution(void)
    256 {
    257     SDL_Log("\nAborting program execution.\n");
    258 
    259     SDL_HapticClose(haptic);
    260     SDL_Quit();
    261 
    262     exit(1);
    263 }
    264 
    265 
    266 /*
    267  * Displays information about the haptic device.
    268  */
    269 static void
    270 HapticPrintSupported(SDL_Haptic * haptic)
    271 {
    272     unsigned int supported;
    273 
    274     supported = SDL_HapticQuery(haptic);
    275     SDL_Log("   Supported effects [%d effects, %d playing]:\n",
    276            SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic));
    277     if (supported & SDL_HAPTIC_CONSTANT)
    278         SDL_Log("      constant\n");
    279     if (supported & SDL_HAPTIC_SINE)
    280         SDL_Log("      sine\n");
    281     /* !!! FIXME: put this back when we have more bits in 2.1 */
    282     /* if (supported & SDL_HAPTIC_SQUARE)
    283         SDL_Log("      square\n"); */
    284     if (supported & SDL_HAPTIC_TRIANGLE)
    285         SDL_Log("      triangle\n");
    286     if (supported & SDL_HAPTIC_SAWTOOTHUP)
    287         SDL_Log("      sawtoothup\n");
    288     if (supported & SDL_HAPTIC_SAWTOOTHDOWN)
    289         SDL_Log("      sawtoothdown\n");
    290     if (supported & SDL_HAPTIC_RAMP)
    291         SDL_Log("      ramp\n");
    292     if (supported & SDL_HAPTIC_FRICTION)
    293         SDL_Log("      friction\n");
    294     if (supported & SDL_HAPTIC_SPRING)
    295         SDL_Log("      spring\n");
    296     if (supported & SDL_HAPTIC_DAMPER)
    297         SDL_Log("      damper\n");
    298     if (supported & SDL_HAPTIC_INERTIA)
    299         SDL_Log("      inertia\n");
    300     if (supported & SDL_HAPTIC_CUSTOM)
    301         SDL_Log("      custom\n");
    302     if (supported & SDL_HAPTIC_LEFTRIGHT)
    303         SDL_Log("      left/right\n");
    304     SDL_Log("   Supported capabilities:\n");
    305     if (supported & SDL_HAPTIC_GAIN)
    306         SDL_Log("      gain\n");
    307     if (supported & SDL_HAPTIC_AUTOCENTER)
    308         SDL_Log("      autocenter\n");
    309     if (supported & SDL_HAPTIC_STATUS)
    310         SDL_Log("      status\n");
    311 }
    312 
    313 #else
    314 
    315 int
    316 main(int argc, char *argv[])
    317 {
    318     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Haptic support.\n");
    319     exit(1);
    320 }
    321 
    322 #endif
    323