From: Doak, R. (GE Healthcare) <Rog...@me...> - 2013-06-27 12:51:06
|
/* * libusb example program to manipulate U.are.U 4000B fingerprint scanner. * Copyright (C) 2007 Daniel Drake <ds...@ge...> * * Basic image capture program only, does not consider the powerup quirks or * the fact that image encryption may be enabled. Not expected to work * flawlessly all of the time. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <getopt.h> #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <signal.h> #include <sched.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <linux/termios.h> #include <fcntl.h> #include <asm/param.h> #include <linux/timer_ioctl.h> #include <time.h> #include <libusb.h> #define LIBUSB_CALL #define bool int #define true 1 #define false 0 #define GE_VID 0x1901 /* GE */ #define U_RE_ACTIVECABLE 0x0020 // GEHC U-RE Active Cable #define U_PP_1_ACTIVECABLE 0x0021 // GEHC U-P Active Cable #define U_PP_2_ACTIVECABLE 0x0022 // GEHC U-P Active Cable #define U_PP_3_ACTIVECABLE 0x0023 // GEHC U-P Active Cable #define U_PP_4_ACTIVECABLE 0x0024 // GEHC U-P Active Cable #define U_PP_12_ACTIVECABLE 0x0029 // GEHC U-P Active Cable #define U_PP_34_ACTIVECABLE 0x002A // GEHC U-PP Active Cable // The active cable comm processor control parent tag #define ACTIVE_CABLE_CP_CONTROL 70 #define STARTUP_STATE_COMPLETE 0x000E #define NONE 0x0000 #define CONTROL_TRANSFER_TIMEOUT_MS 1000 // Request of the Active Cable hardware ID #define DOWNLOAD_HW_ID_REQUEST 0x0060 // The Active Cable hardware ID #define DOWNLOAD_HW_ID 0x0061 // Download packet with an even number of bytes #define DOWNLOAD_TAKE_BINARY_EVEN 0x0064 // Download packet with an odd number of bytes #define DOWNLOAD_TAKE_BINARY_ODD 0x0065 // Acknowledgement that a download packet was processed successfully #define DOWNLOAD_TAKE_BINARY_ACK 0x0066 #define ACTIVE_CABLE_CP_URE_DOWNLOAD 72 static const int TIMEOUT_MS = 5000; typedef struct _TLD { unsigned short Start_Of_Header; unsigned short Device_Tag; unsigned short DT_Length; unsigned int Sequence_High; unsigned int Sequence_Low; unsigned short Header_CRC; } __attribute__((packed)) TLD, *pTLD; #define TAKE_BINARY_HEADER_SIZE 4 #define CHILD_DATA_SIZE 512 #define MAX_DATA_SIZE (CHILD_DATA_SIZE - TAKE_BINARY_HEADER_SIZE) typedef struct _TLDPACKET { unsigned short Start_Of_Header; unsigned short Device_Tag; unsigned short DT_Length; unsigned int Sequence_High; unsigned int Sequence_Low; unsigned short Header_CRC; unsigned short Parent_Tag; unsigned short Parent_Length; unsigned short Child_Tag; unsigned short Child_Length; unsigned char childData[CHILD_DATA_SIZE]; } __attribute__((packed)) TLDPACKET, *pTLDPACKET; unsigned short sendSequence = 0; #define NUMBER_TRANSFERS 8 struct libusb_device_handle *dev1handle = NULL; struct libusb_device_handle *dev2handle = NULL; struct libusb_device_handle *dev3handle = NULL; struct libusb_device_handle *dev4handle = NULL; #define MAX_INTERRUPT_IN_TRANSFER_SIZE 64 unsigned char device1_bufs[NUMBER_TRANSFERS][MAX_INTERRUPT_IN_TRANSFER_SIZE]; unsigned char device2_bufs[NUMBER_TRANSFERS][MAX_INTERRUPT_IN_TRANSFER_SIZE]; unsigned char device3_bufs[NUMBER_TRANSFERS][MAX_INTERRUPT_IN_TRANSFER_SIZE]; unsigned char device4_bufs[NUMBER_TRANSFERS][MAX_INTERRUPT_IN_TRANSFER_SIZE]; struct libusb_transfer* libTransfer1[NUMBER_TRANSFERS]; struct libusb_transfer* libTransfer2[NUMBER_TRANSFERS]; struct libusb_transfer* libTransfer3[NUMBER_TRANSFERS]; struct libusb_transfer* libTransfer4[NUMBER_TRANSFERS]; TLDPACKET tldPacket; #define CRC_SIZE sizeof(unsigned short) static const int INTERRUPT_IN_ENDPOINT = 0x81; static const int INTERRUPT_OUT_ENDPOINT = 0x01; #define CRCCCITT 0x1021 /* CCITT polynomial x^16 + x^12 + x^5 + 1 */ #define CRC7_POLYNOMIAL 0x89 /* x^7 + x^3 + 1 */ #define CRC16 0x8005 /* CRC16 polynomial */ #define CRC_TAB_SIZE 256 static unsigned short calc_16bit_crc_short(unsigned short crc, int len, unsigned short *buf, unsigned short *crctab); unsigned short crc_ccitt_tbl[CRC_TAB_SIZE]; static void gen_crc_tbl(unsigned short poly, unsigned short *crctab); unsigned short calc_16bit_crc(unsigned short crc, int len, unsigned char *buf, unsigned short *crctab); #define SLE(x) ( (unsigned short) *((unsigned char *) x + 0) << 8 | \ (unsigned short) *((unsigned char *) x + 1) << 0) /* swap short endianess */ #define LLLE(x) ( (long long) *((unsigned char *) x + 0) << 56 | \ (long long) *((unsigned char *) x + 1) << 48 | \ (long long) *((unsigned char *) x + 2) << 40 | \ (long long) *((unsigned char *) x + 3) << 32 | \ (long long) *((unsigned char *) x + 4) << 24 | \ (long long) *((unsigned char *) x + 5) << 16 | \ (long long) *((unsigned char *) x + 6) << 8 | \ (long long) *((unsigned char *) x + 7) << 0) /* swap long long endianess */ static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint) { printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress); printf(" bmAttributes: %02xh\n", endpoint->bmAttributes); printf(" wMaxPacketSize: %d\n", endpoint->wMaxPacketSize); printf(" bInterval: %d\n", endpoint->bInterval); printf(" bRefresh: %d\n", endpoint->bRefresh); printf(" bSynchAddress: %d\n", endpoint->bSynchAddress); } static void print_altsetting(const struct libusb_interface_descriptor *interface) { int i; printf(" bInterfaceNumber: %d\n", interface->bInterfaceNumber); printf(" bAlternateSetting: %d\n", interface->bAlternateSetting); printf(" bNumEndpoints: %d\n", interface->bNumEndpoints); printf(" bInterfaceClass: %d\n", interface->bInterfaceClass); printf(" bInterfaceSubClass: %d\n", interface->bInterfaceSubClass); printf(" bInterfaceProtocol: %d\n", interface->bInterfaceProtocol); printf(" iInterface: %d\n", interface->iInterface); for (i = 0; i < interface->bNumEndpoints; i++) print_endpoint(&interface->endpoint[i]); } static void print_interface(const struct libusb_interface *interface) { int i; for (i = 0; i < interface->num_altsetting; i++) print_altsetting(&interface->altsetting[i]); } static void print_configuration(struct libusb_config_descriptor *config) { int i; printf(" wTotalLength: %d\n", config->wTotalLength); printf(" bNumInterfaces: %d\n", config->bNumInterfaces); printf(" bConfigurationValue: %d\n", config->bConfigurationValue); printf(" iConfiguration: %d\n", config->iConfiguration); printf(" bmAttributes: %02xh\n", config->bmAttributes); printf(" MaxPower: %d\n", config->MaxPower); for (i = 0; i < config->bNumInterfaces; i++) print_interface(&config->interface[i]); } void print_descriptor(struct libusb_device_descriptor *desc) { printf(" bLength: %02xh\n", desc->bLength); printf(" bDescriptorType: %02xh\n", desc->bDescriptorType); printf(" bcdUSB: %04xh\n", desc->bcdUSB); printf(" bDeviceClass: %02xh\n", desc->bDeviceClass); printf(" bDeviceSubClass: %02xh\n", desc->bDeviceSubClass); printf(" bDeviceProtocol: %02xh\n", desc->bDeviceProtocol); printf(" bMaxPacketSize0: %02xh\n", desc->bMaxPacketSize0); printf(" idVendor: %04xh\n", desc->idVendor); printf(" idProduct: %04xh\n", desc->idProduct); printf(" bcdDevice: %04xh\n", desc->bcdDevice); printf(" iManufacturer: %02xh\n", desc->iManufacturer); printf(" iProduct: %02xh\n", desc->iProduct); printf(" iSerialNumber: %02xh\n", desc->iSerialNumber); printf(" bNumConfigurations: %02xh\n", desc->bNumConfigurations); } /*------------------------------------------------------------------------------ FUNCTION: int sendUsb() PURPOSE: Sends a control packet to the ST specific USB Device ARGUMENTS: none RETURNS: int: libusb_interrupt_transfer status ------------------------------------------------------------------------------*/ int sendUsb(libusb_device_handle *devHandle, unsigned char* pData, unsigned short dataSize, long responseTimeoutMS) { int sendReturn = 1; int bytesTransferred = 0; unsigned char sendBuf[MAX_INTERRUPT_IN_TRANSFER_SIZE]; int writeReturn = 0; while((dataSize != 0) && (writeReturn == 0)) { int writeSize = ((unsigned short)(MAX_INTERRUPT_IN_TRANSFER_SIZE-1) < dataSize ? (unsigned short)(MAX_INTERRUPT_IN_TRANSFER_SIZE-1) : dataSize); sendBuf[0] = writeSize; memcpy(&sendBuf[1],pData,writeSize); writeReturn = libusb_interrupt_transfer(devHandle, INTERRUPT_OUT_ENDPOINT, sendBuf, writeSize+1, &bytesTransferred, responseTimeoutMS); if((writeReturn == 0) && (bytesTransferred == writeSize+1)) { dataSize -= writeSize; pData += writeSize; } else { sendReturn = 0; } } return sendReturn; } /*------------------------------------------------------------------------------ FUNCTION: int sendCableMessage() PURPOSE: Sends a control packet to the ST specific USB Device ARGUMENTS: none RETURNS: 1: if the packet was successfully sent and reply received if requested ------------------------------------------------------------------------------*/ int sendCableMessage(libusb_device_handle *devHandle, const unsigned short dasParentTag, const unsigned short dasChildTag, const unsigned short dataSize, const unsigned short responseChildTag, long responseTimeoutMS) { tldPacket.Start_Of_Header = htons(0x5eed); tldPacket.Device_Tag = htons(0xbade); unsigned short numShorts = (dataSize + 1)/2; numShorts += 4; // parent, parent length, child, child length tldPacket.DT_Length = htons(numShorts); tldPacket.Sequence_High = 0; sendSequence++; tldPacket.Sequence_Low = htonl(sendSequence); unsigned short crc_calc = calc_16bit_crc_short( 0, (sizeof(TLD) - sizeof(tldPacket.Header_CRC) ) / 2 , &tldPacket.Start_Of_Header, crc_ccitt_tbl ); tldPacket.Header_CRC = htons(crc_calc); tldPacket.Parent_Tag = htons(dasParentTag); numShorts -= 2; tldPacket.Parent_Length = htons(numShorts); tldPacket.Child_Tag = htons(dasChildTag); numShorts -= 2; tldPacket.Child_Length = htons(numShorts); numShorts += 12; crc_calc = calc_16bit_crc_short( 0, numShorts, &tldPacket.Start_Of_Header, crc_ccitt_tbl ); unsigned short *pCRC = (unsigned short *)&tldPacket.childData[dataSize]; *pCRC = htons(crc_calc); numShorts += 1; // add 1 for the packet CRC return sendUsb(devHandle, (unsigned char*)&tldPacket.Start_Of_Header, numShorts * 2, responseTimeoutMS); } void LIBUSB_CALL dumpTransfer(struct libusb_transfer *transfer) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) printf("Invalid transfer status %d\n", transfer->status); if (libusb_submit_transfer(transfer) < 0) printf("Failed submit transfer\n"); } bool openDevice(libusb_device_handle **devHandle, unsigned short device, unsigned char device_bufs[NUMBER_TRANSFERS][MAX_INTERRUPT_IN_TRANSFER_SIZE], struct libusb_transfer* libTransfer[NUMBER_TRANSFERS]) { bool openReturn = true; int libUsbReturn = 0; *devHandle = libusb_open_device_with_vid_pid(NULL, GE_VID, device); if(devHandle == NULL) { printf("Could not open device: %d\n", device); return false; } printf("opened device: %d\n", device); if (libusb_kernel_driver_active(*devHandle, 0) == 1) { //find out if kernel driver is attached printf("Kernel Driver Active\n"); if (libusb_detach_kernel_driver(*devHandle, 0) == 0) //detach it printf("Kernel Driver Detached!\n"); } int r = libusb_claim_interface(*devHandle, 0); if (r < 0) { printf("usb_claim_interface %d error %d %s\n",device, r, strerror(-r)); libusb_close(*devHandle); return false; } printf("claimed STMicro interface\n"); int i; for(i = 0; (i < NUMBER_TRANSFERS) && openReturn; i++) { /* Allocate a libusb transfer with a specified number of isochronous packet * descriptors. The returned transfer is pre-initialized for you. When the new * transfer is no longer needed, it should be freed with libusb_free_transfer(). * Interrupt transfer will use 0 isochronous packet descriptors */ libTransfer[i] = libusb_alloc_transfer(0); if(libTransfer[i] != NULL) { /* Helper function to populate the required \ref libusb_transfer fields for an interrupt transfer. */ libusb_fill_interrupt_transfer(libTransfer[i], *devHandle, INTERRUPT_IN_ENDPOINT, device_bufs[i], MAX_INTERRUPT_IN_TRANSFER_SIZE, dumpTransfer, 0, 0); /* Submit a transfer. This function will fire off the USB transfer and then return immediately. */ libUsbReturn = libusb_submit_transfer(libTransfer[i]); if(libUsbReturn != 0) { printf("Failed to submit transfer %d", i); openReturn = false; } } else { printf("Could not allocate transfer buffer %d", i); openReturn = false; } } if(!openReturn) { libusb_close(*devHandle); } return openReturn; } bool initDevice(libusb_device_handle *devHandle) { printf("Sending message to begin data transfer\n"); if(sendCableMessage(devHandle, ACTIVE_CABLE_CP_CONTROL, STARTUP_STATE_COMPLETE, 0, NONE, CONTROL_TRANSFER_TIMEOUT_MS)) { printf("Sent\n"); return true; } else { printf("Send Error\n"); return false; } } static void *poll_thread_main(libusb_context *ctx) { printf("Entered poll thread main\n"); while(1) libusb_handle_events(ctx); } static int set_realtime_priority(int sched_mode) { struct sched_param schp; /* * set the process to realtime privs */ memset(&schp, 0, sizeof(schp)); schp.sched_priority = sched_get_priority_max(sched_mode); if (sched_setscheduler(0, sched_mode, &schp) != 0) { fprintf(stderr, "sched_setscheduler\n"); return -1; } return 0; } int main(int argc, char **argv) { pthread_attr_t threadAttribute = {0}; pthread_t poll_thread; gen_crc_tbl(CRCCCITT, crc_ccitt_tbl); /* generate crc tables */ int r = libusb_init(NULL); if (r < 0) { fprintf(stderr, "failed to initialize libusb\n"); exit(1); } printf("Initialized libusb\n"); // libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation set_realtime_priority(SCHED_FIFO); printf("Set realtime priority\n"); r = pthread_attr_init( &threadAttribute ); if ( r == -1 ) { fprintf(stderr, "pthread_attr_init\n"); goto out; } printf("Thread Attribute init\n"); r = pthread_attr_setschedpolicy( &threadAttribute, SCHED_FIFO ); if ( r == -1 ) { fprintf(stderr, "pthread_attr_setschedpolicy\n"); goto out; } printf("Thread set schedule policy\n"); r = pthread_attr_setinheritsched(&threadAttribute, PTHREAD_EXPLICIT_SCHED); if ( r == -1 ) { fprintf(stderr, "pthread_attr_setinheritsche\n"); goto out; } printf("Thread set inherited schedule\n"); r = pthread_create(&poll_thread, &threadAttribute, (void *) poll_thread_main, NULL); if (r) goto out; printf("Poll thread created\n"); if(!openDevice(&dev1handle, U_RE_ACTIVECABLE, device1_bufs, libTransfer1)) goto out; printf("Device 1 created\n"); if(!initDevice(dev1handle)) goto out; printf("Device 1 started\n"); if(!openDevice(&dev2handle, U_PP_1_ACTIVECABLE, device2_bufs, libTransfer2)) goto out; printf("Device 2 created\n"); if(!initDevice(dev2handle)) goto out; printf("Device 2 started\n"); if(!openDevice(&dev3handle, U_PP_12_ACTIVECABLE, device3_bufs, libTransfer3)) goto out; printf("Device 3 created\n"); if(!initDevice(dev3handle)) goto out; printf("Device 3 started\n"); if(!openDevice(&dev4handle, U_PP_34_ACTIVECABLE, device4_bufs, libTransfer4)) goto out; printf("Device 4 created\n"); if(!initDevice(dev4handle)) goto out; printf("Device 4 started\n"); printf("Sleeping...\n"); while(1) { sleep(1); } out: libusb_exit(NULL); return r >= 0 ? r : -r; } static void gen_crc_tbl(unsigned short poly, unsigned short *crctab) { int data, i, cntr; unsigned short accum; for (cntr = 0; cntr < CRC_TAB_SIZE; ++cntr) { accum = 0; data = cntr << 8; /* data to high byte */ for (i = 8; i > 0; --i) { if ((data ^ accum) & 0x8000) /* if msb of (data XOR accum) is TRUE */ accum = (accum << 1) ^ poly; /* shift and subtract poly */ else accum <<= 1; /* otherwise, transparent shift */ data <<= 1; /* move up next bit for XOR */ } crctab[cntr] = accum; } } /* calculate 16 bit crc from byte stream */ unsigned short calc_16bit_crc(unsigned short crc, int len, unsigned char *buf, unsigned short *crctab) { for (; len > 0; len--, buf++) crc = (crc << 8) ^ crctab[(crc >> 8) ^ *buf]; return(crc); } /* this might be faster result = ~*p++; { result = crctab[result & 0xff] ^ result >> 8; result = crctab[result & 0xff] ^ result >> 8; result = crctab[result & 0xff] ^ result >> 8; result = crctab[result & 0xff] ^ result >> 8; result ^= *p++; } return ~result; } */ /* calculate 16 bit crc from "short" stream */ static unsigned short calc_16bit_crc_short(unsigned short crc, int len, unsigned short *buf, unsigned short *crctab) { unsigned short temp; for (; len > 0; len--) { /* do both bytes, the stream is big and we're little so do the lsb first */ temp = *buf++; crc = (crc << 8) ^ crctab[(crc >> 8) ^ (temp & 0xff)]; crc = (crc << 8) ^ crctab[(crc >> 8) ^ (temp >> 8)]; } return(crc); } |