4

更新:

我编写了一个异步 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. 释放:清理资源(下图未显示)

原始问题:

我有三个不同的版本。一个是完全同步的,一个是半异步的,最后一个是完全异步的。不同之处在于,同步完全填充了我正在控制的 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 个字节,和 Endpoint size 字节长度传输。看看它在 USB mon 上的样子?

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

我不确定 USB mon 能够显示什么,但根据 Endpoint size packet len 后的 USB 标准,应该有 0 len 数据包数据发送,表明传输结束。

于 2009-07-04T18:13:09.330 回答