~ubuntu-branches/ubuntu/saucy/joystick/saucy

« back to all changes in this revision

Viewing changes to .pc/ioctl-error-handling.patch/utils/ffcfstress.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Kitt
  • Date: 2011-04-04 16:56:39 UTC
  • mfrom: (1.1.2 upstream)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110404165639-wwp0enzkfqi841i7
* New upstream version:
  - Builds with --as-needed. Closes: #607009.
  - inputattach supports W8001. Closes: #616443.
  - inputattach supports Zhen-Hua. LP: #648945.
* Drop all patches, merged upstream. Drop README.source explaining quilt
  usage, and --with-quilt directive to sh.
* Drop manpages, merged upstream.
* Drop store/restore tools, merged upstream.
* Rework udev rules:
  - provide agents to delay invoking inputattach or jscal-restore until
    they become available;
  - drop jskeepalive and use sleep instead to stop Acrux devices from
    going into a coma (as suggested by Oliver Neukum), for kernels prior
    to 2.6.39;
  - only apply the udev rules when adding devices (as suggested by
    Roberto Neri).
* Standards-Version 3.9.1, no change required.
* No longer ship evtest, its source is maintained separately (and will
  be removed from future upstream versions of joystick).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * ffcfstress.c
3
 
 *
4
 
 * Force Feedback: Constant Force Stress Test
5
 
 *
6
 
 * Copyright (C) 2001 Oliver Hamann
7
 
 *
8
 
 * This program is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * This program is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program; if not, write to the Free Software
20
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
 
 */
22
 
 
23
 
#include <linux/input.h>
24
 
#include <sys/ioctl.h>
25
 
#include <stdio.h>
26
 
#include <stdlib.h>
27
 
#include <string.h>
28
 
#include <fcntl.h>
29
 
#include <unistd.h>
30
 
#include <errno.h>
31
 
#include <math.h>
32
 
 
33
 
 
34
 
/* Helper for testing large bit masks */
35
 
#define TEST_BIT(bit,bits) (((bits[bit>>5]>>(bit&0x1f))&1)!=0)
36
 
 
37
 
 
38
 
/* Default values for the options */
39
 
#define DEFAULT_DEVICE_NAME "/dev/input/event0"
40
 
#define DEFAULT_UPDATE_RATE      25.0
41
 
#define DEFAULT_MOTION_FREQUENCY  0.1
42
 
#define DEFAULT_MOTION_AMPLITUDE  1.0
43
 
#define DEFAULT_SPRING_STRENGTH   1.0
44
 
 
45
 
 
46
 
/* Options */
47
 
const char * device_name = DEFAULT_DEVICE_NAME;
48
 
double update_rate       = DEFAULT_UPDATE_RATE;
49
 
double motion_frequency  = DEFAULT_MOTION_FREQUENCY;
50
 
double motion_amplitude  = DEFAULT_MOTION_AMPLITUDE;
51
 
double spring_strength   = DEFAULT_SPRING_STRENGTH;
52
 
int stop_and_play = 0;  /* Stop-upload-play effects instead of updating */
53
 
 
54
 
 
55
 
/* Global variables about the initialized device */
56
 
int device_handle;
57
 
int axis_code, axis_min, axis_max;
58
 
struct ff_effect effect;
59
 
 
60
 
 
61
 
/* Parse command line arguments */
62
 
void parse_args(int argc, char * argv[])
63
 
