4
* Copyright (c) 1997-199 Vojtech Pavlik
10
* This is a joystick calibration program for Linux joystick driver.
14
* This program is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation; either version 2 of the License, or
17
* (at your option) any later version.
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
* Should you need to contact me, the author, you can do so either by
29
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
30
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
33
#include <sys/ioctl.h>
44
#include <asm/param.h>
45
#include <linux/joystick.h>
47
#define PIT_HZ 1193180L
53
const char *pos_name[] = {"minimum", "center", "maximum"};
54
const char *corr_name[] = {"none (raw)", "broken line"};
55
const char corr_coef_num[] = {0,4};
57
struct correction_data {
63
struct js_corr corr[MAX_AXES];
64
__u8 axmap[ABS_MAX + 1];
65
__u16 buttonmap[(KEY_MAX - BTN_MISC + 1)];
66
char axes, buttons, fuzz;
68
struct correction_data corda[MAX_AXES];
75
void print_position(int i, int a)
77
printf("Axis %d: %8d\r", i, a);
86
gettimeofday(&tv, NULL);
88
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
91
void wait_for_event(int d, struct js_info *s)
105
if (select(d+1, &set, NULL, NULL, &tv)) {
107
if (FD_ISSET(d, &set)) {
108
if (read(d, &ev, sizeof(struct js_event)) == sizeof(struct js_event))
109
switch (ev.type & ~JS_EVENT_INIT) {
111
s->axis[ev.number] = ev.value; break;
112
case JS_EVENT_BUTTON:
113
s->buttons = (s->buttons & ~(1 << ev.number)) | (ev.value << ev.number);
117
if (FD_ISSET(0, &set)) {
119
s->buttons |= (1 << 31);
123
s->buttons &= ~(1 << 31);
131
for (i = 0; i < 78; i++) putchar(' ');
137
int solve_broken(int *results, struct correction_data inputs)
143
c = 32767.0 / (inputs.cmin[1] - inputs.cmax[0]);
144
d = 32767.0 / (inputs.cmin[2] - inputs.cmax[1]);
146
results[0] = rint(a);
147
results[1] = rint(b);
148
results[2] = rint(c*16384.0);
149
results[3] = rint(d*16384.0);
157
puts("Usage: jscal <device>");
159
puts(" -c --calibrate Calibrate the joystick");
160
puts(" -h --help Display this help");
161
puts(" -s <x,y,z...> --set-correction Sets correction to specified values");
162
puts(" -t --test-center Tests if joystick is corectly calibrated");
163
puts(" returns 0 on success, see the jscal");
164
puts(" manpage for error values");
165
puts(" -V --version Prints the version numbers");
166
puts(" -p --print-correction Prints the current settings as a jscal");
167
puts(" command line");
168
puts(" -q --print-mappings Print the current axis and button");
169
puts(" mappings as a jscal command line");
170
puts(" -u <n_of_axes,axmap1,axmap2,...,");
171
puts(" n_of_buttons,btnmap1,btnmap2,");
172
puts(" ...> --set-mappings Sets axis and button mappings to the");
173
puts(" specified values");
181
if (ioctl(fd, JSIOCGAXES, &axes)) {
182
perror("jscal: error getting axes");
185
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
186
perror("jscal: error getting buttons");
189
if (ioctl(fd, JSIOCGCORR, &corr)) {
190
perror("jscal: error getting correction");
194
printf("Joystick has %d axes and %d buttons.\n", axes, buttons);
195
for (i = 0; i < axes; i++) {
196
printf("Correction for axis %d is %s, precision is %d.\n",
197
i, corr_name[(int)corr[i].type], corr[i].prec);
198
if (corr_coef_num[(int)corr[i].type]) {
199
printf("Coeficients are:");
200
for(j = 0; j < corr_coef_num[(int)corr[i].type]; j++) {
201
printf(" %d", corr[i].coef[j]);
202
if (j < corr_coef_num[(int)corr[i].type] - 1) putchar(',');
215
for (i=0; i<MAX_AXES; i++) {
216
corr[i].type = JS_CORR_NONE;
220
if (ioctl(fd, JSIOCSCORR, &corr)) {
221
perror("jscal: error setting correction");
228
int amax[MAX_AXES], amin[MAX_AXES];
230
puts("Calibrating precision: wait and don't touch the joystick.");
232
wait_for_event(fd, &js);
234
while (get_time() < t+50) wait_for_event(fd, &js);
236
wait_for_event(fd, &js);
238
for(i=0; i < axes; i++)
239
amin[i] = amax[i] = js.axis[i];
242
wait_for_event(fd, &js);
243
for(i=0; i < axes; i++) {
244
if (amin[i] > js.axis[i]) {
245
amin[i] = js.axis[i];
248
if (amax[i] < js.axis[i]) {
249
amax[i] = js.axis[i];
252
printf("Axis %d:%5d,%5d ", i, amin[i], amax[i]);
256
} while (get_time() < t+4000);
258
printf("Done. Precision is: \n");
260
for (i=0; i < axes; i++) {
261
corr[i].prec = amax[i] - amin[i];
262
printf("Axis: %d: %5d\n", i, corr[i].prec);
272
for (axis = 0; axis < axes; axis++)
273
for (pos = 0; pos < NUM_POS; pos++) {
274
while(b ^ js.buttons) wait_for_event(fd, &js);
275
printf("Move axis %d to %s position and push any button.\n", axis, pos_name[pos]);
277
while (!(b ^ js.buttons)) {
278
print_position(axis, js.axis[axis]);
279
wait_for_event(fd, &js);
284
corda[axis].cmin[pos] = js.axis[axis];
285
corda[axis].cmax[pos] = js.axis[axis];
289
while (get_time() < t + 2000 && (b ^ js.buttons)) {
290
if (js.axis[axis] < corda[axis].cmin[pos]) {
291
corda[axis].cmin[pos] = js.axis[axis];
294
if (js.axis[axis] > corda[axis].cmax[pos]) {
295
corda[axis].cmax[pos] = js.axis[axis];
298
wait_for_event(fd, &js);
305
for (j = 0; j < axes; j++) {
306
solve_broken(corr[j].coef, corda[j]);
307
corr[j].type = JS_CORR_BROKEN;
310
puts("Setting correction to:");
311
for (i = 0; i < axes; i++) {
312
printf("Correction for axis %d: %s, precision: %d.\n",
313
i, corr_name[(int)corr[i].type], corr[i].prec);
314
if (corr_coef_num[(int)corr[i].type]) {
315
printf("Coeficients:");
316
for(j = 0; j < corr_coef_num[(int)corr[i].type]; j++) {
317
printf(" %d", corr[i].coef[j]);
318
if (j < corr_coef_num[(int)corr[i].type] - 1) putchar(',');
326
if (ioctl(fd, JSIOCSCORR, &corr)) {
327
perror("jscal: error setting correction");
334
printf("JsCal was compiled for driver version: %d.%d.%d\n", JS_VERSION >> 16,
335
(JS_VERSION >> 8) & 0xff, JS_VERSION & 0xff);
336
printf("Current running driver version: %d.%d.%d\n", version >> 16,
337
(version >> 8) & 0xff, version & 0xff);
340
void print_mappings(char *devicename)
344
if (ioctl(fd, JSIOCGAXES, &axes)) {
345
perror("jscal: error getting axes");
348
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
349
perror("jscal: error getting buttons");
352
if (ioctl(fd, JSIOCGAXMAP, &axmap)) {
353
perror("jscal: error getting axis map");
356
if (ioctl(fd, JSIOCGBTNMAP, &buttonmap)) {
357
perror("jscal: error getting button map");
361
printf("jscal -u %d", axes);
362
for (i = 0; i < axes; i++)
364
printf( ",%d", axmap[i]);
367
printf(",%d", buttons);
368
for (i = 0; i < buttons; i++)
370
printf( ",%d", buttonmap[i]);
373
printf(" %s\n",devicename);
376
void print_settings(char *devicename)
380
if (ioctl(fd, JSIOCGAXES, &axes)) {
381
perror("jscal: error getting axes");
384
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
385
perror("jscal: error getting buttons");
388
if (ioctl(fd, JSIOCGCORR, &corr)) {
389
perror("jscal: error getting correction");
393
printf("jscal -s %d", axes);
394
for (i = 0; i < axes; i++) {
395
printf( ",%d,%d", corr[i].type, corr[i].prec);
396
for (j = 0; j < corr_coef_num[(int)corr[i].type]; j++)
397
printf(",%d", corr[i].coef[j]);
399
printf(" %s\n",devicename);
403
// 10,0,1,2,5,6,16,17,40,41,42:13,288,289,290,291,292,293,294,295,296,297,298,299,300
404
void set_mappings(char *p)
409
int axis_mapping = 0;
412
if (ioctl(fd, JSIOCGAXES, &axes)) {
413
perror("jscal: error getting axes");
416
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
417
perror("jscal: error getting buttons");
421
if (axes > MAX_AXES) axes = MAX_AXES;
424
fprintf(stderr, "jscal: missing argument for --set-mappings\n");
429
sscanf(p, "%d", &axes_on_cl);
432
if (axes_on_cl != axes) {
433
fprintf(stderr, "jscal: joystick has %d axes and not %d as specified on command line\n",
439
for (i = 0; i < axes; i++)
442
fprintf(stderr, "jscal: missing mapping for axis %d\n", i);
445
sscanf(++p, "%d", &axis_mapping);
449
if (axis_mapping > ABS_MAX + 1) {
450
fprintf(stderr, "jscal: invalid axis mapping for axis %d (max is %d)\n", i, ABS_MAX + 1);
453
axmap[i] = axis_mapping;
457
sscanf(++p, "%d", &btns_on_cl);
460
if (btns_on_cl != buttons) {
461
fprintf(stderr, "jscal: joystick has %d buttons and not %d as specified on command line\n",
462
buttons, btns_on_cl);
467
for (i = 0; i < buttons; i++)
470
fprintf(stderr, "jscal: missing mapping for button %d\n", i);
473
sscanf(++p, "%d", &btn_mapping);
477
if (btn_mapping > KEY_MAX) {
478
fprintf(stderr, "jscal: invalid button mapping for button %d (max is %d)\n", i, KEY_MAX);
481
if (btn_mapping < BTN_MISC) {
482
fprintf(stderr, "jscal: invalid button mapping for button %d (min is %d)\n", i, BTN_MISC);
485
buttonmap[i] = btn_mapping;
489
fprintf(stderr, "jscal: too many values\n");
493
if (ioctl(fd, JSIOCSAXMAP, &axmap)) {
494
perror("jscal: error setting axis map");
497
if (ioctl(fd, JSIOCSBTNMAP, &buttonmap)) {
498
perror("jscal: error setting button map");
503
void set_correction(char *p)
508
if (ioctl(fd, JSIOCGAXES, &axes)) {
509
perror("jscal: error getting axes");
513
if (axes > MAX_AXES) axes = MAX_AXES;
516
fprintf(stderr, "jscal: missing number of axes\n");
523
fprintf(stderr, "jscal: joystick has different number of axes (%d) than specified in command line (%d)\n",
529
for (i = 0; i < axes; i++) {
532
fprintf(stderr, "jscal: missing correction type for axis %d\n", i);
535
sscanf(++p, "%d", &t);
540
fprintf(stderr, "jscal: unknown correction type for axis %d\n", i);
546
fprintf(stderr, "jscal: missing precision for axis %d\n", i);
549
sscanf(++p, "%d", &t);
554
for(j = 0; j < corr_coef_num[corr[i].type]; j++) {
556
fprintf(stderr, "jscal: missing coefficient %d for axis %d\n", j, i);
559
sscanf(++p, "%d", (int*) &corr[i].coef[j]);
565
fprintf(stderr, "jscal: too many values\n");
569
if (ioctl(fd, JSIOCSCORR, &corr)) {
570
perror("jscal: error setting correction");
580
if (ioctl(fd, JSIOCGAXES, &axes)) {
581
perror("jscal: error getting axes");
585
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
586
perror("jscal: error getting buttons");
590
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
591
perror("jscal: cannot set nonblocking mode");
595
while (read(fd, &ev, sizeof(struct js_event)) == sizeof(struct js_event)) {
596
switch (ev.type & ~JS_EVENT_INIT) {
598
js.axis[ev.number] = ev.value; break;
599
case JS_EVENT_BUTTON:
600
js.buttons = (js.buttons & ~(1 << ev.number)) | (ev.value << ev.number);
604
for (i = 0; i < axes; i++) if (js.axis[i]) {
605
fprintf(stderr, "jscal: axes not calibrated\n");
609
fprintf(stderr, "jscal: buttons pressed\n");
616
int main(int argc, char **argv)
618
int option_index = 0;
619
char *parameter = NULL;
622
// /usr/include/getopt.h
623
static struct option long_options[] =
625
{"calibrate", no_argument, NULL, 'c'},
626
{"help", no_argument, NULL, 'h'},
627
{"set-correction", required_argument, NULL, 's'},
628
{"set-mappings", required_argument, NULL, 'u'},
629
{"test-center", no_argument, NULL, 't'},
630
{"version", no_argument, NULL, 'V'},
631
{"print-correction", no_argument, NULL, 'p'},
632
{"print-mappings", no_argument, NULL, 'q'},
633
{NULL, no_argument, NULL, 0 }
642
t = getopt_long(argc, argv, "chpqu:s:vVt", long_options, &option_index);
652
fprintf(stderr, "jscal: more than one action specified\n");
656
if ((parameter=optarg)) strcpy(parameter,optarg);
666
fprintf(stderr, "jscal: missing parameter\n");
669
fprintf(stderr, "jscal: unknown option\n");
672
fprintf(stderr, "jscal: option parsing error\n");
676
if (argc != optind + 1) {
677
fprintf(stderr, "jscal: missing devicename\n");
681
if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) {
682
perror("jscal: can't open joystick device");
686
if (ioctl(fd, JSIOCGVERSION, &version)) {
687
perror("jscal: error getting version");
690
if (version != JS_VERSION) {
691
fprintf(stderr, "jscal: wrong version\n");
705
print_settings(argv[argc -1]);
708
print_mappings(argv[argc -1]);
711
set_correction(parameter);
714
set_mappings(parameter);
723
fprintf(stderr, "jscal: this cannot happen\n");