Reading from input device

From wiki.gp2x.org

It is possible to read input without passing by SDL. It is done more or less the same way than directly Writing_to_the_framebuffer_device, which is: accessing a device. Either the GPIO device or the joystick device.


Contents

Reading from GPIO device

The GPH kernel provides a device called '/dev/GPIO', everytime the device is read, the kernel code reads several GPIO registers and provide a 32bit result to the reader. Since the kernel code reacts on reads it is impossible to detect changes on the device using select. '/dev/GPIO' always provides data to read. If you want to use select just jump to the next section.

To read input (joystick and buttons) there are 3 actions we need to do: opend the device, read and interpret the data, and close the device.

1) Opening the device:

int fd = open("/dev/GPIO", O_RDWR | O_NDELAY );
if (fd < 0) {         
  printf( "GPIO OPEN FAIL\n");
  return -1;
}


2) Read keystates. Key states are stored as bits in a 32bit integer (DWORD).

unsigned long buff = 0;
if (read(fd, &buff, 4) != 4) {
  printf( "GPIO READ ERROR\n");
}

3) Interpret read data. Those constants are the bits associated with the GP2X buttons and joystick state. Please note that the joystick is not analogue so it is treated as 8 different keys (each directions).

// Bit Mask
#define GP2X_VK_UP              (1 <<  0)
#define GP2X_VK_UP_LEFT         (1 <<  1)
#define GP2X_VK_LEFT            (1 <<  2)
#define GP2X_VK_DOWN_LEFT       (1 <<  3)
#define GP2X_VK_DOWN            (1 <<  4)
#define GP2X_VK_DOWN_RIGHT      (1 <<  5)
#define GP2X_VK_RIGHT           (1 <<  6)
#define GP2X_VK_UP_RIGHT        (1 <<  7)
#define GP2X_VK_START           (1 <<  8)
#define GP2X_VK_SELECT          (1 <<  9)
#define GP2X_VK_FL              (1 << 10)
#define GP2X_VK_FR              (1 << 11)
#define GP2X_VK_FA              (1 << 12)
#define GP2X_VK_FB              (1 << 13)
#define GP2X_VK_FX              (1 << 14)
#define GP2X_VK_FY              (1 << 15)
#define GP2X_VK_VOL_UP          (1 << 16)
#define GP2X_VK_VOL_DOWN        (1 << 17)
#define GP2X_VK_TAT             (1 << 18)

All we need to do is compared the read buffer with each bits.

// Compare
if(buff & GP2X_VK_UP            )               printf("Joystick UP\n");
if(buff & GP2X_VK_UP_LEFT       )               printf("Joystick UP_LEFT\n");
if(buff & GP2X_VK_LEFT          )               printf("Joystick LEFT\n");
// The rest is omitted.

4) Clean programming says that any opened device should be close after it is opened and used. Close the device once you're done.

close(fd);

Reading from Joystick device

To read from the linux joystick device /dev/jsX (/dev/js0 is the first), you have to load the linux input subsystem and the joystick handler and finally the gp2x joystick module. The first two things are already available on your gp2x, the third can be downloaded from here:

http://archive.gp2x.de/cgi-bin/cfiles.cgi?0,0,0,0,17,2054

More Information about accessing linux joysticks in general can be found in the Documentation folder for your linux source code. Or look at:

http://www.mjmwired.net/kernel/Documentation/input/joystick-api.txt

Setup

1) Copy the gp2xjoy.o file to your game directory.

2) Add a modprobe call to your start script

modprobe input
modprobe joydev
modprobe ./gp2xjoy.o
./your_game

Programming

1) Setup the fd_set:

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

/* setup FD_SET */
fd_set readfs;
int biggestfd = -1;
FD_ZERO(&readfds);

2) Opening the device

int fd = open("/dev/js0", O_RDONLY );
if (fd < 0) {         
  printf( "JS0 OPEN FAIL\n");
  return -1;
}
FD_SET( fd, &readfds );
biggestfd = fd;

You could also open more than just one js-device, you could check for existing devices with:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

struct stat fileinfo;
if( -1 != stat("/dev/js1",&fileinfo) ) {
   int fd = open("/dev/js1", O_RDONLY );
   FD_SET( fd, &readfds );
   if( fd > biggestfd )
      biggestfd = fd;
}

3) A simple Mainloop:

while(true)
{
  struct timeval nextTimer; /* look at select manpage */
  calcNextTimer( &nextTimer )

  int ret = select( biggestfd, &readfds, 0, 0, &nextTimer )
  if( ret == 0 )
  { 
   /* Timeout triggered */
    calcNextSimulationStep();
    redraw(); 
  }
  else if( ret > 0 )
  { 
    /* ret gives the number of joysticks that have events to read */
    /* check for events with FD_ISSET */ 
    readJoystickEvents( )
  }
  else 
  {  
    /* error, exit gently */
    break;
  }
  /* You have reinitialize the file descriptor set after calling select: */
  recreateFDSETS(&readfds);
}
 

4) Reading from a joystick fd You need these system headers:

#include <fcntl.h>
#include <unistd.h>
#include <linux/joystick.h>

Then you can read the name of the joystick:

  char name[128];
  if (ioctl( fd, JSIOCGNAME(sizeof(name)), name) < 0 )
    printf("Unknown\n");
  else
    printf("Joystick: %s", name);

Or the axes and buttons:

char get_axes( int fd )
{
  char number_of_axes;
  ioctl( fd, JSIOCGAXES, &number_of_axes);
  return number_of_axes;
}

char get_buttons( int fd )
{
  char number_of_axes;
  ioctl( fd, JSIOCGBUTTONS, &number_of_axes);
  return number_of_axes;
}

Finally reading a joystick event:

  js_event event;
  if( sizeof(js_event) == read( fd, &event, sizeof(js_event) );

5) Joystick mapping:

Button 0 : Stick 
Button 1 : A 
Button 2 : B 
Button 3 : X
Button 4 : Y
Button 5 : L
Button 6 : R
Button 7 : VOL Down
Button 8 : VOL Up
Button 9 : Select
Button10 : Start

The stick recognizes 17 different positions. The linux joystick treats the stick as axis 0 and axis 1. Axis 0 is horizontal, Axis1 vertical. One could explain the value range here .. tbc ..

Links

http://dev.gp2x.com/forum/viewtopic.php?t=13

Personal tools