2009-06-29 26 views
4

更新:USB - 同期vs非同期vsセミロシンク

私は非同期Cバージョンを書いていました。

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

間隔をゼロ(デフォルトは100)に設定すると、低速の問題が修正されます。今残っているのは、他の問題を引き起こしていることです(すべてのピクセルが満たされているわけではありません)。これは意味をなさない。 usbmonはすべての通信が通過していることを示します。 libusbのデバッグメッセージングでは、普通のことは何も表示されません。私はusbmonの出力を取って、同期と非同期を比較する必要があると思います。 usbmonが示すデータは一見して正しいように見えます(最初のバイトは0x96または0x95でなければなりません)。

元の質問では、Lott氏は以下のように、USB LCDコントローラ用です。 drv_sendの3つの異なるバージョンがあります。これは発信エンドポイント方式です。私は以下の違いを説明しました。おそらく、私が非同期USB操作の概要を説明すると助けになるでしょう。 syncrhonous USB操作は同じ方法で動作することに注意してください。それは同期しているということだけです。

私たちは、5段階のプロセスとして、非同期I/Oを表示することができます。

  1. 配分:転送あなたについての情報をlibusb_transferインスタンスを移入:libusb_transfer(これはself.transferある)
  2. フィリングを配分します転送を提出するのlibusbを頼む(libusb_submit_transfer)
  3. 完了取扱い:libusb_transfer構造に転送結果を調べ(libusb_handle_eventsとlibusb_handle_events_(libusb_fill_bulk_transfer)
  4. 提出を実行したいですタイムアウト)
  5. 割り当て解除:私は、3つの異なるバージョンを持っている

    :リソース(以下に示されていない)

元の質問をクリーンアップします。 1つは完全に同期、1つは半非同期、最後は完全非同期です。相違点は、同期が完全に表示されているLCDディスプレイのピクセル数がで、実際にはです。半非同期バージョンは、ディスプレイの一部に表示されるのはですが、それでもまだ非常に高速ですです。非同期バージョンは実際には遅く、はディスプレイの一部分のみを満たします。ピクセルが完全に埋め込まれていない理由、すなわちがなぜ非同期バージョンが本当に遅いのかわかりません。手がかりは?ここで

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

を完全に非同期バージョンです:ここでは半非同期バージョンです

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 

はここで完全に同期したバージョンです。 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)) 

ここでキューが空になっています。これは、オブジェクトのタイムアウトのコールバックです。

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 

答えて

1

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

スピードの問題を経験している場合は、転送するデータを制限してみてください。生データ全体を転送せず、変更されたピクセルのみを転送することができます。

第2に、USBアナライザソフトウェアを使用して転送の速度を測定しましたが、ハードウェアのUSBアナライザがソフトウェアバージョンを試してみる価値がない場合は、私はその種のアナライザを使ったことはありませんでしたが、私が提供したデータはあまり頼りにならないと思います。

第3に、本当にどのデバイスがデータ転送のボトルネックになっているのかを見てください。

私は今日、正確にあなたの質問に答えてくれる時間はあまりありませんので、後でこれを取り上げます。

私はしばらくこのスレッドを見ていて、これの周りに死んでいる沈黙があるので、私はいくつかの時間を余裕を持って深く見てみました。まだ今日はあまり時間がかかりません。 Unfortunetly私はPythonの専門家ではありませんが、私はC、C + +、WindowsとすべてのUSBのほとんどについてのいくつかのものを知っています。しかし、私はこれがLCDデバイスの問題かもしれないと思います、あなたは何を使っていますか?転送が正常に動作し、データがデバイスによって再現された場合、それはデバイスの問題を示します。

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

エンドポイントサイズは、PICO LCD USBコントローラーで使用されるHardvareバッファのサイズです。私はそれがあなたのためであるかどうかはわかりませんが、ENdpointサイズのメッセージを送信すると、次のマージは0バイトの長さでなければなりません。多分問題があるかもしれません。 テストに関しては、あなたが送信するようにプログラムされたデータを見たと思います。 第2の事柄は、データが上書きされるか、または十分に速く召喚されないことです。上書きすると、LCDはデータの終わりを見ることができず、ある転送を別のものとミックスします。

エンドポイントサイズのパケットlenの後にUSBスタンドアロンで表示されているUSB monがわかりません。転送が終了したことを示す0 lenのパケットデータが送信されます。

+0

まあ、私はpyusbを使用していません。 pyusbは同期転送のみをサポートするlibusb-0.1に基づいているため、libusb-1.0をPythonのctypesでラップしています。第二に、私は速度の問題を修正しましたが、この他の問題も速度に関連していないのかどうか疑問に思います。第三に、私は転送を分析するためにusbmonを使用しています。私はどのように速度を分析するか分からない。とにかく、誰かがついにこれに答えようとしていたことを知って嬉しい:) – Scott

+0

さて、私はlibusb開発者が提案した非同期Cバージョンを書いています。いくつかの髪を引っ張った後、私は正常に動作するようになった。それは本当に奇妙な問題です。 usbmonは転送が完了していることを示しています。コールバックが呼び出されています。私はこの時点で他に何ができるのか分かりません。 – Scott

+0

「エンドポイントサイズ」という意味がわかりません。私は1バイトと8バイトでしたが、どちらも正しいです。両方とも0x96で始まり、8バイトの転送に続いて7個のゼロが続きます。 – Scott

関連する問題