2 Copyright (c) 2008, Edgar Simo Serra
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
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.
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.
18 #include <string.h> /* strstr */
19 #include <ctype.h> /* isdigit */
23 #ifndef SDL_HAPTIC_DISABLED
25 static SDL_Haptic *haptic;
31 static void abort_execution(void);
32 static void HapticPrintSupported(SDL_Haptic * haptic);
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.
41 main(int argc, char **argv)
46 SDL_HapticEffect efx[9];
49 unsigned int supported;
51 /* Enable standard application logging */
52 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
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",
67 if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) {
73 /* Initialize the force feedbackness */
74 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
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 */
80 i = (index != -1) ? index : 0;
82 /* Try to find matching device */
84 for (i = 0; i < SDL_NumHaptics(); i++) {
85 if (strstr(SDL_HapticName(i), name) != NULL)
89 if (i >= SDL_NumHaptics()) {
90 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n",
96 haptic = SDL_HapticOpen(i);
98 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
102 SDL_Log("Device: %s\n", SDL_HapticName(i));
103 HapticPrintSupported(haptic);
105 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n");
109 /* We only want force feedback errors. */
112 /* Create effects. */
113 memset(&efx, 0, sizeof(efx));
115 supported = SDL_HapticQuery(haptic);
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]);
130 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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]);
146 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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]);
164 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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. */
182 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
184 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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;
200 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
202 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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'. */
219 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
221 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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;
237 id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
239 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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;
249 efx[nefx].ramp.direction.type = SDL_HAPTIC_CARTESIAN;
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]);
259 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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]);
274 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
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 */
291 SDL_HapticClose(haptic);
302 abort_execution(void)
304 SDL_Log("\nAborting program execution.\n");
306 SDL_HapticClose(haptic);
314 * Displays information about the haptic device.
317 HapticPrintSupported(SDL_Haptic * haptic)
319 unsigned int supported;
321 supported = SDL_HapticQuery(haptic);
322 SDL_Log(" Supported effects [%d effects, %d playing]:\n",
323 SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic));
324 if (supported & SDL_HAPTIC_CONSTANT)
325 SDL_Log(" constant\n");
326 if (supported & SDL_HAPTIC_SINE)
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)
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)
354 if (supported & SDL_HAPTIC_AUTOCENTER)
355 SDL_Log(" autocenter\n");
356 if (supported & SDL_HAPTIC_STATUS)
357 SDL_Log(" status\n");
363 main(int argc, char *argv[])
365 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Haptic support.\n");