small updates to hidapi, mostly cosmetic
This commit is contained in:
parent
418044ec1a
commit
6c68f47597
|
@ -15,54 +15,55 @@ USB driver from the kernel, and it may cause the device to become unresponsive.
|
||||||
__version__ = '0.2-hidapi-0.7.0'
|
__version__ = '0.2-hidapi-0.7.0'
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
import ctypes as _C
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
from ctypes import (cdll, create_string_buffer, create_unicode_buffer,
|
|
||||||
c_int, c_ushort, c_size_t,
|
|
||||||
c_char_p, c_wchar_p, c_void_p,
|
|
||||||
POINTER, Structure)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# look for a native implementation in the same directory as this file
|
# look for a native implementation in the same directory as this file
|
||||||
#
|
#
|
||||||
|
|
||||||
_api = None
|
"""The CDLL native library object."""
|
||||||
native_path = os.path.dirname(__file__)
|
_native = None
|
||||||
|
|
||||||
for native_implementation in ('hidraw', 'libusb'):
|
for native_implementation in ('hidraw', 'libusb'):
|
||||||
try:
|
try:
|
||||||
native_name = 'libhidapi-' + native_implementation + '.so'
|
# first look in the default library path
|
||||||
native_libfile = os.path.join(native_path, native_name)
|
native_implementation = 'libhidapi-' + native_implementation + '.so'
|
||||||
_api = cdll.LoadLibrary(native_libfile)
|
_native = _C.cdll.LoadLibrary(native_implementation)
|
||||||
break
|
break
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
del native_path, native_name, native_libfile, native_implementation
|
del native_implementation
|
||||||
if _api is None:
|
|
||||||
raise ImportError(__file__,
|
if _native is None:
|
||||||
'failed to load any HID API native implementation')
|
raise ImportError('hidapi: failed to load any HID API native implementation')
|
||||||
|
|
||||||
|
|
||||||
# internally used by native hidapi, no need to expose it
|
#
|
||||||
class _DeviceInfo(Structure):
|
# Structures used by this API.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# used by the native implementation when enumerating, no need to expose it
|
||||||
|
class _NativeDeviceInfo(_C.Structure):
|
||||||
pass
|
pass
|
||||||
_DeviceInfo._fields_ = [
|
_NativeDeviceInfo._fields_ = [
|
||||||
('path', c_char_p),
|
('path', _C.c_char_p),
|
||||||
('vendor_id', c_ushort),
|
('vendor_id', _C.c_ushort),
|
||||||
('product_id', c_ushort),
|
('product_id', _C.c_ushort),
|
||||||
('serial', c_wchar_p),
|
('serial', _C.c_wchar_p),
|
||||||
('release', c_ushort),
|
('release', _C.c_ushort),
|
||||||
('manufacturer', c_wchar_p),
|
('manufacturer', _C.c_wchar_p),
|
||||||
('product', c_wchar_p),
|
('product', _C.c_wchar_p),
|
||||||
('usage_page', c_ushort),
|
('usage_page', _C.c_ushort),
|
||||||
('usage', c_ushort),
|
('usage', _C.c_ushort),
|
||||||
('interface', c_int),
|
('interface', _C.c_int),
|
||||||
('next_device', POINTER(_DeviceInfo))
|
('next_device', _C.POINTER(_NativeDeviceInfo))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# the tuple object we'll expose when enumerating devices
|
# the tuple object we'll expose when enumerating devices
|
||||||
|
from collections import namedtuple
|
||||||
DeviceInfo = namedtuple('DeviceInfo', [
|
DeviceInfo = namedtuple('DeviceInfo', [
|
||||||
'path',
|
'path',
|
||||||
'vendor_id',
|
'vendor_id',
|
||||||
|
@ -72,78 +73,79 @@ DeviceInfo = namedtuple('DeviceInfo', [
|
||||||
'manufacturer',
|
'manufacturer',
|
||||||
'product',
|
'product',
|
||||||
'interface'])
|
'interface'])
|
||||||
|
del namedtuple
|
||||||
|
|
||||||
|
|
||||||
# create a DeviceInfo tuple from a hid_device object
|
# create a DeviceInfo tuple from a hid_device object
|
||||||
def _DevInfoTuple(hid_device):
|
def _makeDeviceInfo(native_device_info):
|
||||||
return DeviceInfo(
|
return DeviceInfo(
|
||||||
path=str(hid_device.path),
|
path=str(native_device_info.path),
|
||||||
vendor_id=hex(hid_device.vendor_id)[2:],
|
vendor_id=hex(native_device_info.vendor_id)[2:],
|
||||||
product_id=hex(hid_device.product_id)[2:],
|
product_id=hex(native_device_info.product_id)[2:],
|
||||||
serial=str(hid_device.serial) if hid_device.serial else None,
|
serial=str(native_device_info.serial) if native_device_info.serial else None,
|
||||||
release=hex(hid_device.release)[2:],
|
release=hex(native_device_info.release)[2:],
|
||||||
manufacturer=str(hid_device.manufacturer),
|
manufacturer=str(native_device_info.manufacturer),
|
||||||
product=str(hid_device.product),
|
product=str(native_device_info.product),
|
||||||
interface=hid_device.interface)
|
interface=native_device_info.interface)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# set-up arguments and return types for each hidapi function
|
# set-up arguments and return types for each hidapi function
|
||||||
#
|
#
|
||||||
|
|
||||||
_api.hid_init.argtypes = None
|
_native.hid_init.argtypes = None
|
||||||
_api.hid_init.restype = c_int
|
_native.hid_init.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_exit.argtypes = None
|
_native.hid_exit.argtypes = None
|
||||||
_api.hid_exit.restype = c_int
|
_native.hid_exit.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_enumerate.argtypes = [c_ushort, c_ushort]
|
_native.hid_enumerate.argtypes = [_C.c_ushort, _C.c_ushort]
|
||||||
_api.hid_enumerate.restype = POINTER(_DeviceInfo)
|
_native.hid_enumerate.restype = _C.POINTER(_NativeDeviceInfo)
|
||||||
|
|
||||||
_api.hid_free_enumeration.argtypes = [POINTER(_DeviceInfo)]
|
_native.hid_free_enumeration.argtypes = [_C.POINTER(_NativeDeviceInfo)]
|
||||||
_api.hid_free_enumeration.restype = None
|
_native.hid_free_enumeration.restype = None
|
||||||
|
|
||||||
_api.hid_open.argtypes = [c_ushort, c_ushort, c_wchar_p]
|
_native.hid_open.argtypes = [_C.c_ushort, _C.c_ushort, _C.c_wchar_p]
|
||||||
_api.hid_open.restype = c_void_p
|
_native.hid_open.restype = _C.c_void_p
|
||||||
|
|
||||||
_api.hid_open_path.argtypes = [c_char_p]
|
_native.hid_open_path.argtypes = [_C.c_char_p]
|
||||||
_api.hid_open_path.restype = c_void_p
|
_native.hid_open_path.restype = _C.c_void_p
|
||||||
|
|
||||||
_api.hid_close.argtypes = [c_void_p]
|
_native.hid_close.argtypes = [_C.c_void_p]
|
||||||
_api.hid_close.restype = None
|
_native.hid_close.restype = None
|
||||||
|
|
||||||
_api.hid_write.argtypes = [c_void_p, c_char_p, c_size_t]
|
_native.hid_write.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
|
||||||
_api.hid_write.restype = c_int
|
_native.hid_write.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_read.argtypes = [c_void_p, c_char_p, c_size_t]
|
_native.hid_read.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
|
||||||
_api.hid_read.restype = c_int
|
_native.hid_read.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_read_timeout.argtypes = [c_void_p, c_char_p, c_size_t, c_int]
|
_native.hid_read_timeout.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t, _C.c_int]
|
||||||
_api.hid_read_timeout.restype = c_int
|
_native.hid_read_timeout.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_set_nonblocking.argtypes = [c_void_p, c_int]
|
_native.hid_set_nonblocking.argtypes = [_C.c_void_p, _C.c_int]
|
||||||
_api.hid_set_nonblocking.restype = c_int
|
_native.hid_set_nonblocking.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_send_feature_report.argtypes = [c_void_p, c_char_p, c_size_t]
|
_native.hid_send_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
|
||||||
_api.hid_send_feature_report.restype = c_int
|
_native.hid_send_feature_report.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_get_feature_report.argtypes = [c_void_p, c_char_p, c_size_t]
|
_native.hid_get_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
|
||||||
_api.hid_get_feature_report.restype = c_int
|
_native.hid_get_feature_report.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_get_manufacturer_string.argtypes = [c_void_p, c_wchar_p, c_size_t]
|
_native.hid_get_manufacturer_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
|
||||||
_api.hid_get_manufacturer_string.restype = c_int
|
_native.hid_get_manufacturer_string.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_get_product_string.argtypes = [c_void_p, c_wchar_p, c_size_t]
|
_native.hid_get_product_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
|
||||||
_api.hid_get_product_string.restype = c_int
|
_native.hid_get_product_string.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_get_serial_number_string.argtypes = [c_void_p, c_wchar_p, c_size_t]
|
_native.hid_get_serial_number_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
|
||||||
_api.hid_get_serial_number_string.restype = c_int
|
_native.hid_get_serial_number_string.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_get_indexed_string.argtypes = [c_void_p, c_int, c_wchar_p, c_size_t]
|
_native.hid_get_indexed_string.argtypes = [_C.c_void_p, _C.c_int, _C.c_wchar_p, _C.c_size_t]
|
||||||
_api.hid_get_indexed_string.restype = c_int
|
_native.hid_get_indexed_string.restype = _C.c_int
|
||||||
|
|
||||||
_api.hid_error.argtypes = [c_void_p]
|
_native.hid_error.argtypes = [_C.c_void_p]
|
||||||
_api.hid_error.restype = c_wchar_p
|
_native.hid_error.restype = _C.c_wchar_p
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -163,7 +165,7 @@ def init():
|
||||||
|
|
||||||
:returns: ``True`` if successful.
|
:returns: ``True`` if successful.
|
||||||
"""
|
"""
|
||||||
return _api.hid_init() == 0
|
return _native.hid_init() == 0
|
||||||
|
|
||||||
|
|
||||||
def exit():
|
def exit():
|
||||||
|
@ -174,7 +176,7 @@ def exit():
|
||||||
|
|
||||||
:returns: ``True`` if successful.
|
:returns: ``True`` if successful.
|
||||||
"""
|
"""
|
||||||
return _api.hid_exit() == 0
|
return _native.hid_exit() == 0
|
||||||
|
|
||||||
|
|
||||||
def enumerate(vendor_id=None, product_id=None, interface_number=None):
|
def enumerate(vendor_id=None, product_id=None, interface_number=None):
|
||||||
|
@ -187,29 +189,27 @@ def enumerate(vendor_id=None, product_id=None, interface_number=None):
|
||||||
"""
|
"""
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
devices = _api.hid_enumerate(vendor_id, product_id)
|
devices = _native.hid_enumerate(vendor_id, product_id)
|
||||||
d = devices
|
d = devices
|
||||||
while d:
|
while d:
|
||||||
if interface_number is None or interface_number == d.contents.interface:
|
if interface_number is None or interface_number == d.contents.interface:
|
||||||
results.append(_DevInfoTuple(d.contents))
|
results.append(_makeDeviceInfo(d.contents))
|
||||||
d = d.contents.next_device
|
d = d.contents.next_device
|
||||||
|
|
||||||
if devices:
|
if devices:
|
||||||
_api.hid_free_enumeration(devices)
|
_native.hid_free_enumeration(devices)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def open(vendor_id, product_id, serial=None):
|
def open(vendor_id, product_id, serial=None):
|
||||||
"""Open a HID device using a Vendor ID, Product ID and optionally a serial
|
"""Open a HID device by its Vendor ID, Product ID and optional serial number.
|
||||||
number.
|
|
||||||
|
|
||||||
If no serial_number is provided, the first device with the specified ids
|
If no serial is provided, the first device with the specified IDs is opened.
|
||||||
is opened.
|
|
||||||
|
|
||||||
:returns: an opaque device handle, or ``None``.
|
:returns: an opaque device handle, or ``None``.
|
||||||
"""
|
"""
|
||||||
return _api.hid_open(vendor_id, product_id, serial) or None
|
return _native.hid_open(vendor_id, product_id, serial) or None
|
||||||
|
|
||||||
|
|
||||||
def open_path(device_path):
|
def open_path(device_path):
|
||||||
|
@ -220,7 +220,7 @@ def open_path(device_path):
|
||||||
|
|
||||||
:returns: an opaque device handle, or ``None``.
|
:returns: an opaque device handle, or ``None``.
|
||||||
"""
|
"""
|
||||||
return _api.hid_open_path(device_path) or None
|
return _native.hid_open_path(device_path) or None
|
||||||
|
|
||||||
|
|
||||||
def close(device_handle):
|
def close(device_handle):
|
||||||
|
@ -228,7 +228,7 @@ def close(device_handle):
|
||||||
|
|
||||||
:param device_handle: a device handle returned by open() or open_path().
|
:param device_handle: a device handle returned by open() or open_path().
|
||||||
"""
|
"""
|
||||||
_api.hid_close(device_handle)
|
_native.hid_close(device_handle)
|
||||||
|
|
||||||
|
|
||||||
def write(device_handle, data):
|
def write(device_handle, data):
|
||||||
|
@ -254,7 +254,7 @@ def write(device_handle, data):
|
||||||
|
|
||||||
:returns: ``True`` if the write was successful.
|
:returns: ``True`` if the write was successful.
|
||||||
"""
|
"""
|
||||||
bytes_written = _api.hid_write(device_handle, c_char_p(data), len(data))
|
bytes_written = _native.hid_write(device_handle, _C.c_char_p(data), len(data))
|
||||||
return bytes_written > -1
|
return bytes_written > -1
|
||||||
|
|
||||||
|
|
||||||
|
@ -273,8 +273,8 @@ def read(device_handle, bytes_count, timeout_ms=-1):
|
||||||
|
|
||||||
:returns: the bytes read, or ``None`` if a timeout was reached.
|
:returns: the bytes read, or ``None`` if a timeout was reached.
|
||||||
"""
|
"""
|
||||||
out_buffer = create_string_buffer('\x00' * (bytes_count + 1))
|
out_buffer = _C.create_string_buffer(b'\x00' * (bytes_count + 1))
|
||||||
bytes_read = _api.hid_read_timeout(device_handle, out_buffer, bytes_count, timeout_ms)
|
bytes_read = _native.hid_read_timeout(device_handle, out_buffer, bytes_count, timeout_ms)
|
||||||
if bytes_read > -1:
|
if bytes_read > -1:
|
||||||
return out_buffer[:bytes_read]
|
return out_buffer[:bytes_read]
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ def send_feature_report(device_handle, data, report_number=None):
|
||||||
"""
|
"""
|
||||||
if report_number is not None:
|
if report_number is not None:
|
||||||
data = chr(report_number) + data
|
data = chr(report_number) + data
|
||||||
bytes_written = _api.hid_send_feature_report(device_handle, c_char_p(data), len(data))
|
bytes_written = _native.hid_send_feature_report(device_handle, _C.c_char_p(data), len(data))
|
||||||
return bytes_written > -1
|
return bytes_written > -1
|
||||||
|
|
||||||
|
|
||||||
|
@ -316,17 +316,17 @@ def get_feature_report(device_handle, bytes_count, report_number=None):
|
||||||
|
|
||||||
:returns: the feature report data.
|
:returns: the feature report data.
|
||||||
"""
|
"""
|
||||||
out_buffer = create_string_buffer('\x00' * (bytes_count + 2))
|
out_buffer = _C.create_string_buffer('\x00' * (bytes_count + 2))
|
||||||
if report_number is not None:
|
if report_number is not None:
|
||||||
out_buffer[0] = chr(report_number)
|
out_buffer[0] = chr(report_number)
|
||||||
bytes_read = _api.hid_get_feature_report(device_handle, out_buffer, bytes_count)
|
bytes_read = _native.hid_get_feature_report(device_handle, out_buffer, bytes_count)
|
||||||
if bytes_read > -1:
|
if bytes_read > -1:
|
||||||
return out_buffer[:bytes_read]
|
return out_buffer[:bytes_read]
|
||||||
|
|
||||||
|
|
||||||
def _read_wchar(func, device_handle, index=None):
|
def _read_wchar(func, device_handle, index=None):
|
||||||
_BUFFER_SIZE = 64
|
_BUFFER_SIZE = 64
|
||||||
buf = create_unicode_buffer('\x00' * _BUFFER_SIZE)
|
buf = _C.create_unicode_buffer('\x00' * _BUFFER_SIZE)
|
||||||
if index is None:
|
if index is None:
|
||||||
ok = func(device_handle, buf, _BUFFER_SIZE)
|
ok = func(device_handle, buf, _BUFFER_SIZE)
|
||||||
else:
|
else:
|
||||||
|
@ -340,7 +340,7 @@ def get_manufacturer(device_handle):
|
||||||
|
|
||||||
:param device_handle: a device handle returned by open() or open_path().
|
:param device_handle: a device handle returned by open() or open_path().
|
||||||
"""
|
"""
|
||||||
return _read_wchar(_api.hid_get_manufacturer_string, device_handle)
|
return _read_wchar(_native.hid_get_manufacturer_string, device_handle)
|
||||||
|
|
||||||
|
|
||||||
def get_product(device_handle):
|
def get_product(device_handle):
|
||||||
|
@ -348,7 +348,7 @@ def get_product(device_handle):
|
||||||
|
|
||||||
:param device_handle: a device handle returned by open() or open_path().
|
:param device_handle: a device handle returned by open() or open_path().
|
||||||
"""
|
"""
|
||||||
return _read_wchar(_api.hid_get_product_string, device_handle)
|
return _read_wchar(_native.hid_get_product_string, device_handle)
|
||||||
|
|
||||||
|
|
||||||
def get_serial(device_handle):
|
def get_serial(device_handle):
|
||||||
|
@ -356,13 +356,28 @@ def get_serial(device_handle):
|
||||||
|
|
||||||
:param device_handle: a device handle returned by open() or open_path().
|
:param device_handle: a device handle returned by open() or open_path().
|
||||||
"""
|
"""
|
||||||
serial = _read_wchar(_api.hid_get_serial_number_string, device_handle)
|
serial = _read_wchar(_native.hid_get_serial_number_string, device_handle)
|
||||||
if serial is not None:
|
if serial is not None:
|
||||||
return ''.join(hex(ord(c)) for c in serial)
|
return ''.join(hex(ord(c)) for c in serial)
|
||||||
|
|
||||||
|
|
||||||
# def get_indexed_string(device_handle, index):
|
def get_indexed_string(device_handle, index):
|
||||||
# """
|
"""Get a string from a HID device, based on its string index.
|
||||||
# :param device_handle: a device handle returned by open() or open_path().
|
|
||||||
# """
|
Note: may not be implemented by the underlying native library.
|
||||||
# return _read_wchar(_api.hid_get_indexed_string, device_handle, index)
|
|
||||||
|
:param device_handle: a device handle returned by open() or open_path().
|
||||||
|
:param string_index: the index of the string to get.
|
||||||
|
"""
|
||||||
|
return _read_wchar(_native.hid_get_indexed_string, device_handle, index)
|
||||||
|
|
||||||
|
|
||||||
|
def last_error(device_handle):
|
||||||
|
"""Get a string describing the last error which occurred.
|
||||||
|
|
||||||
|
Note: currently not implemented by the underlying native library.
|
||||||
|
|
||||||
|
:param device_handle: a device handle returned by open() or open_path().
|
||||||
|
:returns: a string containing the last error which occurred, or None.
|
||||||
|
"""
|
||||||
|
return _native.hid_error(device_handle)
|
Loading…
Reference in New Issue