2009-06-29 14 views
4

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:

  1. Allocation: eine libusb_transfer zuteilen (Dies ist self.transfer)
  2. Füllung: bevölkern die libusb_transfer Instanz mit Informationen über die Übertragung Sie wünschen (libusb_fill_bulk_transfer)
  3. Submission auszuführen: fragen libusb die Übertragung (libusb_submit_transfer)
  4. Completion Handhabung einreichen: Transfer Ergebnisse in der libusb_transfer Struktur untersuchen (libusb_handle_events und libusb_handle_events_ Timeout)
  5. 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 

Antwort

1

Ok Ich weiß nicht, ob ich dich richtig verstehe. Sie haben ein Gerät mit LCD, Sie haben einige Firmware für USB-Anfragen. Auf PC-Seite verwenden Sie PyUSB, das libUsb umschließt.

Einige Vorschläge, wenn Sie Geschwindigkeitsprobleme haben, versuchen Sie, Daten zu begrenzen, die Sie übertragen. Übertragen Sie nicht ganze Rohdaten, möglicherweise nur Pixel, die sich geändert haben.

Zweitens, haben Sie Geschwindigkeit der Übertragungen mit einigen USB-Analizer-Software gemessen, wenn Sie kein Geld für Hardvare-USB-Analysator haben vielleicht versuchen, Software-Version. Ich habe diese Art von Analysatoren nie benutzt, aber ich denke, die von ihnen gelieferten Daten sind nicht sehr brauchbar.

Drittens, sehen Sie, was Gerät wirklich tut, vielleicht ist das der Flaschenhals Ihrer Datenübertragungen.

Ich habe heute nicht viel Zeit, um Ihre Frage genau zu beantworten, also werde ich später darauf zurückkommen.

Ich beobachte diesen Thread für einige Zeit, und es gibt Totenstille um diese, so versuchte ich, etwas Zeit zu sparen und tiefer zu schauen. Noch nicht viel Zeit heute, vielleicht später am heutigen Tag. Leider bin ich kein Python-Experte, aber ich kenne einige Dinge über C, C++, Windows und vor allem USB. Aber ich denke, dass dies LCD-Gerät Problem sein kann, was Sie verwenden, weil, wenn die Übertragungen gut funktioniert, und Daten vom Gerät empfangen wurde, zeigt es, dass Geräteproblem ist.

Ich sah Ihren Code ein wenig, könnten Sie einige Tests tun, Senden nur 1 Byte, 8 Bytes und Endpunktgröße Byte-Länge zu übertragen. Und sehen Sie, wie es auf USB mon aussieht?

Die Endpunktgröße ist die Größe des vom PICO LCD USB-Controller verwendeten Hardvare-Puffers. Ich bin nicht sicher, was es für Ihr ist, aber ich rate, dass, wenn Sie ENdpoint size Nachricht senden, die nächste masage 0 Bytes Länge sein sollte. Vielleicht ist da das Problem. In Bezug auf den Test nehme ich an, dass Sie Daten gesehen haben, die Sie gesendet haben. Die zweite Sache könnte sein, dass die Daten überschrieben werden oder nicht schnell genug empfangen werden. Overwriting sagen, ich meine LCD konnte nicht sehen, Daten enden, und mischen Sie eine Übertragung mit einer anderen.

Ich bin mir nicht sicher, was USB-Mon ist in der Lage zu zeigen, aber nach USB-Standard nach Endpoint-Größe Paket len, sollte es 0 len Paketdaten senden, zeigt, dass das Ende der Übertragung ist.

+0

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

+0

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

+0

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

Verwandte Themen