python libusb1_Python libusb1中的ctypes

参考python libusb1

python 如何调用 c 语言的库?如果优雅的,规范的调用 c 语言的库?

看完 python libusb1 上面的问题,自然就有答案了.

Enum

libusb 里,定义了大量的 c 的枚举.

Enum 用来将 c 里的 cnum 转成 python 里的数据结构,并可以反查.

class Enum(object):

def __init__(self, member_dict, scope_dict=None):

if scope_dict is None:

# Affect caller's locals, not this module's. # pylint: disable=protected-access scope_dict = sys._getframe(1).f_locals

# pylint: enable=protected-access forward_dict = {}

reverse_dict = {}

next_value = 0

for name, value in list(member_dict.items()):

if value is None:

value = next_value

next_value += 1

forward_dict[name] = value

if value in reverse_dict:

raise ValueError('Multiple names for value %r: %r, %r' % (

value, reverse_dict[value], name

))

reverse_dict[value] = name

scope_dict[name] = value

self.forward_dict = forward_dict

self.reverse_dict = reverse_dict

def __call__(self, value):

return self.reverse_dict[value]

def get(self, value, default=None):

return self.reverse_dict.get(value, default)

测试如下:

from libusb1 import Enum as ReverseEnum

e = ReverseEnum({})

e = ReverseEnum({"111":1,"222":2,"333":3})

e.forward_dict['111']

>>1

e(2)

>>'222'

e.get(3)

>>'333

Structure

自然就是用 ctypes 里的 Structure 定义了,同时定义 1 个 pinter 类型:

class libusb_endpoint_descriptor(Structure):

_fields_ = [

('bLength', c_uint8),

('bDescriptorType', c_uint8),

('bEndpointAddress', c_uint8),

('bmAttributes', c_uint8),

('wMaxPacketSize', c_uint16),

('bInterval', c_uint8),

('bRefresh', c_uint8),

('bSynchAddress', c_uint8),

('extra', c_void_p),

('extra_length', c_int)]

libusb_endpoint_descriptor_p = POINTER(libusb_endpoint_descriptor)

也可以这样定义,可以使用前向声明(比如 c 里的链表 Head 结构):

_libusb_transfer_fields = [

('dev_handle', libusb_device_handle_p),

('flags', c_uint8),

('endpoint', c_uchar),

('type', c_uchar),

('timeout', c_uint),

('status', c_int), # enum libusb_transfer_status ('length', c_int),

('actual_length', c_int),

('callback', libusb_transfer_cb_fn_p),

('user_data', c_void_p),

('buffer', c_void_p),

('num_iso_packets', c_int),

('iso_packet_desc', libusb_iso_packet_descriptor)

]

class libusb_transfer(Structure):

pass

libusb_transfer_p = POINTER(libusb_transfer)

libusb_transfer._fields_ = _libusb_transfer_fields

python 还有能干这个活的内置 struct

struct 用来 pack/unpack binarydata,是 ctypes Structure 的底层实现.

ctypes 的 Structure 的优点,像 c 一样使用结构体,比较清晰.

ctypes 的 Structure 的缺点:uses the byte order that is native to C.当需要处理复杂的 bigendian littleendian 时,最好用 struct,而且效率也高些.

restype and argstype

给从 so 里 load 到的函数,定义返回值和参数:

libusb_get_device_list = libusb.libusb_get_device_list

libusb_get_device_list.argtypes = [libusb_context_p, libusb_device_p_p_p]

libusb_get_device_list.restype = c_ssize_t

回调的注册方法

c 里的回调,在 python 里处理,自然是用的 FUNCTYPE

#typedef int (*libusb_hotplug_callback_fn)(libusb_context *ctx,

# libusb_device *device, libusb_hotplug_event event, void *user_data);libusb_hotplug_callback_fn_p = CFUNCTYPE(

c_int, libusb_context_p, libusb_device_p, c_int, c_void_p)

#int libusb_hotplug_register_callback(libusb_context *ctx,

# libusb_hotplug_event events, libusb_hotplug_flag flags,

# int vendor_id, int product_id, int dev_class,

# libusb_hotplug_callback_fn cb_fn, void *user_data,

# libusb_hotplug_callback_handle *handle);try:

libusb_hotplug_register_callback = libusb.libusb_hotplug_register_callback

except AttributeError:

pass

else:

libusb_hotplug_register_callback.argtypes = [

libusb_context_p,

c_int, c_int,

c_int, c_int, c_int,

libusb_hotplug_callback_fn_p, c_void_p,

POINTER(libusb_hotplug_callback_handle),

]

libusb_hotplug_register_callback.restype = c_int

稍微特殊的函数

其实也就是用到了 cast.

def libusb_fill_control_setup(

setup_p, bmRequestType, bRequest, wValue, wIndex, wLength):

# 一般情况下,setup_p应该就是libusb_control_setup_p, # 但是也许有pointer(create_string_buffer())创建的Array pointer,也是可以强制转换的 setup = cast(setup_p, libusb_control_setup_p).contents

setup.bmRequestType = bmRequestType

setup.bRequest = bRequest

setup.wValue = libusb_cpu_to_le16(wValue)

setup.wIndex = libusb_cpu_to_le16(wIndex)

setup.wLength = libusb_cpu_to_le16(wLength)

上面的几个用法搞明白,python 调用 c 不再有什么问题了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值