Logo Search packages:      
Sourcecode: libjsw version File versions

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include "forcefeedback.h"

#include "../include/string.h"
#include "../include/strexp.h"
#include "../include/disk.h"
#include "../include/fio.h"

#include "../include/jsw.h"


int JSInit(
      js_data_struct *jsd,
      const char *device,
      const char *calibration,
      unsigned int flags
);
int JSUpdate(js_data_struct *jsd);
void JSClose(js_data_struct *jsd);


#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))


/*
 *      Initializes the joystick and stores the new initialized values
 *      into the jsd structure.
 *
 *      If the device is not specified (set to NULL), then it will
 *      be defauled to JSDefaultDevice.
 *
 *      If the calibration file is not specified (set to NULL), then
 *      it will be defaulted to JSDefaultCalibration. The HOME
 *      enviroment value will be used as the prefix to the path of
 *      JSDefaultCalibration. The calibration file does not have to
 *      exist.
 *
 *    Available flags are:
 *
 *    JSFlagNonBlocking       Open in non-blocking mode.
 *    JSFlagForceFeedback           Open in read/write mode.
 */
int JSInit(
        js_data_struct *jsd,
        const char *device,
        const char *calibration,
      unsigned int flags
)
{
      int i;

#ifdef __linux__
      unsigned char axes = 2;
      unsigned char buttons = 2;
      int version = 0x000800;

# ifndef LINUX_JS_NAME_MAX
#  define LINUX_JS_NAME_MAX   128
# endif

      char name[LINUX_JS_NAME_MAX] = "Unknown";

#endif      /* __linux__ */



      if(jsd == NULL)
          return(JSBadValue);


      /* Explicitly reset values. */
      jsd->axis = NULL;
      jsd->total_axises = 0;

      jsd->button = NULL;
      jsd->total_buttons = 0;

      jsd->device_name = NULL;
      jsd->calibration_file = NULL;

      jsd->events_received = 0;
      jsd->events_sent = 0;

      jsd->fd = -1;
      jsd->flags = 0;
      jsd->driver_version = 0;
      jsd->last_calibrated = 0;
      jsd->force_feedback = NULL;


      /* Set default device name as needed. */
      if(device == NULL)
          device = JSDefaultDevice;

      /* Set default calibration file name as needed. */
      if(calibration == NULL)
      {
          const char *home_dir, *tmp_path;

          home_dir = getenv("HOME");
          tmp_path = PrefixPaths(
            (home_dir != NULL) ? home_dir : "/",
            JSDefaultCalibration
          );
          if(tmp_path == NULL)
            tmp_path = JSDefaultCalibration;

          calibration = tmp_path;
      }

      /* From this point on device and calibration are not NULL, so
       * record device and calibration file names on the jsd structure.
       */
      jsd->device_name = strdup(device);
        jsd->calibration_file = strdup(calibration);


#ifdef __linux__
      /* Open joystick. */
      jsd->fd = open(jsd->device_name, O_RDONLY);
      if(jsd->fd < 0)
      {
          JSClose(jsd);
            return(JSNoAccess);
        }

      /* Fetch device values. */
      /* Raw version string. */
        ioctl(jsd->fd, JSIOCGVERSION, &version);
      jsd->driver_version = (unsigned int)version;

      /* Total number of axises. */
        ioctl(jsd->fd, JSIOCGAXES, &axes);      /* Total axises. */
      jsd->total_axises = axes;

      /* Total number of buttons. */
        ioctl(jsd->fd, JSIOCGBUTTONS, &buttons);      /* Total buttons. */
      jsd->total_buttons = buttons;

      /* Device descriptive name. */
        ioctl(jsd->fd, JSIOCGNAME(LINUX_JS_NAME_MAX), name);
      jsd->name = StringCopyAlloc(name);

      /* Allocate axises. */
      if(jsd->total_axises > 0)
      {
          jsd->axis = (js_axis_struct **)calloc(
              jsd->total_axises,
              sizeof(js_axis_struct *)
          );
          if(jsd->axis == NULL)
          {
              jsd->total_axises = 0;
              JSClose(jsd);
              return(JSNoBuffers);
          }
      }
      for(i = 0; i < jsd->total_axises; i++)
      {
          jsd->axis[i] = (js_axis_struct *)calloc(
                1,
                sizeof(js_axis_struct)
            );
            if(jsd->axis == NULL)
            {
                JSClose(jsd);
                return(JSNoBuffers);
            }

          /* Reset axis values. */
            jsd->axis[i]->cur = JSDefaultCenter;
          jsd->axis[i]->min = JSDefaultMin;
            jsd->axis[i]->max = JSDefaultMax;
            jsd->axis[i]->cen = JSDefaultCenter;
          jsd->axis[i]->nz = JSDefaultNullZone;
          jsd->axis[i]->tolorance = JSDefaultTolorance;
            jsd->axis[i]->flags = 0;
      }

        /* Allocate buttons. */  
      if(jsd->total_buttons > 0)
      {
            jsd->button = (js_button_struct **)calloc(
                jsd->total_buttons,
                sizeof(js_button_struct *)
            );
            if(jsd->button == NULL)   
            {
                jsd->total_buttons = 0;
                JSClose(jsd);   
                return(JSNoBuffers);
          }
        }
        for(i = 0; i < jsd->total_buttons; i++)
        {
            jsd->button[i] = (js_button_struct *)calloc(
                1,
                sizeof(js_button_struct)
            );
            if(jsd->button == NULL)
            {
                JSClose(jsd);
                return(JSNoBuffers);
            }

          /* Reset button values. */
            jsd->button[i]->state = JSButtonStateOff;
        }

      /* Set to non-blocking? */
      if(flags & JSFlagNonBlocking)
      {
            fcntl(jsd->fd, F_SETFL, O_NONBLOCK);
          jsd->flags |= JSFlagNonBlocking;
      }

        /* Mark successful initialization. */
        jsd->flags |= JSFlagIsInit;

        /* Load calibration from calibration file. */
        JSLoadCalibrationUNIX(jsd);

#endif      /* __linux__ */

        /* Set axis tolorance for error correction. */
        JSResetAllAxisTolorance(jsd);


      return(JSSuccess);
}


