Fix issue 1) not recognizes some usb device, 2) reconnect when ffmpeg encoder error
[rtmpclient.git] / app / src / main / jni / libusb / examples / dpfp_threaded.c
1 /*
2  * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
3  * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
4  *
5  * Basic image capture program only, does not consider the powerup quirks or
6  * the fact that image encryption may be enabled. Not expected to work
7  * flawlessly all of the time.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 #include <errno.h>
25 #include <pthread.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "libusb.h"
32
33 #define EP_INTR                 (1 | LIBUSB_ENDPOINT_IN)
34 #define EP_DATA                 (2 | LIBUSB_ENDPOINT_IN)
35 #define CTRL_IN                 (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
36 #define CTRL_OUT                (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
37 #define USB_RQ                  0x04
38 #define INTR_LENGTH             64
39
40 enum {
41         MODE_INIT = 0x00,
42         MODE_AWAIT_FINGER_ON = 0x10,
43         MODE_AWAIT_FINGER_OFF = 0x12,
44         MODE_CAPTURE = 0x20,
45         MODE_SHUT_UP = 0x30,
46         MODE_READY = 0x80,
47 };
48
49 static int next_state(void);
50
51 enum {
52         STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
53         STATE_AWAIT_IRQ_FINGER_DETECTED,
54         STATE_AWAIT_MODE_CHANGE_CAPTURE,
55         STATE_AWAIT_IMAGE,
56         STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
57         STATE_AWAIT_IRQ_FINGER_REMOVED,
58 };
59
60 static int state = 0;
61 static struct libusb_device_handle *devh = NULL;
62 static unsigned char imgbuf[0x1b340];
63 static unsigned char irqbuf[INTR_LENGTH];
64 static struct libusb_transfer *img_transfer = NULL;
65 static struct libusb_transfer *irq_transfer = NULL;
66 static int img_idx = 0;
67 static int do_exit = 0;
68
69 static pthread_t poll_thread;
70 static pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
71 static pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER;
72
73 static void request_exit(int code)
74 {
75         do_exit = code;
76         pthread_cond_signal(&exit_cond);
77 }
78
79 static void *poll_thread_main(void *arg)
80 {
81         int r = 0;
82         printf("poll thread running\n");
83
84         while (!do_exit) {
85                 struct timeval tv = { 1, 0 };
86                 r = libusb_handle_events_timeout(NULL, &tv);
87                 if (r < 0) {
88                         request_exit(2);
89                         break;
90                 }
91         }
92
93         printf("poll thread shutting down\n");
94         return NULL;
95 }
96
97 static int find_dpfp_device(void)
98 {
99         devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
100         return devh ? 0 : -EIO;
101 }
102
103 static int print_f0_data(void)
104 {
105         unsigned char data[0x10];
106         int r;
107         unsigned int i;
108
109         r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
110                 sizeof(data), 0);
111         if (r < 0) {
112                 fprintf(stderr, "F0 error %d\n", r);
113                 return r;
114         }
115         if ((unsigned int) r < sizeof(data)) {
116                 fprintf(stderr, "short read (%d)\n", r);
117                 return -1;
118         }
119
120         printf("F0 data:");
121         for (i = 0; i < sizeof(data); i++)
122                 printf("%02x ", data[i]);
123         printf("\n");
124         return 0;
125 }
126
127 static int get_hwstat(unsigned char *status)
128 {
129         int r;
130
131         r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
132         if (r < 0) {
133                 fprintf(stderr, "read hwstat error %d\n", r);
134                 return r;
135         }
136         if ((unsigned int) r < 1) {
137                 fprintf(stderr, "short read (%d)\n", r);
138                 return -1;
139         }
140
141         printf("hwstat reads %02x\n", *status);
142         return 0;
143 }
144
145 static int set_hwstat(unsigned char data)
146 {
147         int r;
148
149         printf("set hwstat to %02x\n", data);
150         r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
151         if (r < 0) {
152                 fprintf(stderr, "set hwstat error %d\n", r);
153                 return r;
154         }
155         if ((unsigned int) r < 1) {
156                 fprintf(stderr, "short write (%d)", r);
157                 return -1;
158         }
159
160         return 0;
161 }
162
163 static int set_mode(unsigned char data)
164 {
165         int r;
166         printf("set mode %02x\n", data);
167
168         r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
169         if (r < 0) {
170                 fprintf(stderr, "set mode error %d\n", r);
171                 return r;
172         }
173         if ((unsigned int) r < 1) {
174                 fprintf(stderr, "short write (%d)", r);
175                 return -1;
176         }
177
178         return 0;
179 }
180
181 static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
182 {
183         if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
184                 fprintf(stderr, "mode change transfer not completed!\n");
185                 request_exit(2);
186         }
187
188         printf("async cb_mode_changed length=%d actual_length=%d\n",
189                 transfer->length, transfer->actual_length);
190         if (next_state() < 0)
191                 request_exit(2);
192 }
193
194 static int set_mode_async(unsigned char data)
195 {
196         unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
197         struct libusb_transfer *transfer;
198
199         if (!buf)
200                 return -ENOMEM;
201
202         transfer = libusb_alloc_transfer(0);
203         if (!transfer) {
204                 free(buf);
205                 return -ENOMEM;
206         }
207
208         printf("async set mode %02x\n", data);
209         libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
210         buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
211         libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
212                 1000);
213
214         transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
215                 | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
216         return libusb_submit_transfer(transfer);
217 }
218
219 static int do_sync_intr(unsigned char *data)
220 {
221         int r;
222         int transferred;
223
224         r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
225                 &transferred, 1000);
226         if (r < 0) {
227                 fprintf(stderr, "intr error %d\n", r);
228                 return r;
229         }
230         if (transferred < INTR_LENGTH) {
231                 fprintf(stderr, "short read (%d)\n", r);
232                 return -1;
233         }
234
235         printf("recv interrupt %04x\n", *((uint16_t *) data));
236         return 0;
237 }
238
239 static int sync_intr(unsigned char type)
240 {
241         int r;
242         unsigned char data[INTR_LENGTH];
243
244         while (1) {
245                 r = do_sync_intr(data);
246                 if (r < 0)
247                         return r;
248                 if (data[0] == type)
249                         return 0;
250         }
251 }
252
253 static int save_to_file(unsigned char *data)
254 {
255         FILE *fd;
256         char filename[64];
257
258         snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
259         fd = fopen(filename, "w");
260         if (!fd)
261                 return -1;
262
263         fputs("P5 384 289 255 ", fd);
264         (void) fwrite(data + 64, 1, 384*289, fd);
265         fclose(fd);
266         printf("saved image to %s\n", filename);
267         return 0;
268 }
269
270 static int next_state(void)
271 {
272         int r = 0;
273         printf("old state: %d\n", state);
274         switch (state) {
275         case STATE_AWAIT_IRQ_FINGER_REMOVED:
276                 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
277                 r = set_mode_async(MODE_AWAIT_FINGER_ON);
278                 break;
279         case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
280                 state = STATE_AWAIT_IRQ_FINGER_DETECTED;
281                 break;
282         case STATE_AWAIT_IRQ_FINGER_DETECTED:
283                 state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
284                 r = set_mode_async(MODE_CAPTURE);
285                 break;
286         case STATE_AWAIT_MODE_CHANGE_CAPTURE:
287                 state = STATE_AWAIT_IMAGE;
288                 break;
289         case STATE_AWAIT_IMAGE:
290                 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
291                 r = set_mode_async(MODE_AWAIT_FINGER_OFF);
292                 break;
293         case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
294                 state = STATE_AWAIT_IRQ_FINGER_REMOVED;
295                 break;
296         default:
297                 printf("unrecognised state %d\n", state);
298         }
299         if (r < 0) {
300                 fprintf(stderr, "error detected changing state\n");
301                 return r;
302         }
303
304         printf("new state: %d\n", state);
305         return 0;
306 }
307
308 static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
309 {
310         unsigned char irqtype = transfer->buffer[0];
311
312         if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
313                 fprintf(stderr, "irq transfer status %d?\n", transfer->status);
314                 irq_transfer = NULL;
315                 request_exit(2);
316                 return;
317         }
318
319         printf("IRQ callback %02x\n", irqtype);
320         switch (state) {
321         case STATE_AWAIT_IRQ_FINGER_DETECTED:
322                 if (irqtype == 0x01) {
323                         if (next_state() < 0) {
324                                 request_exit(2);
325                                 return;
326                         }
327                 } else {
328                         printf("finger-on-sensor detected in wrong state!\n");
329                 }
330                 break;
331         case STATE_AWAIT_IRQ_FINGER_REMOVED:
332                 if (irqtype == 0x02) {
333                         if (next_state() < 0) {
334                                 request_exit(2);
335                                 return;
336                         }
337                 } else {
338                         printf("finger-on-sensor detected in wrong state!\n");
339                 }
340                 break;
341         }
342         if (libusb_submit_transfer(irq_transfer) < 0)
343                 request_exit(2);
344 }
345
346 static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
347 {
348         if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
349                 fprintf(stderr, "img transfer status %d?\n", transfer->status);
350                 img_transfer = NULL;
351                 request_exit(2);
352                 return;
353         }
354
355         printf("Image callback\n");
356         save_to_file(imgbuf);
357         if (next_state() < 0) {
358                 request_exit(2);
359                 return;
360         }
361         if (libusb_submit_transfer(img_transfer) < 0)
362                 request_exit(2);
363 }
364
365 static int init_capture(void)
366 {
367         int r;
368
369         r = libusb_submit_transfer(irq_transfer);
370         if (r < 0)
371                 return r;
372
373         r = libusb_submit_transfer(img_transfer);
374         if (r < 0) {
375                 libusb_cancel_transfer(irq_transfer);
376                 while (irq_transfer)
377                         if (libusb_handle_events(NULL) < 0)
378                                 break;
379                 return r;
380         }
381
382         /* start state machine */
383         state = STATE_AWAIT_IRQ_FINGER_REMOVED;
384         return next_state();
385 }
386
387 static int do_init(void)
388 {
389         unsigned char status;
390         int r;
391
392         r = get_hwstat(&status);
393         if (r < 0)
394                 return r;
395
396         if (!(status & 0x80)) {
397                 r = set_hwstat(status | 0x80);
398                 if (r < 0)
399                         return r;
400                 r = get_hwstat(&status);
401                 if (r < 0)
402                         return r;
403         }
404
405         status &= ~0x80;
406         r = set_hwstat(status);
407         if (r < 0)
408                 return r;
409
410         r = get_hwstat(&status);
411         if (r < 0)
412                 return r;
413
414         r = sync_intr(0x56);
415         if (r < 0)
416                 return r;
417
418         return 0;
419 }
420
421 static int alloc_transfers(void)
422 {
423         img_transfer = libusb_alloc_transfer(0);
424         if (!img_transfer)
425                 return -ENOMEM;
426
427         irq_transfer = libusb_alloc_transfer(0);
428         if (!irq_transfer)
429                 return -ENOMEM;
430
431         libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
432                 sizeof(imgbuf), cb_img, NULL, 0);
433         libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
434                 sizeof(irqbuf), cb_irq, NULL, 0);
435
436         return 0;
437 }
438
439 static void sighandler(int signum)
440 {
441         request_exit(1);
442 }
443
444 int main(void)
445 {
446         struct sigaction sigact;
447         int r = 1;
448
449         r = libusb_init(NULL);
450         if (r < 0) {
451                 fprintf(stderr, "failed to initialise libusb\n");
452                 exit(1);
453         }
454
455         r = find_dpfp_device();
456         if (r < 0) {
457                 fprintf(stderr, "Could not find/open device\n");
458                 goto out;
459         }
460
461         r = libusb_claim_interface(devh, 0);
462         if (r < 0) {
463                 fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
464                 goto out;
465         }
466         printf("claimed interface\n");
467
468         r = print_f0_data();
469         if (r < 0)
470                 goto out_release;
471
472         r = do_init();
473         if (r < 0)
474                 goto out_deinit;
475
476         /* async from here onwards */
477
478         sigact.sa_handler = sighandler;
479         sigemptyset(&sigact.sa_mask);
480         sigact.sa_flags = 0;
481         sigaction(SIGINT, &sigact, NULL);
482         sigaction(SIGTERM, &sigact, NULL);
483         sigaction(SIGQUIT, &sigact, NULL);
484
485         r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL);
486         if (r)
487                 goto out_deinit;
488
489         r = alloc_transfers();
490         if (r < 0) {
491                 request_exit(1);
492                 pthread_join(poll_thread, NULL);
493                 goto out_deinit;
494         }
495
496         r = init_capture();
497         if (r < 0) {
498                 request_exit(1);
499                 pthread_join(poll_thread, NULL);
500                 goto out_deinit;
501         }
502
503         while (!do_exit) {
504                 pthread_mutex_lock(&exit_cond_lock);
505                 pthread_cond_wait(&exit_cond, &exit_cond_lock);
506                 pthread_mutex_unlock(&exit_cond_lock);
507         }
508
509         printf("shutting down...\n");
510         pthread_join(poll_thread, NULL);
511
512         r = libusb_cancel_transfer(irq_transfer);
513         if (r < 0) {
514                 request_exit(1);
515                 goto out_deinit;
516         }
517
518         r = libusb_cancel_transfer(img_transfer);
519         if (r < 0) {
520                 request_exit(1);
521                 goto out_deinit;
522         }
523
524         while (img_transfer || irq_transfer)
525                 if (libusb_handle_events(NULL) < 0)
526                         break;
527
528         if (do_exit == 1)
529                 r = 0;
530         else
531                 r = 1;
532
533 out_deinit:
534         libusb_free_transfer(img_transfer);
535         libusb_free_transfer(irq_transfer);
536         set_mode(0);
537         set_hwstat(0x80);
538 out_release:
539         libusb_release_interface(devh, 0);
540 out:
541         libusb_close(devh);
542         libusb_exit(NULL);
543         return r >= 0 ? r : -r;
544 }