4

更新:

非同期Cバージョンを作成しましたが、正常に動作します。

速度の問題はPythonのGILが原因であることが判明しました。その動作を微調整する方法があります。sys.setcheckinterval(interval)

間隔をゼロ(デフォルトは100)に設定すると、低速の問題が修正されます。あとは、他の問題の原因を突き止めるだけです(すべてのピクセルが塗りつぶされているわけではありません)。これは意味がありません。usbmonは、すべての通信が行われていることを示します。libusbのデバッグメッセージングは​​、異常なことは何も示していません。usbmonの出力を取得して、同期と非同期を比較する必要があると思います。usbmonが示すデータは、一見正しいように見えます(最初のバイトは0x96または0x95である必要があります)。

以下の元の質問、S。Lottで述べたように、これはUSBLCDコントローラー用です。発信エンドポイントメソッドであるdrv_sendには3つの異なるバージョンがあります。以下に違いを説明しました。非同期USB操作の概要を説明すると役立つかもしれません。同期USB操作は同じように機能することに注意してください。同期的に実行されるだけです。

非同期I/Oは5ステップのプロセスと見なすことができます。

  1. 割り当て:libusb_transferを割り当てます(これはself.transferです)
  2. 充填:実行する転送に関する情報をlibusb_transferインスタンスに入力します(libusb_fill_bulk_transfer)
  3. 提出:libusbに転送の提出を依頼します(libusb_submit_transfer)
  4. 完了処理:libusb_transfer構造(libusb_handle_eventsおよびlibusb_handle_events_timeout)で転送結果を調べます
  5. 割り当て解除:リソースのクリーンアップ(以下には表示されていません)

元の質問:

私は3つの異なるバージョンを持っています。人は完全に同期し、人は半非同期であり、最後は完全に非同期です。違いは、同期により、制御しているLCDディスプレイに期待されるピクセルが完全に表示され、非常に高速であるということです。半非同期バージョンは、ディスプレイの一部にしか表示されませんが、それでも非常に高速です。非同期バージョンは非常に遅く、表示の一部しか表示されません。ピクセルが完全に入力されていない理由と、非同期バージョンが本当に遅い理由に困惑しています。手がかりはありますか?

完全同期バージョンは次のとおりです。

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

半非同期バージョンは次のとおりです。

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))

これが完全非同期バージョンです。device_pollはそれ自体がスレッド内にあります。

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))

そして、ここでキューが空になります。これは、gobjectタイムアウトのコールバックです。

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

これが転送のコールバックです。ロック状態をfalseに戻すだけで、操作が終了したことを示します。

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
4

1 に答える 1

1

私はあなたが正しいかどうかわかりません。LCD を備えたデバイスがあり、USB 要求を処理するためのファームウェアがいくつかあります。PC側では、libUsbをラップするPyUSBを使用しています。

速度の問題が発生している場合は、いくつかの提案があります。転送するデータを制限してみてください。生データ全体を転送しないでください。おそらく変更されたピクセルのみを転送してください。

次に、USB アナライザー ソフトウェアを使用して転送速度を測定しましたか。ハードウェア USB アナライザーを購入するお金がない場合は、ソフトウェア バージョンを試してみてください。私はそのようなアナライザーを使用したことはありませんが、それらによって提供されるデータはあまり信頼できないと思います.

第三に、デバイスが実際に何をしているかを確認してください。おそらくそれがデータ転送のボトルネックです。

今日はあなたの質問に正確に答える時間があまりないので、後でまたお話しします。

私はこのスレッドをしばらく見ていますが、この件については完全に沈黙しているので、時間を割いてより深く見てみました。今日はまだあまり時間がないかもしれません。残念ながら、私は Python の専門家ではありませんが、C、C++、Windows、そして何よりも USB についてある程度知っています。しかし、これは LCD デバイスの問題である可能性があると思います。何を使用していますか?転送が正常に機能し、データがデバイスによって受信された場合、それはデバイスの問題であることを示しています。

私はあなたのコードを少し見て、1 バイト、8 バイト、およびエンドポイント サイズのバイト長の転送のみを送信して、いくつかのテストを行うことができますか? USB mon でどのように見えるか見てみましょう。

エンドポイント サイズは、PICO LCD USB コントローラーが使用する Hardvare バッファーのサイズです。あなたの場合はわかりませんが、ENDpoint サイズのメッセージを送信すると、次のメッセージの長さは 0 バイトになるはずです。問題があるのか​​もしれません。テストに関しては、送信するようにプログラムしたデータを見たことがあると思います。次に、データが上書きされるか、十分な速さで受信されない可能性があります。上書きされたと言うのは、LCD がデータの終わりを認識できず、ある転送と別の転送が混在していることを意味します。

USB mon が何を表示できるかはわかりませんが、Endpoint size packet len の後の USB 標準によれば、転送の終了を示す 0 len パケット データが送信されるはずです。

于 2009-07-04T18:13:09.330 に答える