updated features for two different types of sniffing. fixed and scrolling. This can...
[goodfet] / client / hidapi.py
1 from ctypes import *
2
3 # Python doesn't define any sort of ABI string, so we need to manually probe for it.
4 # If your OS/arch isn't supported yet, see lib/README for help.
5
6 import platform
7 import sys
8
9 def _get_shared_lib_name():
10     if sys.platform.startswith('linux'):
11         # This may fail for a x86_32 userland on a x86_64 kernel. platform.architecture can be used to work around it, if necessary
12         arch = platform.machine()
13         if arch == 'amd64':
14             # old 64-bit linux.
15             arch = 'x86_64'
16         if arch == 'x86_64' and platform.architecture()[0] == '32bit':
17             # Whee! 32-bit python on a 64-bit kernel. The horror!
18             arch = 'x86_32'
19         if arch[0] == 'i' and arch[2:] == '86':
20             arch = 'x86_32'
21         # Any other variations need to be dealt with here.
22
23         return "lib/hidapi-%(platform)s-%(arch)s.so" % {"platform": sys.platform, "arch": arch}
24     elif sys.platform == 'darwin':
25         # This is completely backwards... both 32 and 64 report an i386.
26         # However, it may not matter; darwin supports fat binaries.
27         # If necessary, here's what I've found (very incomplete):
28         #
29         # arch*  machine    desired build
30         # 64bit  i386       x86_64
31         return "lib/hidapi-darwin.dylib"
32     elif sys.platform == 'win32':
33         # not yet fully supported. For now, assuming 32-bit x86.
34         return "lib/hidapi-win32-x86_32.dll"
35     else:
36         print >>sys.stderr, "Your platform is not yet supported. Please let the devs know, or read lib/README for help fixing it."
37         raise Exception("Unsupported platform")
38
39 if __name__ == '__main__':
40     print "Would try to load %s" % _get_shared_lib_name()
41
42 _hidapi = CDLL(_get_shared_lib_name())
43
44 class _HidDeviceInfo(Structure):
45     pass
46
47 _HidDeviceInfo._fields_ = [
48     ("path", c_char_p),
49     ("vendor_id", c_ushort),
50     ("product_id", c_ushort),
51     ("serial_number", c_wchar_p),
52     ("release_number", c_ushort),
53     ("manufacturer_string", c_wchar_p),
54     ("product_string", c_wchar_p),
55     ("usage_page", c_ushort),
56     ("usage", c_ushort),
57     ("interface_number", c_int),
58     ("next", POINTER(_HidDeviceInfo))]
59
60 class HidDeviceInfo(object):
61     """User-facing version of the _HidDeviceInfo structure."""
62
63     def __init__(self, raw):
64         for attr in ("path", "vendor_id", "product_id", "serial_number", "release_number", "manufacturer_string", "product_string", "usage_page", "usage", "interface_number"):
65             setattr(self, attr, getattr(raw, attr))
66
67     def open(self):
68         return HidDevice(self.vendor_id, self.product_id, self.serial_number)
69
70 class _HidDevice_p(c_void_p):
71     pass
72
73 class HidDevice(object):
74     def __init__(self, vid, pid=None, serial=None):
75         if type(vid) is str:
76             assert pid is None and serial is None
77             self._device = _hidapi.hid_open_path(vid)
78         else:
79             self._device = _hidapi.hid_open(vid, pid, serial)
80         if not self._device:
81             raise IOError("Failed to open device")
82
83     def write(self, string):
84         return _hidapi.hid_write(self._device, create_string_buffer(string), len(string))
85     def read(self, length):
86         buf = create_string_buffer(length)
87         olen = _hidapi.hid_read(self._device, buf, length)
88         return buf.raw[:length]
89     def set_nonblocking(self, nonblocking = True):
90         _hidapi.hid_set_nonblocking(self._device, nonblocking)
91     def send_feature_report(self, report_id, data):
92         buf = create_string_buffer(chr(report_id) + data)
93
94         return _hidapi.hid_send_feature_report(self._device, buf, len(data) + 1)
95     def get_feature_report(self, report_id, length):
96         # length does not include report id
97         buf = create_string_buffer(length + 1)
98         buf[0] = report_id
99         olen = _hidapi.hid_get_feature_report(self._device, buf, length + 1)
100         # BUG(thequux): Possible off-by-one error
101         return buf.raw[1:olen]
102
103     def close(self):
104         _hidapi.hid_close(self._device)
105         self._device = None
106
107     def get_manufacturer_string(_device):
108         buf = create_unicode_buffer(257)
109         _hidapi.hid_get_manufacturer_string(self._device, buf, 257)
110         return buf.value
111
112     def get_product_string(_device):
113         buf = create_unicode_buffer(257)
114         _hidapi.hid_get_product_string(self._device, buf, 257)
115         return buf.value
116
117     def get_serial_number_string(_device):
118         buf = create_unicode_buffer(257)
119         _hidapi.hid_get_serial_number_string(self._device, buf, 257)
120         return buf.value
121
122     def get_indexed_string(_device, index):
123         buf = create_unicode_buffer(257)
124         _hidapi.hid_get_indexed_string(self._device, index, buf, 257)
125         return buf.value
126
127
128
129
130 class HidApiError(IOError):
131     pass
132
133 def _check_hid_error(result, func, args):
134     if result == -1:
135         print args, _hidapi.hid_error(args[0])
136         raise HidApiError(_hidapi.hid_error(args[0]))
137     return result
138
139 # signatures
140 _hidapi.hid_enumerate.argtypes = [c_ushort, c_ushort]
141 _hidapi.hid_enumerate.restype = POINTER(_HidDeviceInfo)
142
143 _hidapi.hid_free_enumeration.argtypes = [POINTER(_HidDeviceInfo)]
144
145 _hidapi.hid_open.argtypes = [c_ushort, c_ushort, c_wchar_p]
146 _hidapi.hid_open.restype = _HidDevice_p
147
148 _hidapi.hid_open_path.argtypes = [c_char_p]
149 _hidapi.hid_open_path.restype = _HidDevice_p
150
151 _hidapi.hid_write.argtypes = [_HidDevice_p, POINTER(c_char), c_size_t]
152 _hidapi.hid_write.restype = c_int
153 _hidapi.hid_write.errcheck = _check_hid_error
154
155 _hidapi.hid_read.argtypes = [_HidDevice_p, POINTER(c_char), c_size_t]
156 _hidapi.hid_read.restype = c_int
157 _hidapi.hid_read.errcheck = _check_hid_error
158
159 _hidapi.hid_set_nonblocking.argtypes = [_HidDevice_p, c_int]
160 _hidapi.hid_set_nonblocking.restype = c_int
161 _hidapi.hid_set_nonblocking.errcheck = _check_hid_error
162
163 _hidapi.hid_send_feature_report.argtypes = [_HidDevice_p, POINTER(c_char), c_size_t]
164 _hidapi.hid_send_feature_report.restype = c_int
165 _hidapi.hid_send_feature_report.errcheck = _check_hid_error
166
167 _hidapi.hid_get_feature_report.argtypes = [_HidDevice_p, POINTER(c_char), c_size_t]
168 _hidapi.hid_get_feature_report.restype = c_int
169 _hidapi.hid_get_feature_report.errcheck = _check_hid_error
170
171 _hidapi.hid_close.argtypes = [_HidDevice_p]
172
173 _hidapi.hid_get_manufacturer_string.argtypes = [_HidDevice_p, POINTER(c_wchar), c_size_t]
174 _hidapi.hid_get_manufacturer_string.restype = c_int
175 _hidapi.hid_get_manufacturer_string.errcheck = _check_hid_error
176
177 _hidapi.hid_get_product_string.argtypes = [_HidDevice_p, POINTER(c_wchar), c_size_t]
178 _hidapi.hid_get_product_string.restype = c_int
179 _hidapi.hid_get_product_string.errcheck = _check_hid_error
180
181 _hidapi.hid_get_serial_number_string.argtypes = [_HidDevice_p, POINTER(c_wchar), c_size_t]
182 _hidapi.hid_get_serial_number_string.restype = c_int
183 _hidapi.hid_get_serial_number_string.errcheck = _check_hid_error
184
185 _hidapi.hid_get_indexed_string.argtypes = [_HidDevice_p, c_int, POINTER(c_wchar), c_size_t]
186 _hidapi.hid_get_indexed_string.restype = c_int
187 _hidapi.hid_get_indexed_string.errcheck = _check_hid_error
188
189 _hidapi.hid_error.argtypes = [_HidDevice_p]
190 _hidapi.hid_error.restype = c_wchar_p
191
192 def hid_enumerate(vid=0, pid=0):
193     """Enumerate the HID devices.
194
195     If vid == pid == 0, will enumerate all hid devices. Otherwise, just the ones with the given vid/pid.
196
197     Returns:
198        List of HidDeviceInfo structures.
199     """
200
201     devs = _hidapi.hid_enumerate(vid,pid)
202
203     raw_list = devs
204     ret = []
205     while raw_list:
206         raw = raw_list.contents
207         raw_list = raw.next
208         ret.append(HidDeviceInfo(raw))
209
210     _hidapi.hid_free_enumeration(devs)
211     return ret
212
213 def hid_open(vid, pid, serial_number = None):
214     return HidDevice(vid, pid, serial_number)
215
216 def hid_open_path(path):
217     return HidDevice(path)
218
219 if __name__ == '__main__':
220     for dev in hid_enumerate():
221         print "%04x:%04x %30s <%s> <%s> %d" % (dev.vendor_id, dev.product_id, dev.serial_number, dev.manufacturer_string, dev.product_string, dev.interface_number)