changeset 2472:3f73c88c9abb gsoc2008_force_feedback

First commit of the SDL_haptic subsystem. Code compiles and works, very limited functionality (linux only).
author Edgar Simo <bobbens@gmail.com>
date Sun, 01 Jun 2008 11:44:25 +0000
parents 910af9032c73
children 20730743769d
files configure.in include/SDL.h include/SDL_haptic.h src/SDL.c src/haptic/SDL_haptic.c src/haptic/SDL_haptic_c.h src/haptic/SDL_syshaptic.h src/haptic/linux/SDL_syshaptic.c
diffstat 8 files changed, 521 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/configure.in	Wed Apr 23 06:26:07 2008 +0000
+++ b/configure.in	Sun Jun 01 11:44:25 2008 +0000
@@ -235,6 +235,14 @@
 else
     SOURCES="$SOURCES $srcdir/src/joystick/*.c"
 fi
+AC_ARG_ENABLE(haptic,
+AC_HELP_STRING([--enable-haptic], [Enable the haptic (force feedback) subsystem [[default=yes]]]),
+              , enable_haptic=yes)
+if test x$enable_haptic != xyes; then
+    AC_DEFINE(SDL_HAPTIC_DISABLE)
+else
+    SOURCES="$SOURCES $srcdir/src/haptic/*.c"
+fi
 AC_ARG_ENABLE(cdrom,
 AC_HELP_STRING([--enable-cdrom], [Enable the cdrom subsystem [[default=yes]]]),
               , enable_cdrom=yes)
@@ -2176,6 +2184,16 @@
             ;;
           esac
         fi
+        # Set up files for the haptic library
+        if test x$enable_haptic = xyes; then
+          case $ARCH in
+            linux)
+                AC_DEFINE(SDL_HAPTIC_LINUX)
+                SOURCES="$SOURCES $srcdir/src/haptic/linux/*.c"
+                have_haptic=yes
+            ;;
+          esac
+        fi
         # Set up files for the cdrom library
         if test x$enable_cdrom = xyes; then
           case $ARCH in
--- a/include/SDL.h	Wed Apr 23 06:26:07 2008 +0000
+++ b/include/SDL.h	Sun Jun 01 11:44:25 2008 +0000
@@ -109,6 +109,7 @@
 #define SDL_INIT_VIDEO		0x00000020
 #define SDL_INIT_CDROM		0x00000100
 #define SDL_INIT_JOYSTICK	0x00000200
+#define SDL_INIT_HAPTIC    0x00001000
 #define SDL_INIT_NOPARACHUTE	0x00100000      /* Don't catch fatal signals */
 #define SDL_INIT_EVENTTHREAD	0x01000000      /* Not supported on all OS's */
 #define SDL_INIT_EVERYTHING	0x0000FFFF
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/SDL_haptic.h	Sun Jun 01 11:44:25 2008 +0000
@@ -0,0 +1,87 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 2008 Edgar Simo
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+/**
+ * \file SDL_haptic.h
+ *
+ * Include file for SDL haptic subsystem
+ */
+
+#ifndef _SDL_haptic_h
+#define _SDL_haptic_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+   /* *INDENT-ON* */                                                         
+#endif
+
+/* The haptic structure used to identify an SDL haptic */
+struct _SDL_Haptic;                                                     
+typedef struct _SDL_Haptic SDL_Haptic;
+
+
+/* Different effects that can be generated */
+#define SDL_HAPTIC_CONSTANT   (1<<0)
+#define SDL_HAPTIC_PERIODIC   (1<<1)
+#define SDL_HAPTIC_RAMP       (1<<2)
+#define SDL_HAPTIC_SPRING     (1<<3)
+#define SDL_HAPTIC_FRICTION   (1<<4)
+#define SDL_HAPTIC_DAMPER     (1<<5)
+#define SDL_HAPTIC_RUMBLE     (1<<6)
+#define SDL_HAPTIC_INERTIA    (1<<7)
+#define SDL_HAPTIC_GAIN       (1<<8)
+#define SDL_HAPTIC_AUTOCENTER (1<<9)
+
+
+/* Function prototypes */
+/*
+ * Count the number of joysticks attached to the system
+ */
+extern DECLSPEC int SDLCALL SDL_NumHaptics(void);
+
+/*
+ * Get the implementation dependent name of a joystick.
+ * This can be called before any joysticks are opened.
+ * If no name can be found, this function returns NULL.
+ */
+extern DECLSPEC const char *SDLCALL SDL_HapticName(int device_index);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_haptic_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
+
--- a/src/SDL.c	Wed Apr 23 06:26:07 2008 +0000
+++ b/src/SDL.c	Sun Jun 01 11:44:25 2008 +0000
@@ -38,6 +38,10 @@
 extern int SDL_JoystickInit(void);
 extern void SDL_JoystickQuit(void);
 #endif
+#if !SDL_HAPTIC_DISABLED
+extern int SDL_HapticInit(void);
+extern int SDL_HapticQuit(void);
+#endif
 #if !SDL_CDROM_DISABLED
 extern int SDL_CDROMInit(void);
 extern void SDL_CDROMQuit(void);
