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

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.



Solution 1:[1]

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.

Solution 2:[2]

try not to fix the size of the received packets if you are not sure. If possible, look for the maximum packet size of your endpoint and use as a second argument for your read method:

endpoint.wMaxPacketSize

Generally, you can see or the decriptors, endpoints and interfaces by typing this command in the terminal:

lsusb -d vendorId:productId -v

This will provide you with the maximum packet size directly. Hope this will help you correct the error.

Solution 3:[3]

Use usb.util.dispose_resources(dev) when you finish read. You can see an example on my project: https://github.com/JosepEscobar/inverterApi/blob/main/app/data_source.py

Solution 4:[4]

The device sending data may be expecting some sort of reply, and it is sitting there waiting for it, causing your other reads to time out. If you can, sniff traffic of it operating correctly with something, and then make sure you haven't missed any packets.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 eh_whatever
Solution 2 Saddam
Solution 3 Josep Escobar
Solution 4 Seth