libusb_close()之后第二次尝试读取超时

时间:2014-04-03 23:46:47

标签: libusb

我的linux应用程序可以使用libusb对设备执行许多IO操作。但是,如果我关闭然后重新打开对设备的访问权限,则所有读取操作都将超时。我假设我的密码不完整,但我找不到我的错误。

示例程序具有以下功能:

  • deviceCount(),返回与我的VID / PID匹配的设备数
  • deviceOpen()打开与设备的连接
  • deviceClose()关闭与设备的连接并“清理”
  • deviceWrite()将特定数量的字节写入我的设备
  • deviceRead()从我的设备读取特定数量的字节
  • deviceReadRegisters()一个特定于我的设备的函数,它执行写操作,然后执行读取
  • runTest()一个以合理的顺序调用上述所有内容的函数
  • main()尝试多次调用runTest()的主函数。

请注意,在运行程序并获得超时错误后,我需要重新启动设备以进行恢复。在没有电源循环的情况下重新运行我的测试程序是不够的。然后在第一次调用runTest()时失败。

在当前的实现中,我只调用一次libusb_init()和libusb_exit()。我也尝试过每次通过runTest()函数调用这些函数。这没有任何区别。

我猜我在deviceClose()函数中做错了。任何见解将不胜感激。

提前致谢! - 杰夫

#######示例输出
main() attempting to runTest(), i: 0
runTest() Starting!
runTest() Success calling libusb_init()
runTest() Number of devices: 1
deviceOpen() Number of alternate settings: 1
deviceOpen() Interface number: 0 number of endpoints: 5
deviceOpen() Descriptor type: 5 EP Address: 0x02 2
deviceOpen() Found outPort! outPort: 2 index: 0
deviceOpen() Descriptor type: 5 EP Address: 0x84 132
deviceOpen() Descriptor type: 5 EP Address: 0x86 134
deviceOpen() Found inPort! inPort: 134 index: 2
deviceOpen() Descriptor type: 5 EP Address: 0x01 1
deviceOpen() Descriptor type: 5 EP Address: 0x81 129
deviceOpen() Found device! VID: 0x0957 PID: 0x5f18 outPort: 2 inPort: 134
deviceOpen() Success calling libusb_claim_interface( ) handle: 0x88cd140
deviceOpen() Successful open! id: 0 handle: 0x88cd140
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceClose() Sucess calling libusb_release_interface( ) handle: 0x88cd140
deviceClose() Sucess calling libusb_close( ) handle: 0x88cd140
deviceClose() Success calling libusb_free_device_list( ) devs: 0x88cd170
runTest() Success!
main() attempting to runTest(), i: 1    <== this is the second call to runTest( )
runTest() Starting!
runTest() Number of devices: 1
deviceOpen() Number of alternate settings: 1
deviceOpen() Interface number: 0 number of endpoints: 5
deviceOpen() Descriptor type: 5 EP Address: 0x02 2
deviceOpen() Found outPort! outPort: 2 index: 0
deviceOpen() Descriptor type: 5 EP Address: 0x84 132
deviceOpen() Descriptor type: 5 EP Address: 0x86 134
deviceOpen() Found inPort! inPort: 134 index: 2
deviceOpen() Descriptor type: 5 EP Address: 0x01 1
deviceOpen() Descriptor type: 5 EP Address: 0x81 129
deviceOpen() Found device! VID: 0x0957 PID: 0x5f18 outPort: 2 inPort: 134
deviceOpen() Success calling libusb_claim_interface( ) handle: 0x88cd140
deviceOpen() Successful open! id: 0 handle: 0x88cd140
deviceWrite() Success writing 2 bytes
deviceRead() Problem reading 146 bytes, read only 0 bytes, inPort: 134 timeout: 2000 LIBUSB_ERROR_TIMEOUT
#######测试计划
// Test program demonstrating timeout problem following libusb_close()
//
// g++ -o libUsbTest libUsbTest.cpp -I /usr/local/include/libusb-1.0 -L /usr/local/lib -l usb-1.0
//
// sudo ./libUsbTest

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <libusb.h>

// for test purposes, using global variable
libusb_device **devs = NULL;
libusb_device_handle *handle = NULL;  // non-null when device is open
libusb_context *usbContext = NULL;
unsigned short outPort = 0;
unsigned short inPort = 0;

#define VID 0x957
#define PID 0x5f18

#define OUTPUT_ENDPOINT 2
#define INPUT_ENDPOINT 6

// Returns the number of devices matching our VID / PID
// A negative return value indicates a failure
int deviceCount( ) {
    int count = 0;
    if (devs) 
    {
        // Note this automatically dereferrences each device
        libusb_free_device_list(devs, 1);
        devs = NULL;
    }
    ssize_t cnt;

    cnt = libusb_get_device_list(usbContext, &devs);
    if (cnt < 0 || devs == 0)
    {
        fprintf(stderr,"deviceCount() Failed libusb_get_device_list()!\n");
        return -1;
    }

    // Walk through the device list and count those that match our VID / PID
    libusb_device *dev = NULL;
    count = 0;
    int i = 0;

    while ((dev = devs[i++]) != NULL) {
        struct libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(dev, &desc);
        if (r < 0) {
            fprintf(stderr, "deviceCount() Failed libusb_get_device_descriptor()!\n");
            return -1;
        }

        if (desc.idVendor == VID && desc.idProduct == PID) 
        {
            count++;
        }
    }

    return count;
}

