Update:
I wrote an asynchronous version of C, and it works as it should.
Turns out the speed issue is related to the Python GIL. There is a way to fine-tune its behavior. sys.setcheckinterval (interval)
The tuning interval to zero (the default is 100) fixes the problem at a slow speed. Now all that remains is to find out what causes another problem (not all pixels are full). It makes no sense. usbmon shows that all communications go through. Debugging libusb messages doesn't show anything unusual. I think I need to take usbmon output and compare sync vs async. The data shown on the usbmon display seems correct at first glance (the first byte should be 0x96 or 0x95).
As stated below in the original question, S. Lott, this is for the USB LCD controller. There are three different versions of drv_send, which are the outgoing final methods. I explained the differences below. Perhaps this will help if I describe asynchronous USB operations. Please note that synchronous operations with USB work the same way, just so that this happens synchronously.
We can consider asynchronous I / O as a five-step process:
- Highlight: highlight libusb_transfer (this is self.transfer)
- Filling: fill in the libusb_transfer instance with the transfer information you want to complete (libusb_fill_bulk_transfer)
- View: ask libusb to transfer the transfer (libusb_submit_transfer)
- Termination Handling: Check the transfer results in the libusb_transfer structure (libusb_handle_events and libusb_handle_events_timeout)
- Exemption: resource cleanup (not shown below)
The original question:
I have three different versions. One is fully synchronous, one is semi-asynchronous and the last is completely asynchronous. The differences are that the synchronous one completely fills the liquid crystal display, which I control with the expected pixels, and it is very fast . The semi-asynchronous version fills only part of the display , but is still very fast . The asynchronous version is very slow and fills only part of the display. I am confused why the pixels are not full and why the asynchronous version is very slow. Any clues?
Here's a fully synchronous version:
def drv_send(self, data): if not self.Connected(): return self.drv_locked = True buffer = '' for c in data: buffer = buffer + chr(c) length = len(buffer) out_buffer = cast(buffer, POINTER(c_ubyte)) libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0) lib.libusb_submit_transfer(self.transfer) while self.drv_locked: r = lib.libusb_handle_events(None) if r < 0: if r == LIBUSB_ERROR_INTERRUPTED: continue lib.libusb_cancel_transfer(transfer) while self.drv_locked: if lib.libusb_handle_events(None) < 0: break self.count += 1
Here's the semi-asynchronous version:
def drv_send(self, data): if not self.Connected(): return def f(d): self.drv_locked = True buffer = '' for c in data: buffer = buffer + chr(c) length = len(buffer) out_buffer = cast(buffer, POINTER(c_ubyte)) libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0) lib.libusb_submit_transfer(self.transfer) while self.drv_locked: r = lib.libusb_handle_events(None) if r < 0: if r == LIBUSB_ERROR_INTERRUPTED: continue lib.libusb_cancel_transfer(transfer) while self.drv_locked: if lib.libusb_handle_events(None) < 0: break self.count += 1 self.command_queue.put(Command(f, data))
Here is a fully asynchronous version. device_poll is in the thread by itself.
def device_poll(self): while self.Connected(): tv = TIMEVAL(1, 0) r = lib.libusb_handle_events_timeout(None, byref(tv)) if r < 0: break def drv_send(self, data): if not self.Connected(): return def f(d): self.drv_locked = True buffer = '' for c in data: buffer = buffer + chr(c) length = len(buffer) out_buffer = cast(buffer, POINTER(c_ubyte)) libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0) lib.libusb_submit_transfer(self.transfer) self.count += 1 self.command_queue.put(Command(f, data))
And here, where the line is empty. This is a callback for gobject timeout.
def command_worker(self): if self.drv_locked:
Here's the transfer callback. It simply changes the lock state to false, indicating that the operation is complete.
def cb_send_transfer(self, transfer): if transfer[0].status.value != LIBUSB_TRANSFER_COMPLETED: error("%s: transfer status %d" % (self.name, transfer.status)) print "cb_send_transfer", self.count self.drv_locked = False