{
64
 
        int i;
65
 
 
66
 
        if (argc<2) goto l_help;
67
 
 
68
 
        for (i=1; i<argc; i++) {
69
 
                if      (!strcmp(argv[i],"-d") && i<argc-1) device_name     =argv[++i];
70
 
                else if (!strcmp(argv[i],"-u") && i<argc-1) update_rate     =atof(argv[++i]);
71
 
                else if (!strcmp(argv[i],"-f") && i<argc-1) motion_frequency=atof(argv[++i]);
72
 
                else if (!strcmp(argv[i],"-a") && i<argc-1) motion_amplitude=atof(argv[++i]);
73
 
                else if (!strcmp(argv[i],"-s") && i<argc-1) spring_strength =atof(argv[++i]);
74
 
                else if (!strcmp(argv[i],"-o")) ;
75
 
                else goto l_help;
76
 
        }
77
 
        return;
78
 
 
79
 
l_help:
80
 
        printf("-------- ffcfstress - Force Feedback: Constant Force Stress Test --------\n");
81
 
        printf("Description:\n");
82
 
        printf("  This program is for stress testing constant non-enveloped forces on\n");
83
 
        printf("  a force feedback device via the event interface. It simulates a\n");
84
 
        printf("  moving spring force by a frequently updated constant force effect.\n");
85
 
        printf("  BE CAREFUL IN USAGE, YOUR DEVICE MAY GET DAMAGED BY THE STRESS TEST!\n");
86
 
        printf("Usage:\n");
87
 
        printf("  %s <option> [<option>...]\n",argv[0]);
88
 
        printf("Options:\n");
89
 
        printf("  -d <string>  device name (default: %s)\n",DEFAULT_DEVICE_NAME);
90
 
        printf("  -u <double>  update rate in Hz (default: %.2f)\n",DEFAULT_UPDATE_RATE);
91
 
        printf("  -f <double>  spring center motion frequency in Hz (default: %.2f)\n",DEFAULT_MOTION_FREQUENCY);
92
 
        printf("  -a <double>  spring center motion amplitude 0.0..1.0 (default: %.2f)\n",DEFAULT_MOTION_AMPLITUDE);
93
 
        printf("  -s <double>  spring strength factor (default: %.2f)\n",DEFAULT_SPRING_STRENGTH);
94
 
        printf("  -o           dummy option (useful because at least one option is needed)\n");
95
 
        exit(1);
96
 
}
97
 
 
98
 
 
99
 
/* Initialize device, create constant force effect */
100
 
void init_device()
101
 
