Ok, I'm probably doing something dumb, but I can't get libusb to let me transfer data to my device for the life of me.
Code:
#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <libusb-1.0/libusb.h>
#define EP_DATA_IN 0x83
#define EP_DATA_OUT 0x02
#define DEVICE_CONFIGURATION 0
int main(int argc, char **argv)
{
int rc;
libusb_context *ctx = NULL;
libusb_device_handle *dev_handle;
int actual = 0;
unsigned char *data = new unsigned char[4];
data[0]='a';data[1]='b';data[2]='c';data[3]='d';
rc = libusb_init(&ctx);
if(rc < 0) {
std::cout << "Init Error " << rc << std::endl;
return 1;
}
libusb_set_debug(ctx, 6);
dev_handle = libusb_open_device_with_vid_pid(ctx, 0x03eb, 0x2423);
if (!dev_handle) {
fprintf(stderr, "Error finding USB device\n");
return 2;
}
if(libusb_kernel_driver_active(dev_handle, DEVICE_CONFIGURATION) == 1) {
std::cout << "Kernel Driver Active" << std::endl;
if(libusb_detach_kernel_driver(dev_handle, DEVICE_CONFIGURATION) == 0)
std::cout << "Kernel Driver Detached!" << std::endl;
}
rc = libusb_claim_interface(dev_handle, DEVICE_CONFIGURATION);
if(rc != 0) {
std::cout << "Cannot Claim Interface" << std::endl;
return 3;
}
std::cout << "Data->" << data << "<-" << std::endl;
std::cout << "Writing Data..." << std::endl;
std::cout << "Trying endpoint " << EP_DATA_OUT << "." << std::endl;
rc = libusb_bulk_transfer(dev_handle, EP_DATA_OUT, data, sizeof(data), &actual, 100);
if(rc == 0 && actual == 4)
{
std::cout << "Writing Successful!" << std::endl;
}
else
{
std::cout << "Write Error! Rc: " << rc << " Actual transfered bytes: " << actual << "." << std::endl;
std::cout << "Error code means: " << libusb_error_name(rc) << std::endl;
}
rc = libusb_release_interface(dev_handle, 0);
if(rc!=0) {
std::cout << "Cannot Release Interface" << std::endl;
return 1;
}
if (dev_handle)
libusb_close(dev_handle);
libusb_exit(ctx);
return 0;
}
Device in question:
pi@testpi:~$ sudo lsusb -d 03eb: -v
Bus 001 Device 004: ID 03eb:2423 Atmel Corp.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x03eb Atmel Corp.
idProduct 0x2423
bcdDevice 1.00
iManufacturer 1 ATMEL ASF
iProduct 2 Vendor Class Example
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 69
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 1
bNumEndpoints 6
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x04 EP 4 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x85 EP 5 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0100 1x 256 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x06 EP 6 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0100 1x 256 bytes
bInterval 1
Device Status: 0x0001
Self Powered
And what I get when I run the code against the device:
pi@testpi:~/BatLogger/Interface/libusb_test$ ./make.sh
libusb: debug [libusb_get_device_list]
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_open] open 1.4
libusb: debug [usbi_add_pollfd] add fd 11 events 4
libusb: debug [libusb_kernel_driver_active] interface 0
libusb: debug [libusb_claim_interface] interface 0
Data->abcd<-
Writing Data...
Trying endpoint 2.
libusb: debug [add_to_flying_list] arm timerfd for timeout in 100ms (first in line)
libusb: debug [submit_bulk_transfer] need 1 urbs for new transfer with length 4
libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2
libusb: debug [submit_bulk_transfer] first URB failed, easy peasy
libusb: debug [disarm_timerfd]
Write Error! Rc: -1 Actual transfered bytes: 0.
Error code means: LIBUSB_ERROR_IO
libusb: debug [libusb_release_interface] interface 0
libusb: debug [libusb_close]
libusb: debug [usbi_remove_pollfd] remove fd 11
libusb: debug [libusb_exit]
libusb: debug [libusb_exit] destroying default context
As far as I know, I'm doing everything correctly. libusb_claim_interface
returns OK, there isn't a pre-existing driver attached to the device since I'm using a custom VID/PID combo, and EP_DATA_OUT
is a output endpoint (direction bit is 0, though to whom "out" is with respect to isn't described). Out of irritation, I've also tried every other possible endpoint (0-16, 0-16 | 1 << 7), with the exact same error for all of them.
Is there something silly I'm missing? Do I have to install a kernel module or something to make libusb play nice with me? I'm using libusb-1.0.
The error from the libusb debug message is error -1 errno=2
. where errno=2
corresponds to ERNOENT, but the few things I could find about that together with libusb didn't have a decent conclusion about what's actually going on.
Code is built g++ -std=c++11 -Wall -lrt -lusb-1.0 main.cpp -o main.bin
, though the fact that I'm using C++ is probably not relevant to the issue, since I'm not using one of the C++ libusb wrappers.
Ok, so I figured out the issue.
Basically, apparently, for ~reasons~, the endpoints for my device are attached to configuration 0, alternate setting 1.
I'm not sure how, or if it's even possible to determine this from the output of lsusb
, but I had a bit of scripting that I had used for a different device written against PyUSB, so I had a poke around with that, and it told me:
1 pi@testpi:~/BatLogger/Interface/libusb_test$ sudo python3 test.py
INFO:Main.Gui:Device: DEVICE ID 03eb:2423 on Bus 001 Address 004 =================
bLength : 0x12 (18 bytes)
bDescriptorType : 0x1 Device
bcdUSB : 0x200 USB 2.0
bDeviceClass : 0x0 Specified at interface
bDeviceSubClass : 0x0
bDeviceProtocol : 0x0
bMaxPacketSize0 : 0x40 (64 bytes)
idVendor : 0x03eb
idProduct : 0x2423
bcdDevice : 0x100 Device 1.0
iManufacturer : 0x1 ATMEL ASF
iProduct : 0x2 Vendor Class Example
iSerialNumber : 0x0
bNumConfigurations : 0x1
CONFIGURATION 1: 100 mA ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x45 (69 bytes)
bNumInterfaces : 0x1
bConfigurationValue : 0x1
iConfiguration : 0x0
bmAttributes : 0xc0 Self Powered
bMaxPower : 0x32 (100 mA)
INTERFACE 0: Vendor Specific ===========================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x0
bAlternateSetting : 0x0
bNumEndpoints : 0x0
bInterfaceClass : 0xff Vendor Specific
bInterfaceSubClass : 0xff
bInterfaceProtocol : 0xff
iInterface : 0x0
INTERFACE 0, 1: Vendor Specific ========================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x0
bAlternateSetting : 0x1
bNumEndpoints : 0x6
bInterfaceClass : 0xff Vendor Specific
bInterfaceSubClass : 0xff
bInterfaceProtocol : 0xff
iInterface : 0x0
ENDPOINT 0x81: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x1
ENDPOINT 0x2: Interrupt OUT ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x2 OUT
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x1
ENDPOINT 0x83: Bulk IN ===============================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x83 IN
bmAttributes : 0x2 Bulk
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x0
ENDPOINT 0x4: Bulk OUT ===============================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x4 OUT
bmAttributes : 0x2 Bulk
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x0
ENDPOINT 0x85: Isochronous IN ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x85 IN
bmAttributes : 0x1 Isochronous
wMaxPacketSize : 0x100 (256 bytes)
bInterval : 0x1
ENDPOINT 0x6: Isochronous OUT ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x6 OUT
bmAttributes : 0x1 Isochronous
wMaxPacketSize : 0x100 (256 bytes)
bInterval : 0x1
The critical thing being that there are no endpoints under INTERFACE 0:
, but there are endpoints under INTERFACE 0, 1:
. This was enough to go on to figure out that there were more then one version of INTERFACE 0
, and with that, it was pretty easy to figure out I needed to call libusb_set_interface_alt_setting()
to select the right alternate configuration thingie.
Basically, I wound up adding
rc = libusb_set_interface_alt_setting(dev_handle, DEVICE_CONFIGURATION, 1);
if(rc != 0) {
std::cout << "Cannot configure alternate setting" << std::endl;
return 3;
}
after the libusb_claim_interface()
call in my C(++) code, and I can now write to the device.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With