/*
 *    Updates the information in jsd, returns JSGotEvent if there
 *    was some change or JSNoEvent if there was no change.
 *
 *    jsd needs to be previously initialized by a call to
 *    JSInit().
 */
int JSUpdate(js_data_struct *jsd)
{
      int n;
      int status = JSNoEvent;
#ifdef __linux__
      int keep_handling = 1;
      int bytes_read, cycles;
      struct js_event event;
      js_axis_struct **axis;
      js_button_struct **button;
#endif  /* __linux__ */


        if(jsd == NULL)
            return(status);

      if(jsd->fd < 0)
          return(status);

#ifdef __linux__
      /* Reset all button state change value on all buttons. */
      for(n = 0, button = jsd->button;
          n < jsd->total_buttons;
          n++, button++
      )
      {
          if(*button != NULL)
            (*button)->changed_state = JSButtonChangedStateNone;
      }

      /* Reset current and previous axis values. */
        for(n = 0, axis = jsd->axis;
            n < jsd->total_axises;
            n++, axis++
        )
        {
            if(*axis != NULL)
                (*axis)->prev = (*axis)->cur;
        }


      /* Handle up to 16 events from joystick driver. */
      cycles = 0;
      while(keep_handling &&
              (cycles < 16)
      )
      {
          /* Get event. */
          bytes_read = read(
              jsd->fd,
              &event,
              sizeof(struct js_event)
          );
          /* No more events to be read? */
          if(bytes_read != sizeof(struct js_event))
              return(status);

          /* Handle by event type. */
            switch(event.type & ~JS_EVENT_INIT)
          {
            /* Axis event. */
            case JS_EVENT_AXIS:
              /* Get axis number. */
                n = event.number;

                /* Does axis exist? */
                if(JSIsAxisAllocated(jsd, n))
                {
                js_axis_struct *axis_ptr = jsd->axis[n];

                /* Record previous axis position. */
                axis_ptr->prev = axis_ptr->cur;

                /* Set new current axis value. */
                    axis_ptr->cur = (int)event.value;

                    /* Record time stamp (in ms). */
                    axis_ptr->last_time = axis_ptr->time;

                    /* Set new time stamp (in ms). */
                    axis_ptr->time = (time_t)event.time;
                }
            jsd->events_received++; /* Increment events recv count. */
              status = JSGotEvent;  /* Mark that we got event. */
              break;

            /* Button event. */
              case JS_EVENT_BUTTON:
              /* Get button number. */
              n = event.number;

              /* Does button exist? */
                if(JSIsButtonAllocated(jsd, n))
              {
                js_button_struct *button_ptr = jsd->button[n];

                /* Record previous state. */
                button_ptr->prev_state = button_ptr->state;

                /* Set new button state. */
                    button_ptr->state = ((event.value) ?
                    JSButtonStateOn : JSButtonStateOff
                );

                /* Update state change. */
                if((button_ptr->prev_state == JSButtonStateOn) &&
                       (button_ptr->state == JSButtonStateOff)
                )
                  button_ptr->changed_state = JSButtonChangedStateOnToOff;
                    else if((button_ptr->prev_state == JSButtonStateOff) &&
                            (button_ptr->state == JSButtonStateOn)
                    )
                  button_ptr->changed_state = JSButtonChangedStateOffToOn;

                    /* Record time stamp (in ms). */
                button_ptr->last_time = button_ptr->time;

                /* Set new time stamp (in ms). */
                    button_ptr->time = (time_t)event.time;
              }
            jsd->events_received++; /* Increment events recv count. */
              status = JSGotEvent;  /* Mark that we got event. */
              break;

            /* Other event. */
            default:
            keep_handling = 0;      /* Stop handling events. */
            break;
          }

          cycles++;
      }
#endif      /* __linux__ */


        return(status);
}

