我的linux应用程序可以使用libusb对设备执行许多IO操作。但是,如果我关闭然后重新打开对设备的访问权限,则所有读取操作都将超时。我假设我的密码不完整,但我找不到我的错误。
示例程序具有以下功能:
请注意,在运行程序并获得超时错误后,我需要重新启动设备以进行恢复。在没有电源循环的情况下重新运行我的测试程序是不够的。然后在第一次调用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;
}