summaryrefslogtreecommitdiff
path: root/pyhidapi/__init__.py
blob: 819d476e078a0e488f91fed1899f016c396ec64d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import ctypes, ctypes.util

path = ctypes.util.find_library('hidapi')

if not path:
	path = ctypes.util.find_library('hidapi-libusb')

if not path:
	path = ctypes.util.find_library('hidapi-hidraw')

if not path:
	raise ImportError('Cannot find hidapi library')

hidapi = ctypes.CDLL(path)

class c_hid_device_info(ctypes.Structure):
	def __iter__(self):
		p = self
		yield DeviceInfo(p)
		
		while p.next:
			p = p.next.contents
			yield DeviceInfo(p)

c_hid_device_info._fields_ = [
	('path', ctypes.c_char_p),
	('vendor_id', ctypes.c_ushort),
	('product_id', ctypes.c_ushort),
	('serial_number', ctypes.c_wchar_p),
	('release_number', ctypes.c_ushort),
	('manufacturer_string', ctypes.c_wchar_p),
	('product_string', ctypes.c_wchar_p),
	('usage_page', ctypes.c_ushort),
	('usage', ctypes.c_ushort),
	('interface_number', ctypes.c_int),
	('next', ctypes.POINTER(c_hid_device_info)),
]

hidapi.hid_open.argtypes = [ctypes.c_ushort, ctypes.c_ushort, ctypes.c_wchar_p]
hidapi.hid_open.restype = ctypes.c_void_p

hidapi.hid_open_path.argtypes = [ctypes.c_char_p]
hidapi.hid_open_path.restype = ctypes.c_void_p

hidapi.hid_close.argtypes = [ctypes.c_void_p]

hidapi.hid_read_timeout.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t, ctypes.c_int]
hidapi.hid_read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
hidapi.hid_write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
hidapi.hid_send_feature_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
hidapi.hid_get_feature_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]

hidapi.hid_enumerate.restype = ctypes.POINTER(c_hid_device_info)

def enumerate(vid = 0, pid = 0):
	info = hidapi.hid_enumerate(vid, pid)
	
	if not info:
		return []
	
	l = list(info.contents)
	
	hidapi.hid_free_enumeration(info)
	
	return l

class HIDError(Exception):
	pass

class DeviceInfo:
	def __init__(self, cstruct):
		self.path = cstruct.path
		self.vendor_id = cstruct.vendor_id
		self.product_id = cstruct.product_id
		self.serial_number = cstruct.serial_number
		self.release_number = cstruct.release_number
		self.manufacturer_string = cstruct.manufacturer_string
		self.product_string = cstruct.product_string
		self.usage_page = cstruct.usage_page
		self.usage = cstruct.usage
		self.interface_number = cstruct.interface_number
	
	def open(self):
		return Device(path = self.path)

class Device:
	def __init__(self, vid = None, pid = None, serial = None, path = None):
		if path is not None:
			self._dev = hidapi.hid_open_path(path)
		
		elif vid is not None and pid is not None:
			self._dev = hidapi.hid_open(vid, pid, serial)
		
		else:
			raise TypeError('vid/pid or path is required')
		
		if not self._dev:
			raise HIDError('failed to open device')
	
	def __del__(self):
		self.close()
	
	def close(self):
		if self._dev:
			hidapi.hid_close(self._dev)
			self._dev = None
	
	def set_output_report(self, data, id = 0):
		if hidapi.hid_write(self._dev, ctypes.c_char_p(chr(id) + data), len(data) + 1) != len(data) + 1:
			raise HIDError('failed to set output')
	
	def get_input_report(self, timeout = -1):
		buf = ctypes.create_string_buffer(64)
		
		ret = hidapi.hid_read_timeout(self._dev, buf, 64, timeout)
		
		if ret < 0:
			raise HIDError('failed to get input')
		
		return buf[:ret]
	
	def set_feature_report(self, data, id = 0):
		if hidapi.hid_send_feature_report(self._dev, ctypes.c_char_p(chr(id) + data), len(data) + 1) != len(data) + 1:
			raise HIDError('failed to set feature')
	
	def get_feature_report(self, id = 0):
		buf = ctypes.create_string_buffer(chr(id), 64)
		
		ret = hidapi.hid_get_feature_report(self._dev, buf, 64)
		
		if ret < 0:
			raise HIDError('failed to get feature')
		
		return buf[1:ret]