{
102
 
        unsigned long key_bits[32],abs_bits[32],ff_bits[32];
103
 
        struct input_event event;
104
 
        int valbuf[16];
105
 
 
106
 
        /* Open event device with write permission */
107
 
        device_handle = open(device_name,O_RDWR|O_NONBLOCK);
108
 
        if (device_handle<0) {
109
 
                fprintf(stderr,"ERROR: can not open %s (%s) [%s:%d]\n",
110
 
                        device_name,strerror(errno),__FILE__,__LINE__);
111
 
                exit(1);
112
 
        }
113
 
 
114
 
        /* Which buttons has the device? */
115
 
        memset(key_bits,0,32*sizeof(unsigned long));
116
 
        if (ioctl(device_handle,EVIOCGBIT(EV_KEY,32*sizeof(unsigned long)),key_bits)<0) {
117
 
                fprintf(stderr,"ERROR: can not get key bits (%s) [%s:%d]\n",
118
 
                        strerror(errno),__FILE__,__LINE__);
119
 
                exit(1);
120
 
        }
121
 
 
122
 
        /* Which axes has the device? */
123
 
        memset(abs_bits,0,32*sizeof(unsigned long));
124
 
        if (ioctl(device_handle,EVIOCGBIT(EV_ABS,32*sizeof(unsigned long)),abs_bits)<0) {
125
 
                fprintf(stderr,"ERROR: can not get abs bits (%s) [%s:%d]\n",
126
 
                        strerror(errno),__FILE__,__LINE__);
127
 
                exit(1);
128
 
        }
129
 
 
130
 
        /* Now get some information about force feedback */
131
 
        memset(ff_bits,0,32*sizeof(unsigned long));
132
 
        if (ioctl(device_handle,EVIOCGBIT(EV_FF ,32*sizeof(unsigned long)),ff_bits)<0) {
133
 
                fprintf(stderr,"ERROR: can not get ff bits (%s) [%s:%d]\n",
134
 
                        strerror(errno),__FILE__,__LINE__);
135
 
                exit(1);
136
 
        }
137
 
 
138
 
        /* Which axis is the x-axis? */
139
 
        if      (TEST_BIT(ABS_X    ,abs_bits)) axis_code=ABS_X;
140
 
        else if (TEST_BIT(ABS_RX   ,abs_bits)) axis_code=ABS_RX;
141
 
        else if (TEST_BIT(ABS_WHEEL,abs_bits)) axis_code=ABS_WHEEL;
142
 
        else {
143
 
                fprintf(stderr,"ERROR: no suitable x-axis found [%s:%d]\n",
144
 
                        __FILE__,__LINE__);
145
 
                exit(1);
146
 
        }
147
 
 
148
 
        /* get axis value range */
149
 
        if (ioctl(device_handle,EVIOCGABS(axis_code),valbuf)<0) {
150
 
                fprintf(stderr,"ERROR: can not get axis value range (%s) [%s:%d]\n",
151
 
                        strerror(errno),__FILE__,__LINE__);
152
 
                exit(1);
153
 
        }
154
 
        axis_min=valbuf[1];
155
 
        axis_max=valbuf[2];
156
 
        if (axis_min>=axis_max) {
157
 
                fprintf(stderr,"ERROR: bad axis value range (%d,%d) [%s:%d]\n",
158
 
                        axis_min,axis_max,__FILE__,__LINE__);
159
 
                exit(1);
160
 
        }
161
 
 
162
 
        /* force feedback supported? */
163
 
        if (!TEST_BIT(FF_CONSTANT,ff_bits)) {
164
 
                fprintf(stderr,"ERROR: device (or driver) has no force feedback support [%s:%d]\n",
165
 
                        __FILE__,__LINE__);
166
 
                exit(1);
167
 
        }
168
 
 
169
 
        /* Switch off auto centering */
170
 
        memset(&event,0,sizeof(event));
171
 
        event.type=EV_FF;
172
 
        event.code=FF_AUTOCENTER;
173
 
        event.value=0;
174
 
        if (write(device_handle,&event,sizeof(event))!=sizeof(event)) {
175
 
                fprintf(stderr,"ERROR: failed to disable auto centering (%s) [%s:%d]\n",
176
 
                        strerror(errno),__FILE__,__LINE__);
177
 
                exit(1);
178
 
        }
179
 
 
180
 
        /* Initialize constant force effect */
181
 
        memset(&effect,0,sizeof(effect));
182
 
        effect.type=FF_CONSTANT;
183
 
        effect.id=-1;
184
 
        effect.trigger.button=0;
185
 
        effect.trigger.interval=0;
186
 
        effect.replay.length=0xffff;
187
 
        effect.replay.delay=0;
188
 
        effect.u.constant.level=0;
189
 
        effect.direction=0xC000;
190
 
        effect.u.constant.envelope.attack_length=0;
191
 
        effect.u.constant.envelope.attack_level=0;
192
 
        effect.u.constant.envelope.fade_length=0;
193
 
        effect.u.constant.envelope.fade_level=0;
194
 
 
195
 
        /* Upload effect */
196
 
        if (ioctl(device_handle,EVIOCSFF,&effect)==-1) {
197
 
                fprintf(stderr,"ERROR: uploading effect failed (%s) [%s:%d]\n",
198
 
                        strerror(errno),__FILE__,__LINE__);
199
 
                exit(1);
200
 
        }
201
 
 
202
 
        /* Start effect */
203
 
        memset(&event,0,sizeof(event));
204
 
        event.type=EV_FF;
205
 
        event.code=effect.id;
206
 
        event.value=1;
207
 
        if (write(device_handle,&event,sizeof(event))!=sizeof(event)) {
208
 
                fprintf(stderr,"ERROR: starting effect failed (%s) [%s:%d]\n",
209
 
                        strerror(errno),__FILE__,__LINE__);
210
 
                exit(1);
211
 
        }
212
 
}
213
 
 
214
 
 
215
 
/* update the device: set force and query joystick position */
216
 
void update_device(double force, double * position)
217
 
