有些帮助了解libusb-1.0和ctypes的异步USB操作

时间:2021-06-10 16:08:49

Alright. I figured it out. transfer.flags needed to be a byte instead of an int. Silly me. Now I'm getting an error code from ioctl, errno 16, which I think means the device is busy. What a workaholic. I've asked on the libusb mailing list.

好的。我想到了。 transfer.flags需要是一个字节而不是一个int。傻我。现在我从ioctl,errno 16得到一个错误代码,我认为这意味着设备正忙。真是个工作狂。我已经在libusb邮件列表上询问了。

Below is what I have so far. This isn't really that much code. Most of it is ctypes structures for libusb. Scroll down to the bottom to see the actual code where the error occurs.

以下是我到目前为止的情况。这真的不是那么多代码。其中大多数是libusb的ctypes结构。向下滚动到底部以查看发生错误的实际代码。

from ctypes import *

VENDOR_ID = 0x04d8
PRODUCT_ID = 0xc002
_USBLCD_MAX_DATA_LEN = 24
LIBUSB_ENDPOINT_IN = 0x80
LIBUSB_ENDPOINT_OUT = 0x00

class EnumerationType(type(c_uint)):  
    def __new__(metacls, name, bases, dict):  
        if not "_members_" in dict:  
            _members_ = {}  
            for key,value in dict.items():  
                if not key.startswith("_"):  
                    _members_[key] = value  
            dict["_members_"] = _members_  
        cls = type(c_uint).__new__(metacls, name, bases, dict)  
        for key,value in cls._members_.items():  
            globals()[key] = value  
        return cls  

    def __contains__(self, value):
        return value in self._members_.values()

    def __repr__(self):
        return "<Enumeration %s>" % self.__name__

class Enumeration(c_uint):
    __metaclass__ = EnumerationType
    _members_ = {}
    def __init__(self, value):
        for k,v in self._members_.items():
            if v == value:
                self.name = k
                break
        else:
            raise ValueError("No enumeration member with value %r" % value)
        c_uint.__init__(self, value)


    @classmethod
    def from_param(cls, param):
        if isinstance(param, Enumeration):
            if param.__class__ != cls:
                raise ValueError("Cannot mix enumeration members")
            else:
                return param
        else:
            return cls(param)

    def __repr__(self):
        return "<member %s=%d of %r>" % (self.name, self.value, self.__class__)


class LIBUSB_TRANSFER_STATUS(Enumeration):
    _members_ = {'LIBUSB_TRANSFER_COMPLETED':0,
            'LIBUSB_TRANSFER_ERROR':1,
            'LIBUSB_TRANSFER_TIMED_OUT':2,
            'LIBUSB_TRANSFER_CANCELLED':3,
            'LIBUSB_TRANSFER_STALL':4,
            'LIBUSB_TRANSFER_NO_DEVICE':5,
            'LIBUSB_TRANSFER_OVERFLOW':6}

class LIBUSB_TRANSFER_FLAGS(Enumeration):
    _members_ = {'LIBUSB_TRANSFER_SHORT_NOT_OK':1<<0,
            'LIBUSB_TRANSFER_FREE_BUFFER':1<<1,
            'LIBUSB_TRANSFER_FREE_TRANSFER':1<<2}

class LIBUSB_TRANSFER_TYPE(Enumeration):
    _members_ = {'LIBUSB_TRANSFER_TYPE_CONTROL':0,
            'LIBUSB_TRANSFER_TYPE_ISOCHRONOUS':1,
            'LIBUSB_TRANSFER_TYPE_BULK':2,
            'LIBUSB_TRANSFER_TYPE_INTERRUPT':3}

class LIBUSB_CONTEXT(Structure):
    pass

class LIBUSB_DEVICE(Structure):
    pass

class LIBUSB_DEVICE_HANDLE(Structure):
    pass

class LIBUSB_CONTROL_SETUP(Structure):
    _fields_ = [("bmRequestType", c_int),
            ("bRequest", c_int),
            ("wValue", c_int),
            ("wIndex", c_int),
            ("wLength", c_int)]

class LIBUSB_ISO_PACKET_DESCRIPTOR(Structure):
    _fields_ = [("length", c_int),
            ("actual_length", c_int),
            ("status", LIBUSB_TRANSFER_STATUS)]

class LIBUSB_TRANSFER(Structure):
    pass

LIBUSB_TRANSFER_CB_FN = CFUNCTYPE(c_void_p, POINTER(LIBUSB_TRANSFER))

LIBUSB_TRANSFER._fields_ = [("dev_handle", POINTER(LIBUSB_DEVICE_HANDLE)),
            ("flags", c_ubyte),
            ("endpoint", c_ubyte),
            ("type", c_ubyte),
            ("timeout", c_uint),
            ("status", LIBUSB_TRANSFER_STATUS),
            ("length", c_int),
            ("actual_length", c_int),
            ("callback", LIBUSB_TRANSFER_CB_FN),
            ("user_data", c_void_p),
            ("buffer", POINTER(c_ubyte)),
            ("num_iso_packets", c_int),
            ("iso_packet_desc", POINTER(LIBUSB_ISO_PACKET_DESCRIPTOR))]


