1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
|
/** \file server/drivers/joy.c
* LCDd \c joy input driver for inputting data using joysticks.
*/
/*
* Joystick input driver for LCDd
*
* Only two unique functions are defined:
*
* joy_get_key
* joy_close
*
* All others are at their defaults.
*
* The code here is configured for a Gravis Gamepad (2 axis, 4 button)
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/joystick.h>
#ifndef JSIOCGNAME
#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */
#endif
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "lcd.h"
#include "joy.h"
#include "report.h"
#define JOY_NAMELENGTH 128
#define JOY_DEFAULT_DEVICE "/dev/js0"
#define JOY_MAPSIZE 16
#define JOY_DEFAULT_AXISMAP "EFGHIJKLMNOPQRST"
#define JOY_DEFAULT_BUTTONMAP "BDACEFGHIJKLMNOP"
/** private data for the \c joy driver */
typedef struct joy_private_data {
char device[256];
int fd;
char axes;
char buttons;
int jsversion;
char jsname[JOY_NAMELENGTH];
char **axismap;
char **buttonmap;
} PrivateData;
// Vars for the server core
MODULE_EXPORT char *api_version = API_VERSION;
MODULE_EXPORT int stay_in_foreground = 0;
MODULE_EXPORT int supports_multiple = 0;
MODULE_EXPORT char *symbol_prefix = "joy_";
/**
* Initialize the driver.
* \param drvthis Pointer to driver structure.
* \retval 0 Success.
* \retval <0 Error.
*/
MODULE_EXPORT int
joy_init (Driver *drvthis)
{
PrivateData *p;
int i;
/* Allocate and store private data */
p = (PrivateData *) calloc(1, sizeof(PrivateData));
if (p == NULL)
return -1;
if (drvthis->store_private_ptr(drvthis, p))
return -1;
/* initialize private data */
p->fd = -1;
p->axes = 2;
p->buttons = 2;
p->jsversion = 0;
strcpy(p->jsname, "Unknown");
p->axismap = NULL;
p->buttonmap = NULL;
/* Read config file (1st part) */
/* What device should be used */
strncpy(p->device, drvthis->config_get_string(drvthis->name, "Device", 0,
JOY_DEFAULT_DEVICE), sizeof(p->device));
p->device[sizeof(p->device)-1] = '\0';
report(RPT_INFO, "%s: using Device %s", drvthis->name, p->device);
/* End of config file parsing (1st part) */
if ((p->fd = open(p->device, O_RDONLY)) < 0) {
report(RPT_ERR, "%s: open(%s) failed (%s)",
drvthis->name, p->device, strerror(errno));
return -1;
}
/* init joystick, get values for buttons, exes, name, ... */
fcntl(p->fd, F_SETFL, O_NONBLOCK);
ioctl(p->fd, JSIOCGVERSION, &p->jsversion);
ioctl(p->fd, JSIOCGAXES, &p->axes);
ioctl(p->fd, JSIOCGBUTTONS, &p->buttons);
ioctl(p->fd, JSIOCGNAME(JOY_NAMELENGTH), p->jsname);
report(RPT_NOTICE, "%s: Joystick (%s) has %d axes and %d buttons. Driver version is %d.%d.%d",
drvthis->name, p->jsname, p->axes, p->buttons,
p->jsversion >> 16, (p->jsversion >> 8) & 0xff, p->jsversion & 0xff);
if ((p->axismap = calloc(2 * p->axes, sizeof(char *))) == NULL) {
report(RPT_ERR, "%s: cannot allocate memory for axes", drvthis->name);
return -1;
}
if ((p->buttonmap = calloc(p->buttons, sizeof(char *))) == NULL) {
report(RPT_ERR, "%s: cannot allocate memory for buttons", drvthis->name);
return -1;
}
/* Read config file (2nd part) */
for (i = 0; i < p->axes; i++) {
char mapkey[50];
const char *mapval;
snprintf(mapkey, sizeof(mapkey), "Map_Axis%dneg", i+1);
mapval = drvthis->config_get_string(drvthis->name, mapkey, 0, NULL);
if (mapval != NULL) {
p->axismap[2*i] = strdup(mapval);
report(RPT_DEBUG, "%s: map Axis%dneg to %s",
drvthis->name, i+1, p->axismap[2*i]);
}
snprintf(mapkey, sizeof(mapkey), "Map_Axis%dpos", i+1);
mapval = drvthis->config_get_string(drvthis->name, mapkey, 0, NULL);
if (mapval != NULL) {
p->axismap[2*i + 1] = strdup(mapval);
report(RPT_DEBUG, "%s: map Axis%dpos to %s",
drvthis->name, i+1, p->axismap[2*i + 1]);
}
}
for (i = 0; i < p->buttons; i++) {
char mapkey[50];
const char *mapval;
snprintf(mapkey, sizeof(mapkey), "Map_Button%d", i+1);
mapval = drvthis->config_get_string(drvthis->name, mapkey, 0, NULL);
if (mapval != NULL) {
p->buttonmap[i] = strdup(mapval);
report(RPT_DEBUG, "%s: map Button%d to %s",
drvthis->name, i+1, p->buttonmap[i]);
}
}
/* End of config file parsing (2nd part) */
report(RPT_DEBUG, "%s: init() done", drvthis->name);
return 0;
}
/**
* Close the driver (do necessary clean-up).
* \param drvthis Pointer to driver structure.
*/
MODULE_EXPORT void
joy_close (Driver *drvthis)
{
PrivateData *p = drvthis->private_data;
if (p != NULL) {
if (p->fd >= 0)
close(p->fd);
if (p->axismap != NULL)
free(p->axismap);
if (p->buttonmap != NULL)
free(p->buttonmap);
free(p);
}
drvthis->store_private_ptr(drvthis, NULL);
}
/**
* Get key from the joystick.
* Map the joystick events (move, button press) to a key.
* \param drvthis Pointer to driver structure.
* \return String representation of the key;
* \c NULL for nothing available / error.
*/
MODULE_EXPORT const char *
joy_get_key (Driver *drvthis)
{
PrivateData *p = drvthis->private_data;
struct js_event js;
int err;
if ((err = read(p->fd, &js, sizeof(struct js_event))) <= 0) {
return NULL;
}
if (err != sizeof(struct js_event)) {
report(RPT_ERR, "%s: error reading joystick input", drvthis->name);
return NULL;
}
switch (js.type & ~JS_EVENT_INIT) {
case JS_EVENT_BUTTON:
/* ignore button release */
if ((js.value == 0) || (js.number >= p->buttons))
return NULL;
return p->buttonmap[js.number];
case JS_EVENT_AXIS:
/* ignore noise */
if (((js.value > -20000) && (js.value < 20000))
|| (js.number >= 2 * p->axes))
return NULL;
return p->axismap[js.number];
default:
return NULL;
}
}
|