Why can't I call the PyUSB function dev.read() repeatedly without getting a timeout error?

10,628

What is the length of the response you get back? The way you are structuring dev.read you are telling PyUSB that the response should be 100 bytes long and if you don't get 100 bytes in 100 ms, throw a timeout exception. If your device responds with a smaller message, you will get an error after 100ms is reached, even if that message length is correct. So, you can do 1 of 2 things:

1) remove the timeout variable. In this case PyUSB will wait a default amount of time and the report response without an error. If you need to timeout quicker than the default, this won't help

2)Better yet, if you know the length of the responses you are getting in (sounds like you got some data, so this may be the case), use this value instead of the 100 bytes. This will give you the data back without an error and still allow you to set the timeout variable.

Share:
10,628
dimachidy
Author by

dimachidy

Updated on June 04, 2022

Comments

  • dimachidy
    dimachidy almost 2 years

    I have a USB connection between a Macbook Air and a microcontroller sensor that streams hex data continuously. I'm trying to use PyUSB in Python to acquire the data. I used PyUSB to connect to microcontroller like so:

    import usb 
    dev = usb.core.find(idVendor=0xXXXX, idProduct=0xXXXX)
    dev.set_configuration()
    cfg = dev.get_active_configuration()
    intf = cfg[(0,0)]
    ep = usb.util.find_descriptor(intf,custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
    

    I then tried to read data from the device into an array using the dev.read() method, which worked the first time:

    dev.read(0x1,100,100)
    

    This produced an array of length 100, but after I called dev.read(0x1,100,100) several more times (and got several more arrays) I started getting this error:

    dev.read(0x1,100,100)
    
    Traceback (most recent call last):
    
    File "stdin", line 1, in <module>
    
    File "/Users/dimachy/anaconda/lib/python2.7/site-packages/usb/core.py", line 918, in read
    self.__get_timeout(timeout))
    
    File "/Users/dimachy/anaconda/lib/python2.7/site-packages/usb/backend/libusb1.py", line 777, in bulk_read
    timeout)
    
    File "/Users/dimachy/anaconda/lib/python2.7/site-packages/usb/backend/libusb1.py", line 880, in __read
    _check(retval)
    
    File "/Users/dimachy/anaconda/lib/python2.7/site-packages/usb/backend/libusb1.py", line 560, in _check
    raise USBError(_str_error[ret], ret, _libusb_errno[ret])
    
    usb.core.USBError: [Errno 60] Operation timed out
    

    Why does this happen? I suspect I'm not understanding something about how buffers store data at various places during data transfer, but haven't been able to find a clear explanation of what's going on.

  • dimachidy
    dimachidy over 9 years
    Thank you for the tip - the data is supposed to be a continuous stream (it is a sensor and starts transmitting data as soon as it is turned on) at about 16 kilobytes/second, so 100 bytes should easily be delivered in 100 milliseconds. I tried again with very large timeout and go the same error after a few calls.
  • eh_whatever
    eh_whatever over 9 years
    Even if it is a 'continuous stream' of data USB transmits and receives in packets and you aren't receiving a pack of infinite length. You may be able to only send one request to start the data stream, but the data will come back in chunks of a predetermined length. I'm not sure what the exact application is, so say your micro is supposed to report temperatures for 3 sensors. It will read the temp of each at a given time, package them together into a packet it and send that data off over USB. Then once a set time interval is reached it will repeat the process.
  • eh_whatever
    eh_whatever over 9 years
    (con't) You are telling PyUSB that the packet it is expecting should be 100 bytes long and if it doesn't receive that within the timeout period throw an error. What you need to do is follow my instructions above to prevent a single read command from throwing an error then loop your read request until you are ready to stop reading (e.g. time interval, user presses a button, whatever).