USB - синхронизация против асинхронного или полусинхронного - PullRequest
4 голосов
/ 30 июня 2009

Обновление:

Я написал асинхронную версию C, и она работает как надо.

Оказывается, проблема скорости была из-за GIL Python. Есть способ точно настроить его поведение. sys.setcheckinterval (интервал)

Установка интервала на ноль (по умолчанию 100) устраняет проблему медленной скорости. Теперь осталось выяснить, что является причиной другой проблемы (не все пиксели заполнены). Этот не имеет никакого смысла. usbmon показывает, что все коммуникации проходят. Отладочные сообщения libusb не показывают ничего необычного. Я думаю, мне нужно взять вывод usbmon и сравнить синхронизацию с асинхронным. Данные, которые показывает usbmon, на первый взгляд выглядят корректно (первый байт должен быть 0x96 или 0x95).

Как сказано ниже в исходном вопросе С. Лотта, это для USB LCD контроллера. Существует три разных версии drv_send, который является методом исходящей конечной точки. Я объяснил различия ниже. Может быть, это поможет, если я обрисую асинхронные операции USB. Обратите внимание, что синхронные операции USB работают одинаково, просто синхронно.

Мы можем рассматривать асинхронный ввод-вывод как 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. Распределение ресурсов: очистить ресурсы (не показано ниже)

Оригинальный вопрос:

У меня есть три разные версии. Кто-то полностью синхронен, кто-то полуасинхронен, а последний полностью асинхронен. Разница в том, что синхронно полностью заполняет ЖК-дисплей, которым я управляю с ожидаемыми пикселями, , и это действительно быстро . Полусинхронная версия заполняет только часть экрана, , но все еще очень быстро . Асинхронная версия очень медленная, а заполняет только часть экрана. Я сбит с толку, почему пиксели заполнены не полностью, и почему асинхронная версия действительно медленная. Есть какие-нибудь подсказки?

Вот полностью синхронная версия:

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

И вот где очередь опустошается. Это обратный вызов для тайм-аута объекта.

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

Вот обратный вызов перевода. Он просто меняет заблокированное состояние обратно на ложное, указывая на то, что операция завершена.

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 Ответ

1 голос
/ 04 июля 2009

Хорошо, я не знаю, правильно ли я вас понял. У вас есть какое-то устройство с ЖК-дисплеем, у вас есть прошивка для обработки USB-запросов. На стороне ПК вы используете PyUSB, который упаковывает libUsb.

Пара предложений, если вы испытываете проблемы со скоростью, попробуйте ограничить объем передаваемых данных. Не передавайте целые необработанные данные, возможно, только пиксели, которые изменились.

Во-вторых, вы измерили скорость передачи с помощью некоторого программного обеспечения USB-анализатора, если у вас нет денег на hardvare usb-анализатор, возможно, попробуйте версию программного обеспечения. Я никогда не использовал такие анализаторы, но я думаю, что данные, предоставленные ими, не очень надежны.

В-третьих, посмотрите, что на самом деле делает устройство, возможно, это является узким местом ваших передач данных.

У меня не так много времени сегодня, чтобы ответить на ваш вопрос, поэтому я вернусь к этому позже.

Я смотрю эту ветку в течение некоторого времени, и вокруг этого царит мертвая тишина, поэтому я постарался сэкономить немного времени и посмотреть глубже. Все еще не так много времени сегодня, может быть позже сегодня. К сожалению, я не эксперт по Python, но я знаю кое-что о C, C ++, Windows и больше всего о USB. Но я думаю, что это может быть проблема устройства LCD, что вы используете, потому что, если передача работает нормально, и данные были получены устройством, это указывает на проблему устройства.

Я немного посмотрел на ваш код, не могли бы вы провести некоторое тестирование, отправив только 1 байт, 8 байт и передачу длины байта размера конечной точки. И посмотрите как это выглядит на USB mon?

Размер конечной точки - это размер буфера Hardvare, используемый USB-контроллером PICO LCD. Я не уверен, что это для вас, но я предполагаю, что при отправке сообщения размера ENdpoint следующий массаж должен быть длиной 0 байт. Может быть, есть проблема. Что касается теста, я предполагаю, что вы видели данные, которые вы запрограммировали отправить. Во-вторых, данные могут быть перезаписаны или получены недостаточно быстро. Говоря «перезаписано», я имею в виду, что ЖК-дисплей не может видеть конец данных и смешивать одну передачу с другой.

Я не уверен, что USB mon способен отображать, но в соответствии со стандартом USB после пакета len размера конечной точки должна быть отправлена ​​пакетная передача данных 0 len, показывающая, что это конец передачи.

...