@@ -123,6 +127,22 @@
     }
 #endif
 
+#if !SDL_HAPTIC_DISABLED
+    /* Initialize the haptic subsystem */
+    if ((flags & SDL_INIT_HAPTIC) && !(SDL_initialized & SDL_INIT_HAPTIC)) {
+        if (SDL_HapticInit() < 0) {
+            return (-1);
+        }
+        SDL_initialized |= SDL_INIT_HAPTIC;
+    }
+#else
+    if (flags & SDL_INIT_HAPTIC) {
+        SDL_SetError("SDL not built with haptic (force feedback) support");
+        return (-1);
+    }
+#endif
+
+
 #if !SDL_CDROM_DISABLED
     /* Initialize the CD-ROM subsystem */
     if ((flags & SDL_INIT_CDROM) && !(SDL_initialized & SDL_INIT_CDROM)) {
@@ -180,6 +200,12 @@
         SDL_initialized &= ~SDL_INIT_JOYSTICK;
     }
 #endif
+#if !SDL_HAPTIC_DISABLED
+    if ((flags & SDL_initialized & SDL_INIT_HAPTIC)) {
+        SDL_HapticQuit();
+        SDL_initialized &= ~SDL_INIT_HAPTIC;
+    }
+#endif
 #if !SDL_TIMERS_DISABLED
     if ((flags & SDL_initialized & SDL_INIT_TIMER)) {
         SDL_TimerQuit();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/haptic/SDL_haptic.c	Sun Jun 01 11:44:25 2008 +0000
@@ -0,0 +1,127 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 2008 Edgar Simo
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_haptic_c.h"
+#include "SDL_syshaptic.h"
+
+
+static Uint8 SDL_numhaptics = 0;
+SDL_Haptic **SDL_haptics = NULL;
+static SDL_Haptic *default_haptic = NULL;
+
+
+/*
+ * Initializes the Haptic devices.
+ */
+int
+SDL_HapticInit(void)
+{  
+   int arraylen;
+   int status;
+
+   SDL_numhaptics = 0;
+   status = SDL_SYS_HapticInit();
+   if (status >= 0) {
+      arraylen = (status + 1) * sizeof(*SDL_haptics);
+      SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
+      if (SDL_haptics == NULL) {
+         SDL_numhaptics = 0;
+      } else {
+         SDL_memset(SDL_haptics, 0, arraylen);
+         SDL_numhaptics = status;
+      }
+      status = 0;
+   }
+   default_haptic = NULL;
+
+   return status;
+}
+
+
+/*
+ * Returns the number of available devices.
+ */
+int
+SDL_NumHaptics(void)
+{
+   return SDL_numhaptics;
+}
+
+
+/*
+ * Gets the name of a Haptic device by index.
+ */
+const char *
+SDL_HapticName(int device_index)
+{
+   if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
+      SDL_SetError("There are %d haptic devices available", SDL_numhaptics);
+      return NULL;
+   }
+   return SDL_SYS_HapticName(device_index);
+}
+
+
+/*
+ * Opens a Haptic device
+ */
+SDL_Haptic *
+SDL_HapticOpen(int device_index)
+{
+   int i;
+   SDL_Haptic *haptic;
+
+   if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
+      SDL_SetError("There are %d haptic devices available", SDL_numhaptics);
+      return NULL;
+   }
+
+   /* If the haptic is already open, return it */
+   for (i = 0; SDL_haptics[i]; ++i) {             
+      if (device_index == SDL_haptics[i]->index) {
+         haptic = SDL_haptics[i];
+         ++haptic->ref_count;
+         return haptic;
+      }
+   }
+
+   /* Create and initialize the haptic */
+   haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
+   if (haptic != NULL) {
+      SDL_memset(haptic, 0, (sizeof *haptic));
+      haptic->index = device_index;
+      if (SDL_SYS_HapticOpen(haptic) < 0) {
+         SDL_free(haptic);
+         haptic = NULL;
+      } else {
+      }
+   }
+   if (haptic) {
+      /* Add haptic to list */
+      ++haptic->ref_count;
+      for (i = 0; SDL_haptics[i]; ++i)
+         /* Skip to next haptic */ ;
+      SDL_haptics[i] = haptic;
+   }
+   return haptic;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/haptic/SDL_haptic_c.h	Sun Jun 01 11:44:25 2008 +0000
@@ -0,0 +1,33 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 2008 Edgar Simo
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#include "SDL_haptic.h"
+
+struct _SDL_Haptic;
+
+extern int SDL_HapticInit(void);
+extern int SDL_NumHaptics(void);
+extern const char * SDL_HapticName(int device_index);
+extern struct _SDL_Haptic * SDL_HapticOpen(int device_index);
+extern int SDL_HapticOpened(int device_index);
+extern int SDL_HapticIndex(struct _SDL_Haptic *haptic);
+extern void SDL_HapticClose(struct _SDL_Haptic *haptic);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/haptic/SDL_syshaptic.h	Sun Jun 01 11:44:25 2008 +0000
@@ -0,0 +1,44 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 2008 Edgar Simo
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#include "SDL_config.h"
+
+#include "SDL_haptic.h"
+
+
+struct _SDL_Haptic
+{  
+   Uint8 index;
+   const char* name;
+
+   int neffects; /* maximum amount of effects */
+   unsigned int supported; /* supported effects */
+
+   struct haptic_hwdata *hwdata; /* driver dependent */
+   int ref_count; /* count for multiple opens */
+};
+
+
+extern int SDL_SYS_HapticInit(void);
+
+extern const char * SDL_SYS_HapticName(int index);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/haptic/linux/SDL_syshaptic.c	Sun Jun 01 11:44:25 2008 +0000
@@ -0,0 +1,185 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 2008 Edgar Simo
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifdef SDL_JOYSTICK_LINUX
+
+#include "SDL_haptic.h"
+#include "../SDL_haptic_c.h"
+#include "../SDL_syshaptic.h"
+
+#include <unistd.h> /* close */
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <string.h>
+
+
+#include <stdio.h>
+
+
+#define MAX_HAPTICS  32
+
+
+static struct
+{
+   char *fname;
+   SDL_Haptic *haptic;
+} SDL_hapticlist[MAX_HAPTICS];
+
+struct haptic_hwdata
+{
+   int fd;
+};
+
+
+#define test_bit(nr, addr) \
+   (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
+#define EV_TEST(ev,f) \
+   if (test_bit((ev), features)) ret |= (f);
+static int
+EV_IsHaptic(int fd)
+{
+   unsigned int ret;
+   unsigned long features[1 + FF_MAX/sizeof(unsigned long)];
+
+   ret = 0;
+
+   ioctl(fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features);
+
+   EV_TEST(FF_CONSTANT,   SDL_HAPTIC_CONSTANT);
+   EV_TEST(FF_PERIODIC,   SDL_HAPTIC_PERIODIC);
+   EV_TEST(FF_RAMP,       SDL_HAPTIC_RAMP);
+   EV_TEST(FF_SPRING,     SDL_HAPTIC_SPRING);
+   EV_TEST(FF_FRICTION,   SDL_HAPTIC_FRICTION);
+   EV_TEST(FF_DAMPER,     SDL_HAPTIC_DAMPER);
+   EV_TEST(FF_RUMBLE,     SDL_HAPTIC_RUMBLE);
+   EV_TEST(FF_INERTIA,    SDL_HAPTIC_INERTIA);
+   EV_TEST(FF_GAIN,       SDL_HAPTIC_GAIN);
+   EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
+
+   return ret;
+}
+
+int
+SDL_SYS_HapticInit(void)
+{
+   const char joydev_pattern[] = "/dev/input/event%d";
+   dev_t dev_nums[MAX_HAPTICS];
+   char path[PATH_MAX];
+   struct stat sb;
+   int fd;
+   int i, j, k;
+   int duplicate;
+   int numhaptics;
+
+   numhaptics = 0;
+
+   i = 0;
+   for (j = 0; j < MAX_HAPTICS; ++j) {
+
+      snprintf(path, PATH_MAX, joydev_pattern, i++);
+
+      /* check to see if file exists */
+      if (stat(path,&sb) != 0)
+         break;
+
+      /* check for duplicates */
+      duplicate = 0;
+      for (k = 0; (k < numhaptics) && !duplicate; ++k) {
+         if (sb.st_rdev == dev_nums[k]) {
+            duplicate = 1;
+         }                                                     
+      }                                                         
+      if (duplicate) {
+         continue;
+      }
+
+      /* try to open */
+      fd = open(path, O_RDWR, 0);
+      if (fd < 0) continue;
+
+#ifdef DEBUG_INPUT_EVENTS
+      printf("Checking %s\n", path);
+#endif          
+
+      /* see if it works */
+      if (EV_IsHaptic(fd)!=0) {
+         SDL_hapticlist[numhaptics].fname = SDL_strdup(path);
+         SDL_hapticlist[numhaptics].haptic = NULL;
+         dev_nums[numhaptics] = sb.st_rdev;
+         ++numhaptics;
+      }
+      close(fd);
+   }
+
+   return numhaptics;
+}
+
+
+const char *
+SDL_SYS_HapticName(int index)
+{
+   int fd;
+   static char namebuf[128];
+   char *name;
+
+   name = NULL;
+   fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0);
+   if (fd >= 0) {
+      if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
+         name = SDL_hapticlist[index].fname;
+      }
+      else {
+         name = namebuf;
+      }
+   }
+   close(fd);
+
+   return name;
+}
+
+
+int
+SDL_SYS_HapticOpen(SDL_Haptic * haptic)
+{
+   /* TODO finish
+   int fd;
+
+   fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
+   
+   if (fd < 0) {
+      SDL_SetError("Unable to open %s\n", SDL_hapticlist[haptic->index]);
+      return (-1);
+   }
+
+   
+
+   return 0;
+   */
+}
+
+
+#endif /* SDL_HAPTIC_LINUX */