Updates:USB - Synchronisierung vs async vs semi-async
Ich schrieb eine asynchrone C-Version und es funktioniert wie es sollte.
Es stellte sich heraus, dass das Geschwindigkeitsproblem auf Pythons GIL zurückzuführen war. Es gibt eine Methode, um das Verhalten zu optimieren. sys.setcheckinterval (Intervall)
Das Intervall auf Null setzen (Standard ist 100) behebt das Problem mit langsamer Geschwindigkeit. Jetzt ist nur noch herauszufinden, was das andere Problem verursacht (nicht alle Pixel sind gefüllt). Dieser macht keinen Sinn. usbmon zeigt an, dass alle Kommunikationen durchlaufen werden. libusbs Debug-Messaging zeigt nichts Außergewöhnliches. Ich denke, ich muss die Ausgabe von usbmon übernehmen und sync vs async vergleichen. Die Daten, die usbmon zeigt, scheinen auf einen Blick korrekt zu sein (das erste Byte sollte 0x96 oder 0x95 sein).
Wie unten in der ursprünglichen Frage gesagt, S. Lott, ist es für einen USB-LCD-Controller. Es gibt drei verschiedene Versionen von drv_send, die ausgehende Endpunktmethode ist. Ich habe die Unterschiede unten erklärt. Vielleicht hilft es, wenn ich die asynchronen USB-Operationen skizziere. Beachten Sie, dass synchrone USB-Operationen auf die gleiche Weise funktionieren, nur dass sie synchron ausgeführt werden.
Wir können asynchrone I Ansicht/A als 5 Schritten:
- Allocation: eine libusb_transfer zuteilen (Dies ist self.transfer)
- Füllung: bevölkern die libusb_transfer Instanz mit Informationen über die Übertragung Sie wünschen (libusb_fill_bulk_transfer)
- Submission auszuführen: fragen libusb die Übertragung (libusb_submit_transfer)
- Completion Handhabung einreichen: Transfer Ergebnisse in der libusb_transfer Struktur untersuchen (libusb_handle_events und libusb_handle_events_ Timeout)
- Ausplanung: aufzuräumen Ressourcen (nicht unten)
Original Frage:
Ich habe drei verschiedene Versionen. Einer ist völlig synchron, einer ist semi-asynchron und der letzte ist vollständig asynchron. Die Unterschiede bestehen darin, dass synchron das LCD-Display, das ich kontrolliere, vollständig mit den erwarteten Pixeln bestückt ist, , und es ist wirklich schnell. Die semi-asynchrone Version füllt nur einen Teil des Displays, , aber es ist immer noch sehr schnell. Die asynchrone Version ist wirklich langsam und füllt nur einen Teil des Displays. Ich bin verwirrt, warum die Pixel nicht vollständig bestückt sind, und warum die asynchrone Version wirklich langsam ist. Irgendwelche Hinweise?
Hier ist die vollsynchrone 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
Hier ist die semi-asynchrone 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))
Hier ist die voll asynchrone Version. device_poll ist in einem Thread für sich.
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))
Und hier ist, wo die Warteschlange geleert wird. Es ist der Rückruf für ein Gobject-Timeout.
def command_worker(self):
if self.drv_locked: # or time.time() - self.command_time < self.command_rate:
return True
try:
tmp = self.command_queue.get_nowait()
except Queue.Empty:
return True
tmp.func(*tmp.args)
self.command_time = time.time()
return True
Hier ist der Rückruf des Transfers. Es ändert nur den gesperrten Zustand zurück auf "falsch" und zeigt an, dass die Operation abgeschlossen ist.
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
Nun, ich benutze Pyusb nicht. Ich verpacke libusb-1.0 über Python ctypes, da pyusb auf libusb-0.1 basiert, welches nur synchrone Transfers unterstützt. Zweitens habe ich das Geschwindigkeitsproblem behoben, obwohl ich mich zu fragen begann, ob dieses andere Problem auch nicht geschwindigkeitsbezogen ist. Drittens verwende ich usbmon, um die Übertragungen zu analysieren. Ich bin mir nicht sicher, wie ich die Geschwindigkeit analysieren soll. Wie auch immer, toll zu wissen, dass jemand endlich versucht hat, das zu beantworten. :) – Scott
Nun, ich schrieb eine asynchrone C-Version, wie von einem libusb-dev vorgeschlagen. Nach einigem Haarziehen habe ich es gut gemacht. Es ist ein wirklich seltsames Thema. usbmon zeigt, dass die Transfers durchkommen. Der Rückruf wird angerufen. Ich bin mir nicht sicher, was ich sonst noch tun kann. – Scott
Ich bin mir nicht sicher, was Sie unter "Endpunktgröße" verstehen. Ich habe 1 und 8 Byte, und sie sind beide richtig. Beide starteten mit 0x96, dem 8-Byte-Transfer gefolgt von 7 Nullen. – Scott