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@suse.cz>, or by paper mail:
30
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
33
#include <sys/ioctl.h>
43
#include <asm/param.h>
44
#include <linux/joystick.h>
46
#define PIT_HZ 1193180L
52
const char *pos_name[] = {"minimum", "center", "maximum"};
53
const char *corr_name[] = {"none (raw)", "broken line"};
54
const char corr_coef_num[] = {0,4};
56
struct correction_data {
62
struct js_corr corr[MAX_AXES];
63
char axes, buttons, fuzz;
65
struct correction_data corda[MAX_AXES];
72
void print_position(int i, int a)
74
printf("Axis %d: %8d\r", i, a);
83
gettimeofday(&tv, NULL);
85
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
88
void wait_for_event(int d, struct js_info *s)
102
if (select(d+1, &set, NULL, NULL, &tv)) {
104
if (FD_ISSET(d, &set)) {
105
if (read(d, &ev, sizeof(struct js_event)) == sizeof(struct js_event))
106
switch (ev.type & ~JS_EVENT_INIT) {
108
s->axis[ev.number] = ev.value; break;
109
case JS_EVENT_BUTTON:
110
s->buttons = (s->buttons & ~(1 << ev.number)) | (ev.value << ev.number);
114
if (FD_ISSET(0, &set)) {
116
s->buttons |= (1 << 31);
120
s->buttons &= ~(1 << 31);
128
for (i = 0; i < 78; i++) putchar(' ');
134
int solve_broken(int *results, struct correction_data inputs)
140
c = 32767.0 / (inputs.cmin[1] - inputs.cmax[0]);
141
d = 32767.0 / (inputs.cmin[2] - inputs.cmax[1]);
143
results[0] = rint(a);
144
results[1] = rint(b);
145
results[2] = rint(c*16384.0);
146
results[3] = rint(d*16384.0);
154
puts("Usage: jscal <device>");
156
puts(" -c --calibrate Calibrate the joystick");
157
puts(" -h --help Display this help");
158
puts(" -s <x,y,z...> --set-correction Sets correction to specified values");
159
puts(" -t --test-center Tests if joystick is corectly calibrated");
160
puts(" returns 0 on success, see the jscal");
161
puts(" manpage for error values");
162
puts(" -V --version Prints the version numbers");
163
puts(" -p --print-correction Prints the current settings as a jscal");
164
puts(" command line");
172
if (ioctl(fd, JSIOCGAXES, &axes)) {
173
perror("jscal: error getting axes");
176
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
177
perror("jscal: error getting buttons");
180
if (ioctl(fd, JSIOCGCORR, &corr)) {
181
perror("jscal: error getting correction");
185
printf("Joystick has %d axes and %d buttons.\n", axes, buttons);
186
for (i = 0; i < axes; i++) {
187
printf("Correction for axis %d is %s, precision is %d.\n",
188
i, corr_name[(int)corr[i].type], corr[i].prec);
189
if (corr_coef_num[(int)corr[i].type]) {
190
printf("Coeficients are:");
191
for(j = 0; j < corr_coef_num[(int)corr[i].type]; j++) {
192
printf(" %d", corr[i].coef[j]);
193
if (j < corr_coef_num[(int)corr[i].type] - 1) putchar(',');
205
for (i=0; i<MAX_AXES; i++) {
206
corr[i].type = JS_CORR_NONE;
210
if (ioctl(fd, JSIOCSCORR, &corr)) {
211
perror("jscal: error setting correction");
218
int amax[MAX_AXES], amin[MAX_AXES];
220
puts("Calibrating precision: wait and don't touch the joystick.");
222
wait_for_event(fd, &js);
224
while (get_time() < t+50) wait_for_event(fd, &js);
226
wait_for_event(fd, &js);
228
for(i=0; i < axes; i++)
229
amin[i] = amax[i] = js.axis[i];
232
wait_for_event(fd, &js);
233
for(i=0; i < axes; i++) {
234
if (amin[i] > js.axis[i]) amin[i] = js.axis[i];
235
if (amax[i] < js.axis[i]) amax[i] = js.axis[i];
236
printf("Axis %d:%5d,%5d ", i, amin[i], amax[i]);
240
} while (get_time() < t+2000);
242
printf("Done. Precision is: \n");
244
for (i=0; i < axes; i++) {
245
corr[i].prec = amax[i] - amin[i];
246
printf("Axis: %d: %5d\n", i, corr[i].prec);
256
for (j = 0; j < axes; j++)
257
for (i = 0; i < NUM_POS; i++) {
258
while(b ^ js.buttons) wait_for_event(fd, &js);
259
printf("Move axis %d to %s position and push any button.\n", j, pos_name[i]);
261
while (!(b ^ js.buttons)) {
262
print_position(j, js.axis[j]);
263
wait_for_event(fd, &js);
268
corda[j].cmin[i] = js.axis[j];
269
corda[j].cmax[i] = js.axis[j];
273
while (get_time() < t + 2000 && (b ^ js.buttons)) {
274
if (js.axis[j] < corda[j].cmin[i]) corda[j].cmin[i] = js.axis[j];
275
if (js.axis[j] > corda[j].cmax[i]) corda[j].cmax[i] = js.axis[j];
276
wait_for_event(fd, &js);
283
for (j = 0; j < axes; j++) {
284
solve_broken(corr[j].coef, corda[j]);
285
corr[j].type = JS_CORR_BROKEN;
288
puts("Setting correction to:");
289
for (i = 0; i < axes; i++) {
290
printf("Correction for axis %d: %s, precision: %d.\n",
291
i, corr_name[(int)corr[i].type], corr[i].prec);
292
if (corr_coef_num[(int)corr[i].type]) {
293
printf("Coeficients:");
294
for(j = 0; j < corr_coef_num[(int)corr[i].type]; j++) {
295
printf(" %d", corr[i].coef[j]);
296
if (j < corr_coef_num[(int)corr[i].type] - 1) putchar(',');
304
if (ioctl(fd, JSIOCSCORR, &corr)) {
305
perror("jscal: error setting correction");
312
printf("JsCal was compiled for driver version: %d.%d.%d\n", JS_VERSION >> 16,
313
(JS_VERSION >> 8) & 0xff, JS_VERSION & 0xff);
314
printf("Current running driver version: %d.%d.%d\n", version >> 16,
315
(version >> 8) & 0xff, version & 0xff);
318
void print_settings(char *devicename)
322
if (ioctl(fd, JSIOCGAXES, &axes)) {
323
perror("jscal: error getting axes");
326
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
327
perror("jscal: error getting buttons");
330
if (ioctl(fd, JSIOCGCORR, &corr)) {
331
perror("jscal: error getting correction");
335
printf("jscal -s %d", axes);
336
for (i = 0; i < axes; i++) {
337
printf( ",%d,%d", corr[i].type, corr[i].prec);
338
for (j = 0; j < corr_coef_num[(int)corr[i].type]; j++)
339
printf(",%d", corr[i].coef[j]);
341
printf(" %s\n",devicename);
344
void set_correction(char *p)
349
if (ioctl(fd, JSIOCGAXES, &axes)) {
350
perror("jscal: error getting axes");
354
if (axes > MAX_AXES) axes = MAX_AXES;
357
fprintf(stderr, "jscal: missing number of axes\n");
364
fprintf(stderr, "jscal: joystick has different number of axes (%d) than specified in command line (%d)\n",
370
for (i = 0; i < axes; i++) {
373
fprintf(stderr, "jscal: missing correction type for axis %d\n", i);
376
sscanf(++p, "%d", &t);
381
fprintf(stderr, "jscal: unknown correction type for axis %d\n", i);
387
fprintf(stderr, "jscal: missing precision for axis %d\n", i);
390
sscanf(++p, "%d", &t);
395
for(j = 0; j < corr_coef_num[corr[i].type]; j++) {
397
fprintf(stderr, "jscal: missing coefficient %d for axis %d\n", j, i);
400
sscanf(++p, "%d", (int*) &corr[i].coef[j]);
406
fprintf(stderr, "jscal: too many values\n");
410
if (ioctl(fd, JSIOCSCORR, &corr)) {
411
perror("jscal: error setting correction");
421
if (ioctl(fd, JSIOCGAXES, &axes)) {
422
perror("jscal: error getting axes");
426
if (ioctl(fd, JSIOCGBUTTONS, &buttons)) {
427
perror("jscal: error getting buttons");
431
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
432
perror("jscal: cannot set nonblocking mode");
436
while (read(fd, &ev, sizeof(struct js_event)) == sizeof(struct js_event)) {
437
switch (ev.type & ~JS_EVENT_INIT) {
439
js.axis[ev.number] = ev.value; break;
440
case JS_EVENT_BUTTON:
441
js.buttons = (js.buttons & ~(1 << ev.number)) | (ev.value << ev.number);
445
for (i = 0; i < axes; i++) if (js.axis[i]) {
446
fprintf(stderr, "jscal: axes not calibrated\n");
450
fprintf(stderr, "jscal: buttons pressed\n");
457
int main(int argc, char **argv)
459
int option_index = 0;
460
char *parameter = NULL;
463
static struct option long_options[] =
465
{"calibrate", no_argument, NULL, 'c'},
466
{"help", no_argument, NULL, 'h'},
467
{"set-correction", required_argument, NULL, 's'},
468
{"test-center", no_argument, NULL, 't'},
469
{"version", no_argument, NULL, 'V'},
470
{"print-correction", no_argument, NULL, 'p'}
479
t = getopt_long(argc, argv, "chps:vVt", long_options, &option_index);
487
fprintf(stderr, "jscal: more than one action specified\n");
491
if ((parameter=optarg)) strcpy(parameter,optarg);
501
fprintf(stderr, "jscal: missing parameter\n");
504
fprintf(stderr, "jscal: unknown option\n");
507
fprintf(stderr, "jscal: option parsing error\n");
511
if (argc != optind + 1) {
512
fprintf(stderr, "jscal: missing devicename\n");
516
if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) {
517
perror("jscal: can't open joystick device");
521
if (ioctl(fd, JSIOCGVERSION, &version)) {
522
perror("jscal: error getting version");
525
if (version != JS_VERSION) {
526
fprintf(stderr, "jscal: wrong version\n");
540
print_settings(argv[argc -1]);
543
set_correction(parameter);
552
fprintf(stderr, "jscal: this cannot happen\n");