/*
 *    Closes the joystick and deallocates all resources on the given
 *    jsd structure. The jsd structure itself is not deallocated however
 *    its values will be reset to defaults.
 */
void JSClose(js_data_struct *jsd)
{
      int i;


      if(jsd == NULL)
          return;

      /* Deallocate force feedback resources and deallocate the
       * force_feedback structure.
       */
      JSFFDelete(jsd->force_feedback);
      jsd->force_feedback = NULL;

      /* Close descriptor to joystick. */
      if(jsd->fd > -1)
      {
          close(jsd->fd);
          jsd->fd = -1;
      }

      /* Free name. */
      free(jsd->name);
      jsd->name = NULL;


      /* Free all axises. */
      for(i = 0; i < jsd->total_axises; i++)
          free(jsd->axis[i]);
      free(jsd->axis);
      jsd->axis = NULL;
      jsd->total_axises = 0;


      /* Free all buttons. */
      for(i = 0; i < jsd->total_buttons; i++)
            free(jsd->button[i]);
        free(jsd->button);
        jsd->button = NULL;
        jsd->total_buttons = 0;


      /* Free device name. */
      free(jsd->device_name);
      jsd->device_name = NULL;

      /* Free calibration file name. */
      free(jsd->calibration_file);
      jsd->calibration_file = NULL;


      /* Reset rest of the values. */
      jsd->flags = 0;
      jsd->driver_version = 0;
      jsd->last_calibrated = 0;

      /* Do not deallocate the jsd structure. */
}

Generated by  Doxygen 1.6.0   Back to index