EspoTek / Labrador

EspoTek Labrador is a USB device that transforms your PC or smartphone into a fully-featured electronics lab. This repo holds all of the source code!
http://espotek.com
1.1k stars 116 forks source link

submiturb failed should be a hard(er) error #48

Closed mpictor closed 6 years ago

mpictor commented 6 years ago

using e957460134d984 which is tagged v1.0 and 1.1, on amd64 linux:

The software consistently failed to communicate with my labrador when it was plugged into one port, though in the UI the only indication of this that I noticed was that the scope graph didn't show anything and calibration would always fail.

stdout/stderr, however, did include this text:

...
newDig
libusb: error [submit_iso_transfer] submiturb failed error -1 errno=28
libusb_submit_transfer FAILED
ERROR LIBUSB_ERROR_IO
libusb: error [submit_iso_transfer] submiturb failed error -1 errno=28
libusb_submit_transfer FAILED
ERROR LIBUSB_ERROR_IO
libusb: error [submit_iso_transfer] submiturb failed error -1 errno=28
libusb_submit_transfer FAILED
ERROR LIBUSB_ERROR_IO
libusb: error [submit_iso_transfer] submiturb failed error -1 errno=28
libusb_submit_transfer FAILED
ERROR LIBUSB_ERROR_IO
Setup successful!
...

Once I read that the unit reserved all bandwidth, I switched to another port and it's working. However there should be a better indication that something's wrong.

One crude method of providing such an indication:

