00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <linux/input.h>
00012 #include <iostream>
00013 #include <time.h>
00014
00015 #include "common/common.h"
00016 #include "perf/perf.h"
00017 #include "util/file.h"
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define CASE( XYZ ) if (test_bit( XYZ , eventTypes)) { DPRINTF("%s ", #XYZ ); }
00028
00029
00030 static bool
00031 test_bit
00032 (
00033 IN int bit,
00034 IN const byte_t * array
00035 )
00036 throw()
00037 {
00038 ASSERT(bit >= 0, "bad bit: %d", bit);
00039 ASSERT(array, "null");
00040
00041 int offset = bit / 8;
00042 const byte_t * p = array + offset;
00043 int mask = 1 << (bit % 8);
00044 return !!(*p & mask);
00045 }
00046
00047
00048
00049 static int
00050 getIndex
00051 (
00052 IN int code,
00053 IN const int * array
00054 )
00055 {
00056 ASSERT(code >= 0, "bad code: %d", code);
00057 ASSERT(array, "null");
00058
00059 int i = 0;
00060 while (true) {
00061 if (*array == code)
00062 return i;
00063 ++i;
00064 ++array;
00065 }
00066 }
00067
00068
00069
00070 static void
00071 doRumble
00072 (
00073 IN smart_fd& fd,
00074 IN int value,
00075 IN int big
00076 )
00077 {
00078 static int eid = -1;
00079 if (value) {
00080
00081 if (-1 != eid)
00082 return;
00083
00084
00085 ff_effect e;
00086 e.type = FF_RUMBLE;
00087 e.id = -1;
00088 uint16_t strength = 0xe000;
00089 e.u.rumble.strong_magnitude = (big) ? strength : 0;
00090 e.u.rumble.weak_magnitude = (!big) ? strength : 0;
00091 e.replay.length = 2000;
00092 e.replay.delay = 0;
00093
00094 if (ioctl(fd, EVIOCSFF, &e) < 0) {
00095 DPRINTF("Failed to upload rumble");
00096 return;
00097 }
00098 eid = e.id;
00099
00100 input_event play;
00101 play.type = EV_FF;
00102 play.code = eid;
00103 play.value = 1;
00104 if (write(fd, (const void *) &play, sizeof(play)) <= 0) {
00105 DPRINTF("Failed to play rumble");
00106 return;
00107 }
00108 } else {
00109
00110 if (-1 == eid)
00111 return;
00112
00113
00114 input_event stop;
00115 stop.type = EV_FF;
00116 stop.code = eid;
00117 stop.value = 0;
00118 if (write(fd, (const void *) &stop, sizeof(stop)) <= 0) {
00119 DPRINTF("Failed to stop rumble");
00120 return;
00121 }
00122
00123 if (ioctl(fd, EVIOCRMFF, eid) < 0) {
00124 DPRINTF("Failed to remove rumble");
00125 return;
00126 }
00127 eid = -1;
00128 }
00129 }
00130
00131
00132
00133 static void
00134 doTest
00135 (
00136 IN const char * path
00137 )
00138 {
00139 THROW(path, "null device path");
00140
00141 DPRINTF("path: %s", path);
00142 smart_fd fd;
00143 THROW(fd.open(path, O_RDWR), "Failed to open device path: " << path);
00144
00145
00146 const int bufsize = 1024;
00147 char devname[bufsize];
00148 THROW(ioctl(fd, EVIOCGNAME(bufsize), devname) >= 0,
00149 "Failed to acquire device name");
00150 DPRINTF("Device name: '%s'", devname);
00151
00152 char uniq[bufsize];
00153 if (ioctl(fd, EVIOCGUNIQ(bufsize), uniq) < 0) {
00154 DPRINTF("Failed to acquire unique device ID");
00155 } else {
00156 DPRINTF("Unique ID: '%s'", uniq);
00157 }
00158
00159
00160 struct input_id iid;
00161 THROW(ioctl(fd, EVIOCGID, &iid) >= 0,
00162 "Failed to acquire device id");
00163 DPRINTF("Bus type: %08x = %d", iid.bustype, iid.bustype);
00164 DPRINTF("Vendor: %08x = %d", iid.vendor, iid.vendor);
00165 DPRINTF("Product: %08x = %d", iid.product, iid.product);
00166 DPRINTF("Version: %08x = %d", iid.version, iid.version);
00167
00168
00169 byte_t features[(FF_MAX + 7) / 8];
00170 THROW(ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) >= 0,
00171 "Failed to query for force-feedback capabilities");
00172
00173 printf("\nList of force feedback effects: ");
00174 if (test_bit(FF_RUMBLE, features)) printf("Rumble ");
00175 if (test_bit(FF_PERIODIC, features)) printf("Periodic ");
00176 if (test_bit(FF_CONSTANT, features)) printf("Constant ");
00177 if (test_bit(FF_SPRING, features)) printf("Spring ");
00178 if (test_bit(FF_FRICTION, features)) printf("Friction ");
00179
00180
00181
00182 printf("\n");
00183
00184 int n_effects;
00185 THROW(ioctl(fd, EVIOCGEFFECTS, &n_effects) >= 0,
00186 "Failed to query number of simultaneous force-feedback effects");
00187 DPRINTF("Can play %d simultaneous force-feedback effects", n_effects);
00188
00189
00190 byte_t eventTypes[(EV_MAX + 7) / 8];
00191 THROW(ioctl(fd, EVIOCGBIT(0, sizeof(eventTypes)), eventTypes) >= 0,
00192 "Failed to retrieve event types");
00193
00194
00195 printf("Events: ");
00196 CASE(EV_SYN)
00197 CASE(EV_KEY)
00198 CASE(EV_REL)
00199 CASE(EV_ABS)
00200 CASE(EV_MSC)
00201 CASE(EV_SW)
00202 CASE(EV_LED)
00203 CASE(EV_SND)
00204 CASE(EV_REP)
00205 CASE(EV_FF)
00206 CASE(EV_PWR)
00207 CASE(EV_FF_STATUS)
00208
00209
00210 const int nMax = 128;
00211 THROW(test_bit(EV_KEY, eventTypes),
00212 "Device reports no buttons/keys?");
00213 int nButtons = 0;
00214 byte_t keyStats[(KEY_MAX + 7) / 8];
00215 THROW(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyStats)), keyStats) >= 0,
00216 "Failed to retrieve button types");
00217 printf("Buttons:");
00218 int btnIndex[nMax];
00219 for (int i = 0; i < KEY_MAX; ++i) {
00220 if (test_bit(i, keyStats)) {
00221 printf(" %d", i);
00222 btnIndex[nButtons] = i;
00223 nButtons++;
00224 }
00225 }
00226 printf("\n");
00227 DPRINTF("Found %d buttons total", nButtons);
00228
00229
00230 THROW(test_bit(EV_ABS, eventTypes),
00231 "Device reports no absolute axes?");
00232 int nAxes = 0;
00233 byte_t axisStats[(ABS_MAX + 7) / 8];
00234 THROW(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(axisStats)), axisStats) >= 0,
00235 "Failed to retrieve absolute axis types");
00236 printf("Axes:");
00237 int axisIndex[nMax];
00238 for (int i = 0; i < ABS_MAX; ++i) {
00239 if (test_bit(i, axisStats)) {
00240 printf(" %d", i);
00241 axisIndex[nAxes] = i;
00242 nAxes++;
00243 }
00244 }
00245 printf("\n");
00246 DPRINTF("Found %d axes total", nAxes);
00247
00248
00249 THROW(!fcntl(fd, F_SETFL, O_NONBLOCK),
00250 "Failed to set device path as nonblocking");
00251
00252
00253 const int desiredHz = 100;
00254 int msSleep = 1000 / desiredHz;
00255 DPRINTF("Want to run at %d Hz", desiredHz);
00256 DPRINTF(" That means polling every %d milliseconds", msSleep);
00257 long nsSleep = 1000 * 1000 * msSleep;
00258 DPRINTF(" Which is %ld nanoseconds", nsSleep);
00259 struct timespec ts;
00260 ts.tv_sec = 0;
00261 ts.tv_nsec = nsSleep;
00262
00263
00264 THROW(nAxes <= nMax, "Too many axes!");
00265 THROW(nButtons <= nMax, "Too many buttons!");
00266 short axes[nMax];
00267 byte_t buttons[nMax];
00268 memset(axes, 0, sizeof(axes));
00269 memset(buttons, 0, sizeof(buttons));
00270
00271
00272 printf("\n");
00273 for (;;) {
00274 nanosleep(&ts, NULL);
00275
00276
00277 int nEvents = 0;
00278 struct input_event events[32];
00279 while (true) {
00280 int len = read(fd, events, sizeof(events));
00281 if (len <= 0)
00282 break;
00283
00284
00285 nEvents = len / sizeof(input_event);
00286 for (int i = 0; i < nEvents; ++i) {
00287 int idx;
00288 switch(events[i].type) {
00289 case EV_KEY:
00290 idx = getIndex(events[i].code, btnIndex);
00291
00292
00293 buttons[idx] = events[i].value;
00294 if (idx < 2) {
00295
00296 doRumble(fd, events[i].value, idx);
00297 }
00298 break;
00299
00300 case EV_ABS:
00301 idx = getIndex(events[i].code, axisIndex);
00302 axes[idx] = events[i].value;
00303 break;
00304 }
00305 }
00306 }
00307
00308
00309 printf("\r");
00310 printf("%02d", nEvents);
00311 for (int i = 0; i < nAxes; ++i) {
00312 printf(" %6d", axes[i]);
00313 }
00314 printf(":");
00315 for (int i = 0; i < nButtons; ++i) {
00316 if (buttons[i]) {
00317 printf(" b%02d", i);
00318
00319 }
00320 }
00321 printf(" ");
00322 }
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 int
00334 main
00335 (
00336 IN int argc,
00337 IN const char * argv[]
00338 )
00339 {
00340 int retval = 0;
00341 try {
00342 perf::Timer timer("overall timer");
00343
00344 THROW(2 == argc, "Usage: linux-joy-events <event-device-path>"
00345 << "\nAn example path is /dev/input/event8");
00346 const char * path = argv[1];
00347
00348 doTest(path);
00349
00350 } catch (std::exception& e) {
00351 DPRINTF("EXCEPTION: %s", e.what());
00352 retval = 1;
00353 }
00354
00355 perf::dumpTimingSummary(std::cerr);
00356
00357 return retval;
00358 }
00359