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