Darn, I forgot a helpful subject line. Sorry about that. Fixed now...though
that probably means I broke the thread structure.

I was able to re-test on a laptop running an older version of Linux Mint
natively (no VM), and after a few compatibility tweaks, I got it to
communicate correctly AND there is no weird delay anymore! I believe the
issue may be specific to the VM, although I am really unsure why, and would
love any insight anyone might have. I also need to do some more testing on
a different machine with the latest Ubuntu, so that I can more confidently
point at the VM environment as the cause rather than something else.

In case anyone is interested, I've pushed the relevant code up to a Github
repo:

https://github.com/jrowberg/keyglove/blob/master/host/python/kglib.py#L335

If I learn anything more, I'll be sure to follow up.

--Jeff


On Sat, Dec 6, 2014 at 12:55 AM, Jeff Rowberg <j...@rowberg.net> wrote:

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
>
>
>
> ------------------------------------------------------------------------------
> Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
> from Actuate! Instantly Supercharge Your Business Reports and Dashboards
> with Interactivity, Sharing, Native Excel Exports, App Integration & more
> Get technology previously reserved for billion-dollar corporations, FREE
>
> http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
> _______________________________________________
> pyusb-users mailing list
> pyusb-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/pyusb-users
>
>
------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
_______________________________________________
pyusb-users mailing list
pyusb-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/pyusb-users

Reply via email to