SDL  2.0
testhaptic.c
Go to the documentation of this file.
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 static SDL_Haptic *haptic;
26 
27 
28 /*
29  * prototypes
30  */
31 static void abort_execution(void);
32 static void HapticPrintSupported(SDL_Haptic * haptic);
33 
34 
35 /**
36  * @brief The entry point of this force feedback demo.
37  * @param[in] argc Number of arguments.
38  * @param[in] argv Array of argc arguments.
39  */
40 int
41 main(int argc, char **argv)
42 {
43  int i;
44  char *name;
45  int index;
46  SDL_HapticEffect efx[9];
47  int id[9];
48  int nefx;
49  unsigned int supported;
50 
51  /* Enable standard application logging */
53 
54  name = NULL;
55  index = -1;
56  if (argc > 1) {
57  name = argv[1];
58  if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
59  SDL_Log("USAGE: %s [device]\n"
60  "If device is a two-digit number it'll use it as an index, otherwise\n"
61  "it'll use it as if it were part of the device's name.\n",
62  argv[0]);
63  return 0;
64  }
65 
66  i = strlen(name);
67  if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) {
68  index = atoi(name);
69  name = NULL;
70  }
71  }
72 
73  /* Initialize the force feedbackness */
76  SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics());
77  if (SDL_NumHaptics() > 0) {
78  /* We'll just use index or the first force feedback device found */
79  if (name == NULL) {
80  i = (index != -1) ? index : 0;
81  }
82  /* Try to find matching device */
83  else {
84  for (i = 0; i < SDL_NumHaptics(); i++) {
85  if (strstr(SDL_HapticName(i), name) != NULL)
86  break;
87  }
88 
89  if (i >= SDL_NumHaptics()) {
90  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n",
91  name);
92  return 1;
93  }
94  }
95 
97  if (haptic == NULL) {
98  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
99  SDL_GetError());
100  return 1;
101  }
102  SDL_Log("Device: %s\n", SDL_HapticName(i));
104  } else {
105  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n");
106  return 1;
107  }
108 
109  /* We only want force feedback errors. */
110  SDL_ClearError();
111 
112  /* Create effects. */
113  memset(&efx, 0, sizeof(efx));
114  nefx = 0;
115  supported = SDL_HapticQuery(haptic);
116 
117  SDL_Log("\nUploading effects\n");
118  /* First we'll try a SINE effect. */
119  if (supported & SDL_HAPTIC_SINE) {
120  SDL_Log(" effect %d: Sine Wave\n", nefx);
121  efx[nefx].type = SDL_HAPTIC_SINE;
122  efx[nefx].periodic.period = 1000;
123  efx[nefx].periodic.magnitude = -0x2000; /* Negative magnitude and ... */
124  efx[nefx].periodic.phase = 18000; /* ... 180 degrees phase shift => cancel eachother */
125  efx[nefx].periodic.length = 5000;
126  efx[nefx].periodic.attack_length = 1000;
127  efx[nefx].periodic.fade_length = 1000;
128  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
129  if (id[nefx] < 0) {
130  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
131  abort_execution();
132  }
133  nefx++;
134  }
135  /* Now we'll try a SAWTOOTHUP */
136  if (supported & SDL_HAPTIC_SAWTOOTHUP) {
137  SDL_Log(" effect %d: Sawtooth Up\n", nefx);
138  efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP;
139  efx[nefx].periodic.period = 500;
140  efx[nefx].periodic.magnitude = 0x5000;
141  efx[nefx].periodic.length = 5000;
142  efx[nefx].periodic.attack_length = 1000;
143  efx[nefx].periodic.fade_length = 1000;
144  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
145  if (id[nefx] < 0) {
146  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
147  abort_execution();
148  }
149  nefx++;
150  }
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;
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 
170  /* The cute spring effect. */
171  if (supported & SDL_HAPTIC_SPRING) {
172  SDL_Log(" effect %d: Condition Spring\n", nefx);
173  efx[nefx].type = SDL_HAPTIC_SPRING;
174  efx[nefx].condition.length = 5000;
175  for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
176  efx[nefx].condition.right_sat[i] = 0xFFFF;
177  efx[nefx].condition.left_sat[i] = 0xFFFF;
178  efx[nefx].condition.right_coeff[i] = 0x2000;
179  efx[nefx].condition.left_coeff[i] = 0x2000;
180  efx[nefx].condition.center[i] = 0x1000; /* Displace the center for it to move. */
181  }
182  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
183  if (id[nefx] < 0) {
184  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
185  abort_execution();
186  }
187  nefx++;
188  }
189  /* The interesting damper effect. */
190  if (supported & SDL_HAPTIC_DAMPER) {
191  SDL_Log(" effect %d: Condition Damper\n", nefx);
192  efx[nefx].type = SDL_HAPTIC_DAMPER;
193  efx[nefx].condition.length = 5000;
194  for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
195  efx[nefx].condition.right_sat[i] = 0xFFFF;
196  efx[nefx].condition.left_sat[i] = 0xFFFF;
197  efx[nefx].condition.right_coeff[i] = 0x2000;
198  efx[nefx].condition.left_coeff[i] = 0x2000;
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  /* The pretty awesome inertia effect. */
208  if (supported & SDL_HAPTIC_INERTIA) {
209  SDL_Log(" effect %d: Condition Inertia\n", nefx);
210  efx[nefx].type = SDL_HAPTIC_INERTIA;
211  efx[nefx].condition.length = 5000;
212  for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
213  efx[nefx].condition.right_sat[i] = 0xFFFF;
214  efx[nefx].condition.left_sat[i] = 0xFFFF;
215  efx[nefx].condition.right_coeff[i] = 0x2000;
216  efx[nefx].condition.left_coeff[i] = 0x2000;
217  efx[nefx].condition.deadband[i] = 0x1000; /* 1/16th of axis-range around the center is 'dead'. */
218  }
219  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
220  if (id[nefx] < 0) {
221  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
222  abort_execution();
223  }
224  nefx++;
225  }
226  /* The hot friction effect. */
227  if (supported & SDL_HAPTIC_FRICTION) {
228  SDL_Log(" effect %d: Condition Friction\n", nefx);
229  efx[nefx].type = SDL_HAPTIC_FRICTION;
230  efx[nefx].condition.length = 5000;
231  for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
232  efx[nefx].condition.right_sat[i] = 0xFFFF;
233  efx[nefx].condition.left_sat[i] = 0xFFFF;
234  efx[nefx].condition.right_coeff[i] = 0x2000;
235  efx[nefx].condition.left_coeff[i] = 0x2000;
236  }
237  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
238  if (id[nefx] < 0) {
239  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
240  abort_execution();
241  }
242  nefx++;
243  }
244 
245  /* Now we'll try a ramp effect */
246  if (supported & SDL_HAPTIC_RAMP) {
247  SDL_Log(" effect %d: Ramp\n", nefx);
248  efx[nefx].type = SDL_HAPTIC_RAMP;
250  efx[nefx].ramp.direction.dir[0] = 1; /* Force comes from */
251  efx[nefx].ramp.direction.dir[1] = -1; /* the north-east. */
252  efx[nefx].ramp.length = 5000;
253  efx[nefx].ramp.start = 0x4000;
254  efx[nefx].ramp.end = -0x4000;
255  efx[nefx].ramp.attack_length = 1000;
256  efx[nefx].ramp.fade_length = 1000;
257  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
258  if (id[nefx] < 0) {
259  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
260  abort_execution();
261  }
262  nefx++;
263  }
264 
265  /* Finally we'll try a left/right effect. */
266  if (supported & SDL_HAPTIC_LEFTRIGHT) {
267  SDL_Log(" effect %d: Left/Right\n", nefx);
268  efx[nefx].type = SDL_HAPTIC_LEFTRIGHT;
269  efx[nefx].leftright.length = 5000;
270  efx[nefx].leftright.large_magnitude = 0x3000;
271  efx[nefx].leftright.small_magnitude = 0xFFFF;
272  id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
273  if (id[nefx] < 0) {
274  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
275  abort_execution();
276  }
277  nefx++;
278  }
279 
280 
281  SDL_Log
282  ("\nNow playing effects for 5 seconds each with 1 second delay between\n");
283  for (i = 0; i < nefx; i++) {
284  SDL_Log(" Playing effect %d\n", i);
285  SDL_HapticRunEffect(haptic, id[i], 1);
286  SDL_Delay(6000); /* Effects only have length 5000 */
287  }
288 
289  /* Quit */
290  if (haptic != NULL)
292  SDL_Quit();
293 
294  return 0;
295 }
296 
297 
298 /*
299  * Cleans up a bit.
300  */
301 static void
303 {
304  SDL_Log("\nAborting program execution.\n");
305 
307  SDL_Quit();
308 
309  exit(1);
310 }
311 
312 
313 /*
314  * Displays information about the haptic device.
315  */
316 static void
318 {
319  unsigned int supported;
320 
321  supported = SDL_HapticQuery(haptic);
322  SDL_Log(" Supported effects [%d effects, %d playing]:\n",
324  if (supported & SDL_HAPTIC_CONSTANT)
325  SDL_Log(" constant\n");
326  if (supported & SDL_HAPTIC_SINE)
327  SDL_Log(" sine\n");
328  /* !!! FIXME: put this back when we have more bits in 2.1 */
329  /* if (supported & SDL_HAPTIC_SQUARE)
330  SDL_Log(" square\n"); */
331  if (supported & SDL_HAPTIC_TRIANGLE)
332  SDL_Log(" triangle\n");
333  if (supported & SDL_HAPTIC_SAWTOOTHUP)
334  SDL_Log(" sawtoothup\n");
335  if (supported & SDL_HAPTIC_SAWTOOTHDOWN)
336  SDL_Log(" sawtoothdown\n");
337  if (supported & SDL_HAPTIC_RAMP)
338  SDL_Log(" ramp\n");
339  if (supported & SDL_HAPTIC_FRICTION)
340  SDL_Log(" friction\n");
341  if (supported & SDL_HAPTIC_SPRING)
342  SDL_Log(" spring\n");
343  if (supported & SDL_HAPTIC_DAMPER)
344  SDL_Log(" damper\n");
345  if (supported & SDL_HAPTIC_INERTIA)
346  SDL_Log(" inertia\n");
347  if (supported & SDL_HAPTIC_CUSTOM)
348  SDL_Log(" custom\n");
349  if (supported & SDL_HAPTIC_LEFTRIGHT)
350  SDL_Log(" left/right\n");
351  SDL_Log(" Supported capabilities:\n");
352  if (supported & SDL_HAPTIC_GAIN)
353  SDL_Log(" gain\n");
354  if (supported & SDL_HAPTIC_AUTOCENTER)
355  SDL_Log(" autocenter\n");
356  if (supported & SDL_HAPTIC_STATUS)
357  SDL_Log(" status\n");
358 }
359 
360 #else
361 
362 int
363 main(int argc, char *argv[])
364 {
365  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Haptic support.\n");
366  exit(1);
367 }
368 
369 #endif
Uint16 deadband[3]
Definition: SDL_haptic.h:611
#define SDL_ClearError
#define SDL_GetError
#define SDL_HapticNewEffect
#define SDL_HAPTIC_AUTOCENTER
Device can set autocenter.
Definition: SDL_haptic.h:280
#define SDL_INIT_JOYSTICK
Definition: SDL.h:79
#define SDL_HAPTIC_GAIN
Device can set global gain.
Definition: SDL_haptic.h:271
#define SDL_HAPTIC_CUSTOM
Custom effect is supported.
Definition: SDL_haptic.h:258
#define SDL_HAPTIC_TRIANGLE
Triangle wave effect supported.
Definition: SDL_haptic.h:184
static void HapticPrintSupported(SDL_Haptic *haptic)
Definition: testhaptic.c:317
#define SDL_HAPTIC_INERTIA
Inertia effect supported - uses axes acceleration.
Definition: SDL_haptic.h:241
SDL_HapticRamp ramp
Definition: SDL_haptic.h:796
#define SDL_HapticOpen
#define memset
Definition: SDL_malloc.c:619
int main(int argc, char **argv)
The entry point of this force feedback demo.
Definition: testhaptic.c:41
Sint16 left_coeff[3]
Definition: SDL_haptic.h:610
Uint16 right_sat[3]
Definition: SDL_haptic.h:607
Sint16 right_coeff[3]
Definition: SDL_haptic.h:609
#define SDL_HAPTIC_SINE
Sine wave effect supported.
Definition: SDL_haptic.h:161
#define SDL_HapticClose
#define SDL_HapticRunEffect
GLuint const GLchar * name
#define SDL_LogError
#define SDL_HAPTIC_CARTESIAN
Uses cartesian coordinates for the direction.
Definition: SDL_haptic.h:319
SDL_HapticCondition condition
Definition: SDL_haptic.h:795
#define SDL_Log
The generic template for any haptic effect.
Definition: SDL_haptic.h:789
#define SDL_HAPTIC_CONSTANT
Constant effect supported.
Definition: SDL_haptic.h:152
#define SDL_HapticName
#define SDL_Quit
#define SDL_HAPTIC_POLAR
Uses polar coordinates for the direction.
Definition: SDL_haptic.h:312
SDL_HapticConstant constant
Definition: SDL_haptic.h:793
static void abort_execution(void)
Definition: testhaptic.c:302
SDL_HapticDirection direction
Definition: SDL_haptic.h:632
#define SDL_HapticNumAxes
GLuint index
#define SDL_Delay
Uint16 attack_length
Definition: SDL_haptic.h:647
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define SDL_LogSetPriority
Uint16 fade_length
Definition: SDL_haptic.h:649
#define NULL
Definition: begin_code.h:164
static SDL_Haptic * haptic
Definition: testhaptic.c:25
#define SDL_HAPTIC_STATUS
Device can be queried for effect status.
Definition: SDL_haptic.h:289
#define SDL_INIT_TIMER
Definition: SDL.h:76
#define SDL_HapticNumEffectsPlaying
SDL_HapticLeftRight leftright
Definition: SDL_haptic.h:797
#define SDL_HAPTIC_RAMP
Ramp effect supported.
Definition: SDL_haptic.h:211
#define SDL_HAPTIC_SPRING
Spring effect supported - uses axes position.
Definition: SDL_haptic.h:221
#define SDL_NumHaptics
#define SDL_Init
#define SDL_HAPTIC_SAWTOOTHUP
Sawtoothup wave effect supported.
Definition: SDL_haptic.h:193
#define SDL_INIT_HAPTIC
Definition: SDL.h:80
#define SDL_HapticNumEffects
#define SDL_HAPTIC_LEFTRIGHT
Left/Right effect supported.
Definition: SDL_haptic.h:172
SDL_HapticPeriodic periodic
Definition: SDL_haptic.h:794
#define SDL_HAPTIC_FRICTION
Friction effect supported - uses axes movement.
Definition: SDL_haptic.h:251
#define SDL_HAPTIC_SAWTOOTHDOWN
Sawtoothdown wave effect supported.
Definition: SDL_haptic.h:202
#define SDL_HapticQuery
#define SDL_INIT_VIDEO
Definition: SDL.h:78
SDL_HapticDirection direction
Definition: SDL_haptic.h:461
#define SDL_HAPTIC_DAMPER
Damper effect supported - uses axes velocity.
Definition: SDL_haptic.h:231
Uint16 left_sat[3]
Definition: SDL_haptic.h:608