diff --git a/Desktop_Interface/unixusbdriver.cpp b/Desktop_Interface/unixusbdriver.cpp
index 2a00b474..e9d4ce54 100644
--- a/Desktop_Interface/unixusbdriver.cpp
+++ b/Desktop_Interface/unixusbdriver.cpp
@@ -18,6 +18,7 @@ unixUsbDriver::~unixUsbDriver(void){
     qDebug() << "\n\nunixUsbDriver destructor ran!";
     //unixDriverDeleteMutex.lock();
     if(connected){
+        qDebug() <<"terminate worker thread";
         workerThread->terminate();
         delete(isoHandler);
         delete(workerThread);
@@ -112,7 +113,7 @@ void unixUsbDriver::usbSendControl(uint8_t RequestType, uint8_t Request, uint16_
 }

 unsigned char unixUsbDriver::usbIsoInit(void){
-    int error;
+    int error, err_cnt = 0;

     for(int n=0;n<NUM_FUTURE_CTX;n++){
         for (unsigned char k=0;k<NUM_ISO_ENDPOINTS;k++){
@@ -128,6 +129,7 @@ unsigned char unixUsbDriver::usbIsoInit(void){
         for (unsigned char k=0;k<NUM_ISO_ENDPOINTS;k++){
             error = libusb_submit_transfer(isoCtx[k][n]);
             if(error){
+                err_cnt++;
                 qDebug() << "libusb_submit_transfer FAILED";
                 qDebug() << "ERROR" << libusb_error_name(error);
             } else {
@@ -146,6 +148,10 @@ unsigned char unixUsbDriver::usbIsoInit(void){
             }
         }
     }
+    if (err_cnt > 0) {
+        qDebug() << "encountered" << err_cnt << "errors, aborting.";
+        abort();
+    }

     isoTimer = new QTimer();
     isoTimer->setTimerType(Qt::PreciseTimer);

This also adds an unrelated debug statement, as I was seeing crashes on re-init. The QT docs make it sound like a very bad idea to ever use QTThread::terminate().

mpictor commented 6 years ago

Note that the failure I'm seeing even happens if the labrador is the only thing on the hub.

lsusb output:

Bus 001 Device 021: ID 03eb:ba94 Atmel Corp. 
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

lsusb -t

/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/5p, 480M
    |__ Port 2: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 3: Dev 21, If 0, Class=Vendor Specific Class, Driver=, 12M

This hub is built into a Dell monitor (ought to be decent quality) and I've never had trouble with it in the past.

EspoTek commented 6 years ago

Hi Mark. I fixed the problem with the thread termination a few months back. See commit here: https://github.com/EspoTek/Labrador/commit/0d66cb870bef4a59adcf2fa2b571a6000d2f6f1c You were right about QThread::Terminate. I should not have used that method.

Regarding your idea to notify the user directly of submiturb issues, that's a fantastic idea and something I'll definitely implement over the coming week. I think it would be better to use a qMessageBox rather than qDebugs, though, as that way the users would notice the messages straight away.

As for why Labrador is not working on that one particular hub, I honestly can't explain it. Looking at your lsusb -t output, it should work perfectly in theory. Possibly a quirk with that particular hub; maybe 12Mbit/s isochronous devices are not supported on Linux?

mpictor commented 6 years ago

Ok, I'll switch to a version with thread termination fixed. I'd originally been using HEAD but thought I'd try a tagged version in the hopes my issue was not present.

A message box would certainly be a better idea, when I threw my solution together I wasn't trying for something polished :)


I've attached a zip with a pair of wireshark usb captures, one from a successful connection and one that failed. In both cases, I started the UI then plugged the board in. labrador-wireshark.zip

For these captures, I used HEAD (ca86c1da0a39c56) with my exit-on-urb-error patch, so in the failed session the app sends no more traffic after that initialization fails. There's also a patch for a missing function i2cDecoder::dataByteCompleted() - just to get it to compile - but that shouldn't affect the packet capture.

mpictor commented 6 years ago

Verbose lsusb output. Not sure whether the Resource temporarily unavailable lines are significant or not; re-running as root doesn't make them go away.

$ lsusb -v -s 1:

Bus 001 Device 031: ID 03eb:ba94 Atmel Corp. 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x03eb Atmel Corp.
  idProduct          0xba94 
  bcdDevice            2.00
  iManufacturer           1 EspoTek
  iProduct                2 Labrador
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           25
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      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            1
          Transfer Type            Isochronous
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x03ff  1x 1023 bytes
        bInterval               1
can't get device qualifier: Resource temporarily unavailable
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)

Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 
  bDeviceProtocol         2 TT per port
  bMaxPacketSize0        64
  idVendor           0x0424 Standard Microsystems Corp.
  idProduct          0x2514 USB 2.0 Hub
  bcdDevice            b.b3
  iManufacturer           0 
  iProduct                0 
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower                2mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 
      bInterfaceProtocol      1 Single TT
      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     0x0001  1x 1 bytes
        bInterval              12
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 
      bInterfaceProtocol      2 TT per port
      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     0x0001  1x 1 bytes
        bInterval              12
Hub Descriptor:
  bLength               9
  bDescriptorType      41
  nNbrPorts             4
  wHubCharacteristic 0x000d
    Per-port power switching
    Compound device
    Per-port overcurrent protection
    TT think time 8 FS bits
  bPwrOn2PwrGood       50 * 2 milli seconds
  bHubContrCurrent      1 milli Ampere
  DeviceRemovable    0x02
  PortPwrCtrlMask    0xff
 Hub Port Status:
   Port 1: 0000.0100 power
   Port 2: 0000.0100 power
   Port 3: 0000.0103 power enable connect
   Port 4: 0000.0100 power
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 
  bDeviceProtocol         0 Full speed (or root) hub
  bMaxPacketSize0        64
  bNumConfigurations      1
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0001
  Self Powered

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 
  bDeviceProtocol         0 Full speed (or root) hub
  bMaxPacketSize0        64
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0002 2.0 root hub
  bcdDevice            4.14
  iManufacturer           3 Linux 4.14.52-gentoo ehci_hcd
  iProduct                2 EHCI Host Controller
  iSerial                 1 0000:00:12.2
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           25
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 Full speed (or root) hub
      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     0x0004  1x 4 bytes
        bInterval              12
Hub Descriptor:
  bLength               9
  bDescriptorType      41
  nNbrPorts             5
  wHubCharacteristic 0x000a
    No power switching (usb 1.0)
    Per-port overcurrent protection
  bPwrOn2PwrGood       10 * 2 milli seconds
  bHubContrCurrent      0 milli Ampere
  DeviceRemovable    0x00
  PortPwrCtrlMask    0xff
 Hub Port Status:
   Port 1: 0000.0100 power
   Port 2: 0000.0503 highspeed power enable connect
   Port 3: 0000.0100 power
   Port 4: 0000.0100 power
   Port 5: 0000.0100 power
can't get device qualifier: Resource temporarily unavailable
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0001
  Self Powered
EspoTek commented 6 years ago

Looked at the Wireshark traces. It's definitely a bandwidth related issue. ENOSPC on (only) the Isochronous endpoint pretty much confirms this. As to why this is happening, I'm not sure. It's definitely transmitting upstream at at least 480MBps (note the timings; they're occuring at intervals <1ms) and if nothing else is connected then this should not cause any problems.
Unless, of course, there's some kind of bug in (the driver for) that particular USB hub? How good are you at kernel hacking? :)

mpictor commented 6 years ago

How good are you at kernel hacking?

I've ported an NDIS filter driver from windows to linux, so could be worse ;)

I think the problem would be finding time, and/or finding a machine I can reboot frequently enough; I like my desktop to stay up for long periods without reboot.

It looks to me like all usb hubs use the same driver, hub.c/hub.h, which is >5k lines. Fixing this is not important enough to make me commit to digging into the driver, when I can instead plug into a slightly less convenient port :)

EspoTek commented 6 years ago

Hahaha, my thoughts exactly. The rabbit hole is just too deep. I'll keep this issue open until I have a notification for submiturb failure.

EspoTek commented 6 years ago

This has been implemented in the latest patch.