3

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
  • 110
  • 1
  • 4
  • 9

5 Answers5

2

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.

eh_whatever
  • 193
  • 1
  • 3
  • 13
  • 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. – dimachidy Oct 23 '14 at 21:22
  • 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 Oct 24 '14 at 21:04
  • (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). – eh_whatever Oct 24 '14 at 21:08
1

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.

Saddam
  • 25
  • 8
0

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

Josep Escobar
  • 445
  • 4
  • 11
0

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.

Seth
  • 707
  • 1
  • 9
  • 20
0

You can do this.

while True:
try:
    r = dev.read(eddr, 1024)
    print(r)
except Exception as e:
    continue