From: Jeff R. <je...@ro...> - 2014-12-06 06:12:17
|
Hello PyUSB community! I'm trying to solve a raw HID write delay problem when using PyUSB 1.0.0b2 with Python 2.7 in an Ubuntu 14.10 Linux environment, actually running inside a VMware Player virtual machine on a Windows 8.1 64-bit desktop. I'm communicating from the Python script to a Teensy++ configured in Raw HID mode. I have been able to make this work perfectly in Windows using PyWinUSB, and using the Teensy++ manufacturer's own RawHID C demo code, and *almost* in Linux with PyUSB. In fact, I even get the data moving back and forth over the IN and OUT interrupt endpoints, intact and in order. The problem is that there is a very measurable delay (usually between 200ms and 500ms, varying) whenever I try to use the .write() method to send data to the device. I receive it instantly whenever anything new comes in; I've narrowed down the delay very specifically to the single line that attempts to send data: self.pyusb_endpoint_out.write(raw_packet) The "raw_packet" variable is an array of bytes. The data is delivered properly, and everything else works great on the device and in the response that comes back, so I know it's being interpreted correctly. It just takes way longer than it should. First, here's the string representation of the interface that I'm using: INTERFACE 0: Human Interface Device ==================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x0 bAlternateSetting : 0x0 bNumEndpoints : 0x2 bInterfaceClass : 0x3 Human Interface Device bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x2 Teensyduino RawHID ENDPOINT 0x83: Interrupt IN ========================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x83 IN bmAttributes : 0x3 Interrupt wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x1 ENDPOINT 0x4: Interrupt OUT ========================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x4 OUT bmAttributes : 0x3 Interrupt wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x1 I read data from 0x83 and send it out 0x4. Both are interrupt endpoints, so I would assume this should be pretty straightforward. The Python script is fairly complicated, so I won't post the whole thing here (though I will be happy to post it on Github if needed; that's where it will end up, but I was kinda hoping to actually make it work first). However, salient points about its functionality are these: 1. It's running in VM of Ubuntu 14.10, on a Win8 machine. I can try a non-VM Ubuntu environment, but it will take some time to arrange that. 2. The script starts a separate daemon thread which constantly tries to read from endpoint 0x83, timing out every second and retrying whenever there is no data available. This approach seems to work perfectly, but I'm wondering if it has some adverse effect on the ability to write data in a timely fashion. The thread runs in a single handler function that looks like this: # handler for reading incoming raw HID packets via PyUSB (thread started in local connect() method) def pyusb_read_handler(self): while self.pyusb_endpoint_in != None and self.connected: try: ret = self.devobj.read(self.pyusb_endpoint_in.bEndpointAddress, self.pyusb_endpoint_in.wMaxPacketSize) if len(ret) > 0 and ret[0] > 0: for b in ret[1:ret[0] + 1]: if self.kgapi.parse(b) == 0xC0: self.responses_pending = self.responses_pending - 1 if self.responses_pending == 0: self.on_api_idle() except usb.core.USBError as e: if e.errno == 110: # PyUSB timeout, probably just no data sys.exc_clear() elif e.errno == 5 or e.errno == 19: # "Input/Output Error" or "No such device", this is serious self.on_unplugged() self.disconnect() else: raise KeygloveHIDError("PyUSB read thread error: %s" % e) 3. The packets being sent are 64 bytes in size. The trailing bytes beyond the important part of the data payload are padded to zeros to fill the whole size. I had originally tried without doing this (by accident, in fact), so the byte array I wrote was only perhaps 5-10 bytes long, and then realized that I'd forgotten to pad it. However, the same delay exists whether or not the bytes are zero-padded out to the full report size, so that isn't it. Given the above, is there ANY reason why there would be a 100+ millisecond seemingly arbitrary delay sending a 64-byte packet? --Jeff |