class TIMEVAL(Structure):
    _fields_ = [('tv_sec', c_long), ('tv_usec', c_long)]

lib = cdll.LoadLibrary("libusb-1.0.so")
lib.libusb_open_device_with_vid_pid.restype = POINTER(LIBUSB_DEVICE_HANDLE)
lib.libusb_alloc_transfer.restype = POINTER(LIBUSB_TRANSFER)

def libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, buffer, length, callback, user_data, timeout):
    transfer[0].dev_handle = dev_handle
    transfer[0].endpoint = chr(endpoint)
    transfer[0].type = chr(LIBUSB_TRANSFER_TYPE_INTERRUPT)
    transfer[0].timeout = timeout
    transfer[0].buffer = buffer
    transfer[0].length = length
    transfer[0].user_data = user_data
    transfer[0].callback = LIBUSB_TRANSFER_CB_FN(callback)

def cb_transfer(transfer):
    print "Transfer status %d" % transfer.status

if __name__ == "__main__":
    context = POINTER(LIBUSB_CONTEXT)()
    lib.libusb_init(None)
    transfer = lib.libusb_alloc_transfer(0)
    handle = lib.libusb_open_device_with_vid_pid(None, VENDOR_ID, PRODUCT_ID)
    size = _USBLCD_MAX_DATA_LEN
    buffer = c_char_p(size)
    libusb_fill_interrupt_transfer(transfer, handle, LIBUSB_ENDPOINT_IN + 1, buffer, size, cb_transfer, None, 0)

    r = lib.libusb_submit_transfer(transfer) # This is returning -2, should be => 0.
    if r < 0:
        print "libusb_submit_transfer failed", r

    while r >= 0:
        print "Poll before"
        tv = TIMEVAL(1, 0)
        r = lib.libusb_handle_events_timeout(None, byref(tv))
        print "Poll after", r

3 个解决方案

#1


  • Have you checked to make sure the return values of libusb_alloc_transfer and libusb_open_device_with_vid_pid are valid?
  • 您是否检查过以确保libusb_alloc_transfer和libusb_open_device_with_vid_pid的返回值是否有效?

  • Have you tried annotating the library functions with the appropriate argtypes?
  • 您是否尝试使用适当的argtypes注释库函数?

  • You may run in to trouble with transfer[0].callback = LIBUSB_TRANSFER_CB_FN(callback)—you're not keeping any references to the CFunctionType object returned from LIBUSB_TRANSFER_CB_FN(), and so that object might be getting released and overwritten.
  • 您可能会遇到传输[0] .callback = LIBUSB_TRANSFER_CB_FN(回调)的问题 - 您没有保留对从LIBUSB_TRANSFER_CB_FN()返回的CFunctionType对象的任何引用,因此该对象可能会被释放并被覆盖。

The next step, I suppose, would be to install a version of libusb with debugging symbols, boot up GDB, set a breakpoint at libusb_submit_transfer(), make sure the passed-in libusb_transfer is sane, and see what's triggering the error to be returned.

我想,下一步是安装带有调试符号的libusb版本,启动GDB,在libusb_submit_transfer()上设置断点,确保传入的libusb_transfer是理智的,并查看触发错误的原因是什么。

#2


Running it as root once fixed the busy flag.

一旦修复了忙碌标志,就以root身份运行它。

#3


where is the initial declaration of transfer? I am not familiar with python, but is this ok to assign values to fields in your struct without defining what data type it should be?

最初的转让声明在哪里?我不熟悉python,但是可以为结构中的字段赋值而不定义它应该是什么数据类型吗?

#1


  • Have you checked to make sure the return values of libusb_alloc_transfer and libusb_open_device_with_vid_pid are valid?
  • 您是否检查过以确保libusb_alloc_transfer和libusb_open_device_with_vid_pid的返回值是否有效?

  • Have you tried annotating the library functions with the appropriate argtypes?
  • 您是否尝试使用适当的argtypes注释库函数?

  • You may run in to trouble with transfer[0].callback = LIBUSB_TRANSFER_CB_FN(callback)—you're not keeping any references to the CFunctionType object returned from LIBUSB_TRANSFER_CB_FN(), and so that object might be getting released and overwritten.
  • 您可能会遇到传输[0] .callback = LIBUSB_TRANSFER_CB_FN(回调)的问题 - 您没有保留对从LIBUSB_TRANSFER_CB_FN()返回的CFunctionType对象的任何引用,因此该对象可能会被释放并被覆盖。

The next step, I suppose, would be to install a version of libusb with debugging symbols, boot up GDB, set a breakpoint at libusb_submit_transfer(), make sure the passed-in libusb_transfer is sane, and see what's triggering the error to be returned.

我想,下一步是安装带有调试符号的libusb版本,启动GDB,在libusb_submit_transfer()上设置断点,确保传入的libusb_transfer是理智的,并查看触发错误的原因是什么。

#2


Running it as root once fixed the busy flag.

一旦修复了忙碌标志,就以root身份运行它。

#3


where is the initial declaration of transfer? I am not familiar with python, but is this ok to assign values to fields in your struct without defining what data type it should be?

最初的转让声明在哪里?我不熟悉python,但是可以为结构中的字段赋值而不定义它应该是什么数据类型吗?