// Open the USB device. Only one device can be open at a time because of the above global variables
// Returns negative number for errors
int deviceOpen( int id) {
    if (!usbContext) {
        fprintf(stderr,"deviceOpen() Can't open! Null usbContext!\n");
        return -1;
    }

    if (handle) {
        fprintf(stderr,"deviceOpen() Device already open!\n");
        return 0;
    }

    if (devs == 0) {
        fprintf(stderr,"deviceOpen() Can't open! Null devs!\n");
        return -1;
    }

    // Walk through the same device list and stop when we get to the desired sensor VID / PID
    libusb_device *dev = NULL;
    int count = 0;
    bool keepGoing = true;
    int i = 0;

    while ((dev = devs[i++]) != NULL && keepGoing) {
        struct libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(dev, &desc);
        if (r < 0) {
            fprintf(stderr, "deviceOpen() Failed libusb_get_device_descriptor()!\n");
            return -1;
        }

        if (desc.idVendor == VID && desc.idProduct == PID) 
        {
            if (count == id) {
                // Match!
                keepGoing = false;

                // Get the out and input ports
                libusb_config_descriptor *config;
                libusb_get_config_descriptor( dev, 0, &config);

                const libusb_interface *inter;
                const libusb_interface_descriptor *interdesc;
                const libusb_endpoint_descriptor *epdesc;
                for (int i=0; i<(int)config->bNumInterfaces; i++)
                {
                    inter = &config->interface[i];
                    fprintf(stderr,"deviceOpen() Number of alternate settings: %d\n", inter->num_altsetting);

                    for (int j=0; j<inter->num_altsetting; j++)
                    {
                        interdesc = &inter->altsetting[j];
                        fprintf(stderr, "deviceOpen() Interface number: %d number of endpoints: %d\n",
                            interdesc->bInterfaceNumber, interdesc->bNumEndpoints);

                        for (int k=0; k<interdesc->bNumEndpoints; k++)
                        {
                            epdesc = &interdesc->endpoint[k];
                            fprintf(stderr, "deviceOpen() Descriptor type: %d EP Address: 0x%2.2x %d\n",
                                epdesc->bDescriptorType, epdesc->bEndpointAddress, epdesc->bEndpointAddress);

                            if (epdesc->bDescriptorType == LIBUSB_DT_ENDPOINT) 
                            {
                                // Found an endpoint
                                uint8_t address = epdesc->bEndpointAddress & 0xf;
                                bool input = (epdesc->bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN;

                                if ( address == OUTPUT_ENDPOINT && input == false)
                                {
                                    outPort = epdesc->bEndpointAddress;
                                    fprintf(stderr, "deviceOpen() Found outPort! outPort: %d index: %d\n", outPort, k);
                                }

                                if ( address == INPUT_ENDPOINT && input == true)
                                {
                                    inPort = epdesc->bEndpointAddress;
                                    fprintf(stderr, "deviceOpen() Found inPort! inPort: %d index: %d\n", inPort, k);
                                }
                            }
                        } // endpoints}
                    } // num_altsetting
                } // interfaces

                libusb_free_config_descriptor( config);

                // Open device
                fprintf(stderr,  "deviceOpen() Found device! VID: 0x%4.4x PID: 0x%4.4x outPort: %d inPort: %d\n", VID, PID, outPort, inPort);
                libusb_error errCode;
                errCode = (libusb_error) libusb_open( dev, &handle);
                if (errCode) 
                {
                    fprintf(stderr, "deviceOpen() Failed in libusb_open(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
                    return -1;
                }

                // Verify not in use by kernel
                if (libusb_kernel_driver_active( handle, 0))
                {
                    // FIXME: we could call libusb_detach_kernel_driver( ) here
                    fprintf(stderr, "deviceOpen() Failed! kernel owns device!\n");
                    return -1;
                }

                // Claim the interface.
                errCode = (libusb_error) libusb_claim_interface( handle, 0);
                if (errCode) 
                {
                    fprintf(stderr, "deviceOpen() Failed in libusb_claim_interface(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
                    return -1;
                }
                fprintf(stderr,  "deviceOpen() Success calling libusb_claim_interface( ) handle: %p\n", handle);


            } else {
                count++;
            }
        }       // desired VID / PID
    }           // Walk device list
    fprintf(stderr, "deviceOpen() Successful open! id: %d handle: %p\n", id, handle);
    return 0;
}

// Close the USB device
// Returns negative number for errors
int deviceClose() {
    if (handle)
    {
        // Release the interface.
        libusb_error errCode = (libusb_error) libusb_release_interface( handle, 0);
        if (errCode) 
        {
            fprintf(stderr, "deviceClose() Failed in libusb_release_interface(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
            return -1;
        }
        fprintf(stderr, "deviceClose() Sucess calling libusb_release_interface( ) handle: %p\n", handle);

        libusb_close( handle);
        fprintf(stderr, "deviceClose() Sucess calling libusb_close( ) handle: %p\n", handle);
        handle = NULL;
    }

    if (devs) 
    {
        // Note this automatically dereferrences each device
        libusb_free_device_list(devs, 1);
        fprintf(stderr, "deviceClose() Success calling libusb_free_device_list( ) devs: %p\n", devs);
        devs = NULL;
    }
    outPort = 0;
    inPort = 0;
    return 0;
}

// Write to the device. 
// Returns number of bytes written. Negative return value indicates an error
int deviceWrite( unsigned char *addr, int len){
    if (!handle || !outPort) { 
        fprintf(stderr, "deviceWrite() No handle or outPort!\n");
        return -1;
    }

    libusb_error errCode;
    int transferred;
    unsigned int timeout = 2000;

    errCode = (libusb_error) libusb_bulk_transfer( handle, outPort, addr, len, &transferred, timeout);

    if (errCode || transferred != len) {
        fprintf(stderr, "deviceWrite() Problem writing %d bytes, wrote only %d bytes, outPort: %d timeout: %d %s\n", 
            len, transferred, outPort, timeout, libusb_error_name(errCode));
        return -1;
    }

    fprintf(stderr, "deviceWrite() Success writing %ld bytes\n", transferred);
    return transferred;
}

// Read from the device. 
// Returns number of bytes read. Negative return value indicates an error
int deviceRead( unsigned char *addr, int len){
    if (!handle || !outPort) { 
        fprintf(stderr, "deviceRead() No handle or outPort!\n");
        return -1;
    }

    libusb_error errCode;
    int transferred;
    unsigned int timeout = 2000;

    errCode = (libusb_error) libusb_bulk_transfer( handle, inPort, addr, len, &transferred, timeout);

    if (errCode || (transferred != len)) {
        fprintf(stderr, "deviceRead() Problem reading %ld bytes, read only %ld bytes, inPort: %d timeout: %d %s\n",
            len, transferred, inPort, timeout, libusb_error_name(errCode));
        return -1;
    }

    fprintf(stderr, "deviceRead() Success reading %ld bytes\n", transferred);
    return transferred;
}

// Read the registers from the USB device
// Caution: this function is specific to my device!!!
// Returns negative number for errors
int deviceReadRegisters( ) {

    // Write the command to the device so that it will return the registers
    unsigned char wrBuf[2] = { 0x00, 0x10};
    int rtn = deviceWrite( wrBuf, sizeof(wrBuf));
    if (rtn < 0) return rtn;

    // Read back 146 bytes
    unsigned char rdBuf[146];
    rtn = deviceRead( rdBuf, sizeof( rdBuf));
    if (rtn < 0) return rtn;

    // Just in case we add more logic later...
    fprintf(stderr,"deviceReadRegisters() Success!\n");
    return rtn;
}

// Execute the full test including initialization and cleanup
// Return negative number for error
int runTest(  bool performLibUsbExit) {
    int rtn;

    fprintf(stderr,"runTest() Starting!\n");

    // Initialize library
    if (usbContext == NULL) {
        int r = libusb_init( &usbContext);
        if (r < 0) 
        {
            fprintf(stderr,"runTest() failed in libusb_init()\n");
            return -1;
        }
        fprintf(stderr,"runTest() Success calling libusb_init()\n");
    }

    // Make sure we have a device
    int count = deviceCount();
    if (count < 0) {
        fprintf(stderr,"runTest() Error in deviceCount()\n");
        return count;
    }
    if (count == 0) {
        fprintf(stderr,"runTest() No devices found!\n");
        return -1;
    }
    fprintf(stderr,"runTest() Number of devices: %d\n", count);

    // Open the device
    rtn = deviceOpen( 0);
    if (rtn < 0) return rtn;

    // Read the device registers a few times
    for (int i=0; i<5; i++) {
        rtn = deviceReadRegisters();
        if (rtn < 0) return rtn;
    }

    // Close the device
    rtn = deviceClose();
    if (rtn < 0) return rtn;

    // De-initialize the library
    if (performLibUsbExit == true) {
        libusb_exit(usbContext);
        usbContext = NULL;
        fprintf(stderr,"runTest() Success calling libusb_exit()\n");
    }

    fprintf(stderr,"runTest() Success!\n");
    return 0;
}

int main( int argc, char *argv[]) {

    int rtn;

    // Run the test a few times
    // The first test will pass. The second pass will timeout on the read.
    int maxNum = 5;
    for (int i=0; i<maxNum; i++) {
        fprintf(stderr, "main() attempting to runTest(), i: %d\n", i);

        // Only clean-up on the last call
        rtn = runTest( i+1 == maxNum ? true : false);

        if (rtn < 0) return rtn;
    }

    fprintf(stderr,"main() Success!\n");
    return 0;
}

0 个答案:

没有答案