USB - 同步与异步对半同步

时间:2009-06-29 20:22:42

标签: python usb ctypes libusb

更新

我编写了一个异步C版本,它可以正常工作。

原来速度问题是由于Python的GIL造成的。有一种方法可以微调其行为。 sys.setcheckinterval(间隔)

将间隔设置为零(默认值为100)可修复慢速问题。现在剩下的就是找出造成另一个问题的原因(并非所有像素都被填充)。这个没有任何意义。 usbmon显示所有通信正在进行中。 libusb的调试消息传递没有任何异常。我想我需要拿usbmon的输出并比较同步和异步。 usbmon显示的数据看起来一目了然(第一个字节应该是0x96或0x95)。

如下面原始问题中所述,S。Lott,它是用于USB LCD控制器。 drv_send有三种不同版本,即传出端点方法。我已经解释了下面的差异。如果我概述异步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. 解除分配:清理资源(下面未显示)
  6. 原始问题:

    我有三个不同的版本。一个是完全同步的,一个是半异步的,最后一个是完全异步的。不同之处在于同步完全填充了我正在控制的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
    

1 个答案:

答案 0 :(得分:1)

好的,我不知道我是否帮助你。你有一些带LCD的设备,你有一些固件来处理USB请求。在PC端你正在使用PyUSB包装libUsb。

如果您正在尝试速度问题,请尝试限制您正在转移的数据。不要传输整个原始数据,只能传输更改的像素。

其次,你是否通过使用一些USB分析软件来测量传输速度,如果你没有钱用于hardvare usb分析器可能会尝试软件版本。我从未使用过那种分析仪,但我认为它们提供的数据并不是很可靠。

第三,看看设备正在做什么,也许这是数据传输的瓶颈。

今天我没有太多时间来回答你的问题,所以我稍后会再回过头来。

我正在观看这个帖子已经有一段时间了,并且周围已经有了沉默,所以我试着节省一些时间并且看得更深。今天也许今天晚些时候还没多久。不幸的是,我不是python专家,但我知道一些关于C,C ++,Windows和大多数USB的东西。但我认为这可能是LCD设备问题,您使用的是什么,因为如果传输工作正常,并且数据被设备接收,则指出这是设备问题。

我稍微看了一下你的代码,你能做一些测试,只发送1个字节,8个字节和端点大小的字节长度传输。看看它在USB mon上的外观如何?

端点大小是PICO LCD USB控制器使用的Hardvare缓冲区的大小。我不确定它对你来说是什么,但我猜测当你发送ENdpoint大小消息时,下一次masage应该是0字节长度。也许有问题。 关于测试,我假设您已经看过编程发送的数据。 第二件事可能是数据被覆盖,或者没有足够快地恢复。说覆盖我的意思是LCD无法看到数据结束,并将一次传输与另一次传输混合。

我不确定USB mon能够显示什么,但根据USB标准在端点大小包len之后,应该有0个len数据包发送,表明这是传输结束。