为什么我无法重复调用PyUSB函数dev.read()而不出现超时错误?
我有一个USB连接,连接着一台Macbook Air和一个微控制器传感器,这个传感器会不断地发送十六进制数据。我想用Python中的PyUSB来获取这些数据。我用PyUSB连接微控制器,代码是这样的:
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)
然后我尝试使用dev.read()方法从设备中读取数据到一个数组里,第一次这样做是成功的:
dev.read(0x1,100,100)
这次读取得到了一个长度为100的数组,但在我多次调用dev.read(0x1,100,100)之后(并且得到了几个不同的数组),我开始收到这个错误:
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
为什么会发生这种情况呢?我怀疑我对数据传输过程中缓冲区是如何存储数据的理解有问题,但我找不到一个清晰的解释来说明发生了什么。
5 个回答
你可以这样做。
while True:
try:
r = dev.read(eddr, 1024)
print(r)
except Exception as e:
continue
发送数据的设备可能在等待某种回复,它就在那里等着,这样会导致你其他的读取操作超时。如果可以的话,试着用一些工具监控它正常工作时的数据流量,然后确保你没有漏掉任何数据包。
在你完成读取后,记得使用 usb.util.dispose_resources(dev)
来释放资源。你可以在我的项目中看到一个例子:https://github.com/JosepEscobar/inverterApi/blob/main/app/data_source.py
如果你不确定的话,尽量不要固定接收到的数据包大小。如果可以的话,找一下你这个端点的最大数据包大小,然后把它作为你读取方法的第二个参数:
endpoint.wMaxPacketSize
通常,你可以通过在终端输入这个命令来查看描述符、端点和接口:
lsusb -d vendorId:productId -v
这样你就能直接得到最大数据包大小了。希望这能帮助你解决问题。
你收到的响应长度是多少呢?你现在设置的dev.read
是告诉PyUSB,期望的响应长度是100字节。如果在100毫秒内没有收到100字节的数据,就会抛出一个超时错误。如果你的设备返回的消息长度小于100字节,那么在100毫秒到达时,你会收到一个错误,尽管这个消息的长度是正确的。所以,你可以选择以下两种方法:
1) 去掉超时变量。在这种情况下,PyUSB会等待一个默认的时间,然后返回响应而不会报错。如果你需要比默认时间更快的超时,这样做就不管用了。
2) 更好的方法是,如果你知道你收到的响应长度(听起来你已经有一些数据了,所以这可能是情况),就用这个实际的长度来替代100字节。这样可以在没有错误的情况下获取数据,同时还可以设置超时变量。