comparison src/haptic/darwin/SDL_syshaptic.c @ 2520:6aee9eb4fc6d gsoc2008_force_feedback

Adding initial darwin port of haptic subsystem - broken atm.
author Edgar Simo <bobbens@gmail.com>
date Tue, 15 Jul 2008 16:35:14 +0000
parents
children 7aa91c21ce5f
comparison
equal deleted inserted replaced
2519:af9df9662807 2520:6aee9eb4fc6d
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 2008 Edgar Simo
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #ifdef SDL_HAPTIC_IOKIT
25
26 #include "SDL_haptic.h"
27 #include "../SDL_syshaptic.h"
28 #include "SDL_joystick.h"
29 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
30 /*#include "../../joystick/dawrin/SDL_sysjoystick_c.h"*/ /* For joystick hwdata */
31
32 #include <ForceFeedback/ForceFeedback.h>
33 #include <ForceFeedback/ForceFeedbackConstants.h>
34
35
36 #define MAX_HAPTICS 32
37
38
39 /*
40 * List of available haptic devices.
41 */
42 static struct
43 {
44 io_service_t dev;
45 SDL_Haptic *haptic;
46 } SDL_hapticlist[MAX_HAPTICS];
47
48
49 /*
50 * Haptic system hardware data.
51 */
52 struct haptic_hwdata
53 {
54 FFDeviceObjectReference device; /* Hardware device. */
55 };
56
57
58 /*
59 * Haptic system effect data.
60 */
61 struct haptic_hweffect
62 {
63 FFEffectObjectReference ref; /* Reference. */
64 struct FFEFFECT effect; /* Hardware effect. */
65 };
66
67
68 /*
69 * Initializes the haptic subsystem.
70 */
71 int
72 SDL_SYS_HapticInit(void)
73 {
74 int numhaptics;
75 IOReturn result;
76 io_iterator_t iter;
77 CFDictionaryRef match;
78 io_sercive_t device;
79
80 /* Get HID devices. */
81 match = IOServiceMatching(kIOHIDDeviceKey);
82 if (match == NULL) {
83 SDL_SetError("Haptic: Failed to get IOServiceMatching.");
84 return -1;
85 }
86
87 /* Now search I/O Registry for matching devices. */
88 result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter);
89 if (result != kIOReturnSuccess) {
90 SDL_SetError("Haptic: Couldn't create a HID object iterator.");
91 return -1;
92 }
93 /* IOServiceGetMatchingServices consumes dictionary. */
94
95 numhaptics = 0;
96 while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
97
98 /* Check for force feedback. */
99 if (FFIsForceFeedback(device) == FF_OK) {
100 SDL_hapticlist[numhaptics].dev = device;
101 SDL_hapticlist[numhaptics].haptic = NULL;
102 numhaptics++;
103 }
104
105 /* Reached haptic limit. */
106 if (numhaptics >= MAX_HAPTICS)
107 break;
108 }
109 IOObjectRelease(iter);
110
111 return numhaptics;
112 }
113
114
115 /*
116 * Return the name of a haptic device, does not need to be opened.
117 */
118 const char *
119 SDL_SYS_HapticName(int index)
120 {
121 return NULL;
122 }
123
124
125 #define FF_TEST(ff, s) \
126 if (features.supportedEffects & ff) supported |= s
127 /*
128 * Gets supported features.
129 */
130 static unsigned int
131 GetSupportedFeatures(FFDeviceObjectReference device,
132 int *neffects, int *nplaying)
133 {
134 HRESULT ret;
135 FFCAPABILITIES features;
136 unsigned int supported;
137 Uint32 val;
138
139 ret = FFDeviceGetForceFeedbackCapabilities(device, &features);
140 if (ret != FF_OK) {
141 SDL_SetError("Haptic: Unable to get device's supported features.");
142 return 0;
143 }
144
145 supported = 0;
146
147 /* Get maximum effects. */
148 *neffects = features.storageCapacity;
149 *nplaying = features.playbackCapacity;
150
151 /* Test for effects. */
152 FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT);
153 FF_TEST(FFCAP_ET_RAMPFORCE, SDL_HAPTIC_RAMP);
154 FF_TEST(FFCAP_ET_SQUARE, SDL_HAPTIC_SQUARE);
155 FF_TEST(FFCAP_ET_SINE, SDL_HAPTIC_SINE);
156 FF_TEST(FFCAP_ET_TRIANGLE, SDL_HAPTIC_TRIANGLE);
157 FF_TEST(FFCAP_ET_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHUP);
158 FF_TEST(FFCAP_ET_SAWTOOTHDOWN, SDL_HAPTIC_SAWTOOTHDOWN);
159 FF_TEST(FFCAP_ET_SPRING, SDL_HAPTIC_SPRING);
160 FF_TEST(FFCAP_ET_DAMPER, SDL_HAPTIC_DAMPER);
161 FF_TEST(FFCAP_ET_INERTIA, SDL_HAPTIC_INERTIA);
162 FF_TEST(FFCAP_ET_FRICTION, SDL_HAPTIC_FRICTION);
163 FF_TEST(FFCAP_ET_CUSTOMFORCE, SDL_HAPTIC_CUSTOM);
164
165 /* Check if supports gain. */
166 ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFGAIN,
167 val, sizeof(val));
168 if (ret == FF_OK) supported |= SDL_HAPTIC_GAIN;
169 else if (ret != FFERR_UNSUPPORTED) {
170 SDL_SetError("Haptic: Unable to get if device supports gain.");
171 return 0;
172 }
173
174 /* Checks if supports autocenter. */
175 ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFAUTOCENTER,
176 val, sizeof(val));
177 if (ret == FF_OK) supported |= SDL_HAPTIC_AUTOCENTER;
178 else if (ret != FFERR_UNSUPPORTED) {
179 SDL_SetError("Haptic: Unable to get if device supports autocenter.");
180 return 0;
181 }
182
183 /* Always supported features. */
184 supported |= SDL_HAPTIC_STATUS;
185 return supported;
186 }
187
188
189 /*
190 * Opens the haptic device from the file descriptor.
191 */
192 static int
193 SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service)
194 {
195 /* Allocate the hwdata */
196 haptic->hwdata = (struct haptic_hwdata *)
197 SDL_malloc(sizeof(*haptic->hwdata));
198 if (haptic->hwdata == NULL) {
199 SDL_OutOfMemory();
200 goto creat_err;
201 }
202 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
203
204 /* Open the device */
205 if (FFCreateDevice( &service, &haptic->hwdata->device ) != FF_OK) {
206 SDL_SetError("Haptic: Unable to create device from service.");
207 goto creat_err;
208 }
209
210 /* Get supported features. */
211 haptic->supported = GetSupportedFeatures(haptic->hwdata->device,
212 &haptic->neffects, &haptic->nplaying);
213 if (haptic->supported == 0) { /* Error since device supports nothing. */
214 goto open_err;
215 }
216 haptic->effects = (struct haptic_effect *)
217 SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
218 if (haptic->effects == NULL) {
219 SDL_OutOfMemory();
220 goto open_err;
221 }
222 /* Clear the memory */
223 SDL_memset(haptic->effects, 0,
224 sizeof(struct haptic_effect) * haptic->neffects);
225
226 return 0;
227
228 /* Error handling */
229 open_err:
230 FFReleaseDevice(haptic->hwdata->device);
231 creat_err:
232 if (haptic->hwdata != NULL) {
233 free(haptic->hwdata);
234 haptic->hwdata = NULL;
235 }
236 return -1;
237
238 }
239
240
241 /*
242 * Opens a haptic device for usage.
243 */
244 int
245 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
246 {
247 return SDL_SYS_HapticOpenFromService(haptic,
248 SDL_hapticlist[haptic->index].device);
249 }
250
251
252 /*
253 * Opens a haptic device from first mouse it finds for usage.
254 */
255 int
256 SDL_SYS_HapticMouse(void)
257 {
258 return -1;
259 }
260
261
262 /*
263 * Checks to see if a joystick has haptic features.
264 */
265 int
266 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
267 {
268 return SDL_FALSE;
269 }
270
271
272 /*
273 * Checks to see if the haptic device and joystick and in reality the same.
274 */
275 int
276 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
277 {
278 if (SDL_strcmp(joystick->name,haptic->name)==0) {
279 return 1;
280 }
281 return 0;
282 }
283
284
285 /*
286 * Opens a SDL_Haptic from a SDL_Joystick.
287 */
288 int
289 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
290 {
291 return -1;
292 }
293
294
295 /*
296 * Closes the haptic device.
297 */
298 void
299 SDL_SYS_HapticClose(SDL_Haptic * haptic)
300 {
301 int i;
302
303 if (haptic->hwdata) {
304
305 /* Clean up */
306 FFReleaseDevice(haptic->hwdata->device);
307
308 /* Free */
309 SDL_free(haptic->hwdata);
310 haptic->hwdata = NULL;
311 for (i=0; i<haptic->neffects; i++) {
312 if (haptic->effects[i].hweffect != NULL)
313 SDL_free(haptic->effects[i].hweffect->effect.lpvTypeSpecificParams);
314 }
315 SDL_free(haptic->effects);
316 haptic->neffects = 0;
317 }
318 }
319
320
321 /*
322 * Clean up after system specific haptic stuff
323 */
324 void
325 SDL_SYS_HapticQuit(void)
326 {
327 int i;
328
329 for (i=0; i < SDL_numhaptics; i++) {
330 IOObjectRelease(SDL_hapticlist[i].dev);
331 /* TODO free effects. */
332 }
333 }
334
335
336 /*
337 * Sets the direction.
338 */
339 static int
340 SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int axes )
341 {
342 LONG *dir;
343 dir = SDL_malloc( sizeof(LONG) * axes );
344 if (dir == NULL) {
345 SDL_OutOfMemory();
346 return -1;
347 }
348 SDL_memset( dir, 0, sizeof(LONG) * axes );
349 effect->rglDirection = dir;
350
351 switch (dir->type) {
352 case SDL_HAPTIC_POLAR:
353 effect->dwFlags |= FFEFF_POLAR;
354 dir[0] = dir->dir[0];
355 return 0;
356 case SDL_HAPTIC_CARTESIAN:
357 effects->dwFlags |= FFEFF_CARTESIAN;
358 dir[0] = dir->dir[0];
359 dir[1] = dir->dir[1];
360 dir[2] = dir->dir[2];
361 return 0;
362 case SDL_HAPTIC_SHPERICAL:
363 effects->dwFlags |= FFEFF_SPHERICAL;
364 dir[0] = dir->dir[0];
365 dir[1] = dir->dir[1];
366 dir[2] = dir->dir[2];
367 return 0;
368
369 default:
370 SDL_SetError("Haptic: Unknown direction type.");
371 return -1;
372 }
373 }
374
375 #define CONVERT(x) (((x)*10000) / 0xFFFF )
376 /*
377 * Creates the FFStruct
378 */
379 static int
380 SDL_SYS_ToFFEFFECT( FFEFFECT * dest, SDL_HapticEffect * src )
381 {
382 FFCONSTANTFORCE *constant;
383 FFPERIODIC *periodic;
384 FFCONDITION *condition;
385 FFRAMPFORCE *ramp;
386 FFCUSTOMFORCE *custom;
387 SDL_HapticConstant *hap_constant;
388 SDL_HapticPeriodic *hap-periodic;
389 SDL_HapticCondition *hap_condition;
390 SDL_HapticRamp *hap_ramp;
391
392 /* Set global stuff. */
393 SDL_memset(dest, 0, sizeof(FFEFFECT));
394 dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */
395 dest->dwSamplePeriod = 0; /* Not used by us. */
396 dest->dwGain = 10000; /* Gain is set globally, not locally. */
397 dest->lpEnvelope.dwSize = sizeof(FFENVELOPE); /* Always should be this. */
398
399 switch (src->type) {
400 case SDL_HAPTIC_CONSTANT:
401 hap_constant = &src->constant;
402 constant = SDL_malloc( sizeof(FFCONSTANTFORCE) );
403
404 /* Specifics */
405 constant->lMagnitude = CONVERT(hap_constant->level);
406 dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE);
407 dest->lpvTypeSpecificParams = constant;
408
409 /* Generics */
410 dest->dwDuration = src->length * 1000; /* In microseconds. */
411 dest->dwTriggerButton = FFJOFS_BUTTON(hap_constant->button);
412 dest->dwTriggerRepeatInterval = hap_constant->interval;
413 dest->dwStartDelay = src->delay * 1000; /* In microseconds. */
414
415 /* Axes */
416 dest->cAxes = 2; /* TODO handle */
417 dest->rgdwAxes = 0;
418
419 /* Direction. */
420 if (SDL_SYS_SetDirection(dest, hap_constant->direction, dest->cAxes) < 0) {
421 return -1;
422 }
423
424 /* Envelope */
425 dest->lpEnvelope.dwAttackLevel = CONVERT(hap_constant->attack_level);
426 dest->lpEnvelope.dwAttackTime = hap_constant->attack_length * 1000;
427 dest->lpEnvelope.dwFadeLevel = CONVERT(hap_constant->fade_level);
428 dest->lpEnvelope.dwFadeTime = hap_constant->fade_length * 1000;
429
430 break;
431
432 /* TODO finish */
433
434 case SDL_HAPTIC_SINE:
435 case SDL_HAPTIC_SQUARE:
436 case SDL_HAPTIC_TRIANGLE:
437 case SDL_HAPTIC_SAWTOOTHUP:
438 case SDL_HAPTIC_SAWTOOTHDOWN:
439 periodic = &src->periodic;
440
441 break;
442
443 case SDL_HAPTIC_SPRING:
444 case SDL_HAPTIC_DAMPER:
445 case SDL_HAPTIC_INERTIA:
446 case SDL_HAPTIC_FRICTION:
447 condition = &src->condition;
448
449 break;
450
451 case SDL_HAPTIC_RAMP:
452 ramp = &src->ramp;
453
454 break;
455
456
457 default:
458 SDL_SetError("Haptic: Unknown effect type.");
459 return -1;
460 }
461
462 return 0;
463 }
464
465
466 /*
467 * Gets the effect type from the generic SDL haptic effect wrapper.
468 */
469 CFUUIDRef SDL_SYS_HapticEffectType(struct haptic_effect * effect)
470 {
471 switch (effect->effect->type) {
472 case SDL_HAPTIC_CONSTANT:
473 return kFFEffectType_ConstantForce_ID;
474
475 case SDL_HAPTIC_RAMP:
476 return kFFEffectType_RampForce_ID;
477
478 case SDL_HAPTIC_SQUARE:
479 return kFFEffectType_Square_ID;
480
481 case SDL_HAPTIC_SINE:
482 return kFFEffectType_Sine_ID;
483
484 case SDL_HAPTIC_TRIANGLE;
485 return kFFEffectType_Triangle_ID;
486
487 case SDL_HAPTIC_SAWTOOTHUP:
488 return kFFEffectType_SawtoothUp_ID;
489
490 case SDL_HAPTIC_SAWTOOTHDOWN:
491 return kFFEffectType_SawtoothDown_ID;
492
493 case SDL_HAPTIC_SPRING:
494 return kFFEffectType_Spring_ID;
495
496 case SDL_HAPTIC_DAMPER:
497 return kFFEffectType_Damper_ID;
498
499 case SDL_HAPTIC_INERTIA:
500 return kFFEffectType_Inertia_ID;
501
502 case SDL_HAPTIC_FRICTION:
503 return kFFEffectType_Friction_ID;
504
505 case SDL_HAPTIC_CUSTOM:
506 return kFFEffectType_CustomForce_ID;
507
508 default:
509 SDL_SetError("Haptic: Unknown effect type.");
510 return NULL;
511 }
512 }
513
514
515 /*
516 * Creates a new haptic effect.
517 */
518 int
519 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
520 SDL_HapticEffect * base)
521 {
522 HRESULT ret;
523 CFUUIDRef type;
524
525 /* Alloc the effect. */
526 effect->hweffect = (struct haptic_hweffect *)
527 SDL_malloc(sizeof(struct haptic_hweffect));
528 if (effect->hweffect == NULL) {
529 SDL_OutOfMemory();
530 return -1;
531 }
532
533 /* Get the type. */
534 type = SDL_SYS_HapticEffectType(effect);
535 if (type == NULL) {
536 SDL_free(effect->hweffect);
537 effect->hweffect = NULL;
538 return -1;
539 }
540
541 /* Get the effect. */
542 if (SDL_SYS_ToFFEFFECT( &effect->hweffect->effect, &haptic_effect->effect ) < 0) {
543 /* TODO cleanup alloced stuff. */
544 return -1;
545 }
546
547 ret = FFDeviceCreateEffect( haptic->hwdata->device, type,
548 &effect->hweffect->effect, &effect->hweffect->ref );
549 }
550
551
552 /*
553 * Updates an effect.
554 */
555 int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
556 struct haptic_effect * effect, SDL_HapticEffect * data)
557 {
558 /* TODO */
559 return -1;
560 }
561
562
563 /*
564 * Runs an effect.
565 */
566 int
567 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
568 Uint32 iterations)
569 {
570 HRESULT ret;
571 Uint32 iter;
572
573 /* Check if it's infinite. */
574 if (iterations == SDL_HAPTIC_INFINITY) {
575 iter = INFINITE;
576 }
577 else
578 iter = iterations;
579
580 /* Run the effect. */
581 ret = FFEffectStart(effect->hweffect->ref, iter, 0);
582 if (ret != FF_OK) {
583 SDL_SetError("Haptic: Unable to run the effect.");
584 return -1;
585 }
586
587 return 0;
588 }
589
590
591 /*
592 * Stops an effect.
593 */
594 int
595 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
596 {
597 HRESULT ret;
598
599 ret = FFEffectStop(effect->hweffect->ref);
600 if (ret != FF_OK) {
601 SDL_SetError("Haptic: Unable to stop the effect.");
602 return -1;
603 }
604
605 return 0;
606 }
607
608
609 /*
610 * Frees the effect.
611 */
612 void
613 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
614 {
615 HRESULT ret;
616
617 ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref);
618 if (ret != FF_OK) {
619 SDL_SetError("Haptic: Error removing the effect from the device.");
620 }
621 SDL_free(effect->hweffect->effect.lpvTypeSpecificParams);
622 effect->hweffect->effect.lpvTypeSpecificParams = NULL;
623 SDL_free(effect->hweffect);
624 effect->hweffect = NULL;
625 }
626
627
628 /*
629 * Gets the status of a haptic effect.
630 */
631 int
632 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect)
633 {
634 HRESULT ret;
635 FFEffectStatusFlag status;
636
637 ret = FFEffectGetEffectStatus(effect->hweffect.ref, &status);
638 if (ret != FF_OK) {
639 SDL_SetError("Haptic: Unable to get effect status.");
640 return -1;
641 }
642
643 if (status == 0) return SDL_FALSE;
644 return SDL_TRUE; /* Assume it's playing or emulated. */
645 }
646
647
648 /*
649 * Sets the gain.
650 */
651 int
652 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
653 {
654 HRESULT ret;
655 Uint32 val;
656
657 val = gain * 100; /* Mac OS X uses 0 to 10,000 */
658 ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_FFGAIN, &val);
659 if (ret != FF_OK) {
660 SDL_SetError("Haptic: Error setting gain.");
661 return -1;
662 }
663
664 return 0;
665 }
666
667
668 /*
669 * Sets the autocentering.
670 */
671 int
672 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
673 {
674 HRESULT ret;
675 Uint32 val;
676
677 /* Mac OS X only has 0 (off) and 1 (on) */
678 if (autocenter == 0) val = 0;
679 else val = 1;
680
681 ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
682 FFPROP_FFAUTOCENTER, &val);
683 if (ret != FF_OK) {
684 SDL_SetError("Haptic: Error setting autocenter.");
685 return -1;
686 }
687
688 return 0;
689
690 }
691
692
693 #endif /* SDL_HAPTIC_LINUX */