{
218
 
        struct input_event event;
219
 
 
220
 
        /* Delete effect */
221
 
        if (stop_and_play && effect.id!=-1) {
222
 
                if (ioctl(device_handle,EVIOCRMFF,effect.id)==-1) {
223
 
                        fprintf(stderr,"ERROR: removing effect failed (%s) [%s:%d]\n",
224
 
                                strerror(errno),__FILE__,__LINE__);
225
 
                        exit(1);
226
 
                }
227
 
                effect.id=-1;
228
 
        }
229
 
 
230
 
        /* Set force */
231
 
        if (force>1.0) force=1.0;
232
 
        if (force<-1.0) force=1.0;
233
 
        effect.u.constant.level=(short)(force*32767.0); /* only to be safe */
234
 
        effect.direction=0xC000;
235
 
        effect.u.constant.envelope.attack_level=(short)(force*32767.0); /* this one counts! */
236
 
        effect.u.constant.envelope.fade_level=(short)(force*32767.0); /* only to be safe */
237
 
 
238
 
        /* Upload effect */
239
 
        if (ioctl(device_handle,EVIOCSFF,&effect)==-1) {
240
 
                perror("upload effect");
241
 
                /* We do not exit here. Indeed, too frequent updates may be
242
 
                 * refused, but that is not a fatal error */
243
 
        }
244
 
 
245
 
        /* Start effect */
246
 
        if (stop_and_play && effect.id!=-1) {
247
 
                memset(&event,0,sizeof(event));
248
 
                event.type=EV_FF;
249
 
                event.code=effect.id;
250
 
                event.value=1;
251
 
                if (write(device_handle,&event,sizeof(event))!=sizeof(event)) {
252
 
                        fprintf(stderr,"ERROR: re-starting effect failed (%s) [%s:%d]\n",
253
 
                                strerror(errno),__FILE__,__LINE__);
254
 
                        exit(1);
255
 
                }
256
 
        }
257
 
 
258
 
        /* Get events */
259
 
        while (read(device_handle,&event,sizeof(event))==sizeof(event)) {
260
 
                if (event.type==EV_ABS && event.code==axis_code) {
261
 
                        *position=((double)(((short)event.value)-axis_min))*2.0/(axis_max-axis_min)-1.0;
262
 
                        if (*position>1.0) *position=1.0;
263
 
                        else if (*position<-1.0) *position=-1.0;
264
 
                }
265
 
        }
266
 
}
267
 
 
268
 
 
269
 
/* little helper to print a graph bar from a value */
270
 
void fprint_bar(FILE * file, double value, int radius)
271
 
{
272
 
        int i,c;
273
 
 
274
 
        for (i=0; i<radius*2+1; i++) {
275
 
                if (i==radius) c='|';
276
 
                else if ((i<radius && value*radius<i-radius+0.25) ||
277
 
                         (i>radius && value*radius>i-radius-0.25)) c='*';
278
 
                else if ((i<radius && value*radius<i-radius+0.75) ||
279
 
                         (i>radius && value*radius>i-radius-0.75)) c='+';
280
 
                else if (i==0) c='<';
281
 
                else if (i==radius*2) c='>';
282
 
                else c='-';
283
 
                fputc(c,file);
284
 
        }
285
 
}
286
 
 
287
 
 
288
 
/* main: perform the spring simulation */
289
 
int main(int argc, char * argv[])
290
 
{
291
 
        double time,position,center,force;
292
 
 
293
 
        /* Parse command line arguments */
294
 
        parse_args(argc,argv);
295
 
 
296
 
        /* Initialize device, create constant force effect */
297
 
        init_device();
298
 
 
299
 
        /* Print header */
300
 
        printf("\n        position                   center                     force\n");
301
 
 
302
 
        /* For ever */
303
 
        for (position=0, time=0;; time+=1.0/update_rate) {
304
 
 
305
 
                /* Spring center oscillates */
306
 
                center = sin( time * 2 * M_PI * motion_frequency ) * motion_amplitude;
307
 
 
308
 
                /* Calculate spring force */
309
 
                force = ( center - position ) * spring_strength;
310
 
                if (force >  1.0) force =  1.0;
311
 
                if (force < -1.0) force = -1.0;
312
 
 
313
 
                /* Print graph bars */
314
 
                printf("\r");
315
 
                fprint_bar(stdout,position,12);
316
 
                printf(" ");
317
 
                fprint_bar(stdout,center,12);
318
 
                printf(" ");
319
 
                fprint_bar(stdout,force,12);
320
 
                fflush(stdout);
321
 
 
322
 
                /* Set force and ask for joystick position */
323
 
                update_device(force,&position);
324
 
 
325
 
                /* Next time... */
326
 
                usleep((unsigned long)(1000000.0/update_rate));
327
 
 
328
 
        }
329
 
}