testhaptic.c (13851B)
1/* 2Copyright (c) 2008, Edgar Simo Serra 3All rights reserved. 4 5Redistribution 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 11THIS 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 27static SDL_Haptic *haptic; 28 29 30/* 31 * prototypes 32 */ 33static void abort_execution(void); 34static 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 */ 42int 43main(int argc, char **argv) 44{ 45 int i; 46 char *name; 47 int index; 48 SDL_HapticEffect efx[9]; 49 int id[9]; 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 = -0x2000; /* Negative magnitude and ... */ 126 efx[nefx].periodic.phase = 18000; /* ... 180 degrees phase shift => cancel eachother */ 127 efx[nefx].periodic.length = 5000; 128 efx[nefx].periodic.attack_length = 1000; 129 efx[nefx].periodic.fade_length = 1000; 130 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 131 if (id[nefx] < 0) { 132 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 133 abort_execution(); 134 } 135 nefx++; 136 } 137 /* Now we'll try a SAWTOOTHUP */ 138 if (supported & SDL_HAPTIC_SAWTOOTHUP) { 139 SDL_Log(" effect %d: Sawtooth Up\n", nefx); 140 efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP; 141 efx[nefx].periodic.period = 500; 142 efx[nefx].periodic.magnitude = 0x5000; 143 efx[nefx].periodic.length = 5000; 144 efx[nefx].periodic.attack_length = 1000; 145 efx[nefx].periodic.fade_length = 1000; 146 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 147 if (id[nefx] < 0) { 148 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 149 abort_execution(); 150 } 151 nefx++; 152 } 153 154 /* Now the classical constant effect. */ 155 if (supported & SDL_HAPTIC_CONSTANT) { 156 SDL_Log(" effect %d: Constant Force\n", nefx); 157 efx[nefx].type = SDL_HAPTIC_CONSTANT; 158 efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR; 159 efx[nefx].constant.direction.dir[0] = 20000; /* Force comes from the south-west. */ 160 efx[nefx].constant.length = 5000; 161 efx[nefx].constant.level = 0x6000; 162 efx[nefx].constant.attack_length = 1000; 163 efx[nefx].constant.fade_length = 1000; 164 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 165 if (id[nefx] < 0) { 166 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 167 abort_execution(); 168 } 169 nefx++; 170 } 171 172 /* The cute spring effect. */ 173 if (supported & SDL_HAPTIC_SPRING) { 174 SDL_Log(" effect %d: Condition Spring\n", nefx); 175 efx[nefx].type = SDL_HAPTIC_SPRING; 176 efx[nefx].condition.length = 5000; 177 for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { 178 efx[nefx].condition.right_sat[i] = 0xFFFF; 179 efx[nefx].condition.left_sat[i] = 0xFFFF; 180 efx[nefx].condition.right_coeff[i] = 0x2000; 181 efx[nefx].condition.left_coeff[i] = 0x2000; 182 efx[nefx].condition.center[i] = 0x1000; /* Displace the center for it to move. */ 183 } 184 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 185 if (id[nefx] < 0) { 186 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 187 abort_execution(); 188 } 189 nefx++; 190 } 191 /* The interesting damper effect. */ 192 if (supported & SDL_HAPTIC_DAMPER) { 193 SDL_Log(" effect %d: Condition Damper\n", nefx); 194 efx[nefx].type = SDL_HAPTIC_DAMPER; 195 efx[nefx].condition.length = 5000; 196 for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { 197 efx[nefx].condition.right_sat[i] = 0xFFFF; 198 efx[nefx].condition.left_sat[i] = 0xFFFF; 199 efx[nefx].condition.right_coeff[i] = 0x2000; 200 efx[nefx].condition.left_coeff[i] = 0x2000; 201 } 202 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 203 if (id[nefx] < 0) { 204 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 205 abort_execution(); 206 } 207 nefx++; 208 } 209 /* The pretty awesome inertia effect. */ 210 if (supported & SDL_HAPTIC_INERTIA) { 211 SDL_Log(" effect %d: Condition Inertia\n", nefx); 212 efx[nefx].type = SDL_HAPTIC_INERTIA; 213 efx[nefx].condition.length = 5000; 214 for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { 215 efx[nefx].condition.right_sat[i] = 0xFFFF; 216 efx[nefx].condition.left_sat[i] = 0xFFFF; 217 efx[nefx].condition.right_coeff[i] = 0x2000; 218 efx[nefx].condition.left_coeff[i] = 0x2000; 219 efx[nefx].condition.deadband[i] = 0x1000; /* 1/16th of axis-range around the center is 'dead'. */ 220 } 221 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 222 if (id[nefx] < 0) { 223 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 224 abort_execution(); 225 } 226 nefx++; 227 } 228 /* The hot friction effect. */ 229 if (supported & SDL_HAPTIC_FRICTION) { 230 SDL_Log(" effect %d: Condition Friction\n", nefx); 231 efx[nefx].type = SDL_HAPTIC_FRICTION; 232 efx[nefx].condition.length = 5000; 233 for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { 234 efx[nefx].condition.right_sat[i] = 0xFFFF; 235 efx[nefx].condition.left_sat[i] = 0xFFFF; 236 efx[nefx].condition.right_coeff[i] = 0x2000; 237 efx[nefx].condition.left_coeff[i] = 0x2000; 238 } 239 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 240 if (id[nefx] < 0) { 241 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 242 abort_execution(); 243 } 244 nefx++; 245 } 246 247 /* Now we'll try a ramp effect */ 248 if (supported & SDL_HAPTIC_RAMP) { 249 SDL_Log(" effect %d: Ramp\n", nefx); 250 efx[nefx].type = SDL_HAPTIC_RAMP; 251 efx[nefx].ramp.direction.type = SDL_HAPTIC_CARTESIAN; 252 efx[nefx].ramp.direction.dir[0] = 1; /* Force comes from */ 253 efx[nefx].ramp.direction.dir[1] = -1; /* the north-east. */ 254 efx[nefx].ramp.length = 5000; 255 efx[nefx].ramp.start = 0x4000; 256 efx[nefx].ramp.end = -0x4000; 257 efx[nefx].ramp.attack_length = 1000; 258 efx[nefx].ramp.fade_length = 1000; 259 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 260 if (id[nefx] < 0) { 261 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 262 abort_execution(); 263 } 264 nefx++; 265 } 266 267 /* Finally we'll try a left/right effect. */ 268 if (supported & SDL_HAPTIC_LEFTRIGHT) { 269 SDL_Log(" effect %d: Left/Right\n", nefx); 270 efx[nefx].type = SDL_HAPTIC_LEFTRIGHT; 271 efx[nefx].leftright.length = 5000; 272 efx[nefx].leftright.large_magnitude = 0x3000; 273 efx[nefx].leftright.small_magnitude = 0xFFFF; 274 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); 275 if (id[nefx] < 0) { 276 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); 277 abort_execution(); 278 } 279 nefx++; 280 } 281 282 283 SDL_Log 284 ("\nNow playing effects for 5 seconds each with 1 second delay between\n"); 285 for (i = 0; i < nefx; i++) { 286 SDL_Log(" Playing effect %d\n", i); 287 SDL_HapticRunEffect(haptic, id[i], 1); 288 SDL_Delay(6000); /* Effects only have length 5000 */ 289 } 290 291 /* Quit */ 292 if (haptic != NULL) 293 SDL_HapticClose(haptic); 294 SDL_Quit(); 295 296 return 0; 297} 298 299 300/* 301 * Cleans up a bit. 302 */ 303static void 304abort_execution(void) 305{ 306 SDL_Log("\nAborting program execution.\n"); 307 308 SDL_HapticClose(haptic); 309 SDL_Quit(); 310 311 exit(1); 312} 313 314 315/* 316 * Displays information about the haptic device. 317 */ 318static void 319HapticPrintSupported(SDL_Haptic * haptic) 320{ 321 unsigned int supported; 322 323 supported = SDL_HapticQuery(haptic); 324 SDL_Log(" Supported effects [%d effects, %d playing]:\n", 325 SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic)); 326 if (supported & SDL_HAPTIC_CONSTANT) 327 SDL_Log(" constant\n"); 328 if (supported & SDL_HAPTIC_SINE) 329 SDL_Log(" sine\n"); 330 /* !!! FIXME: put this back when we have more bits in 2.1 */ 331 /* if (supported & SDL_HAPTIC_SQUARE) 332 SDL_Log(" square\n"); */ 333 if (supported & SDL_HAPTIC_TRIANGLE) 334 SDL_Log(" triangle\n"); 335 if (supported & SDL_HAPTIC_SAWTOOTHUP) 336 SDL_Log(" sawtoothup\n"); 337 if (supported & SDL_HAPTIC_SAWTOOTHDOWN) 338 SDL_Log(" sawtoothdown\n"); 339 if (supported & SDL_HAPTIC_RAMP) 340 SDL_Log(" ramp\n"); 341 if (supported & SDL_HAPTIC_FRICTION) 342 SDL_Log(" friction\n"); 343 if (supported & SDL_HAPTIC_SPRING) 344 SDL_Log(" spring\n"); 345 if (supported & SDL_HAPTIC_DAMPER) 346 SDL_Log(" damper\n"); 347 if (supported & SDL_HAPTIC_INERTIA) 348 SDL_Log(" inertia\n"); 349 if (supported & SDL_HAPTIC_CUSTOM) 350 SDL_Log(" custom\n"); 351 if (supported & SDL_HAPTIC_LEFTRIGHT) 352 SDL_Log(" left/right\n"); 353 SDL_Log(" Supported capabilities:\n"); 354 if (supported & SDL_HAPTIC_GAIN) 355 SDL_Log(" gain\n"); 356 if (supported & SDL_HAPTIC_AUTOCENTER) 357 SDL_Log(" autocenter\n"); 358 if (supported & SDL_HAPTIC_STATUS) 359 SDL_Log(" status\n"); 360} 361 362#else 363 364int 365main(int argc, char *argv[]) 366{ 367 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Haptic support.\n"); 368 exit(1); 369} 370 371#endif