Repository navigation
Expand file tree
/
Copy pathHID.py
More file actions
241 lines (192 loc) · 7.94 KB
/
Copy pathHID.py
File metadata and controls
241 lines (192 loc) · 7.94 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
import ctypes
import os
import sys
import BTCommands
# USB Parameters
VID = 0x10C4
PID = 0x8468
HID_READ_TIMEOUT = 0
HID_WRITE_TIMEOUT = 1000
# HID Report IDs
ID_IN_CONTROL = 0xFE
ID_OUT_CONTROL = 0xFD
ID_IN_DATA = 0x01
ID_OUT_DATA = 0x02
# HID Report Sizes
SIZE_IN_CONTROL = 5
SIZE_OUT_CONTROL = 5
SIZE_IN_DATA = 61
SIZE_OUT_DATA = 61
SIZE_MAX_WRITE = 59
SIZE_MAX_READ = 59
# Return Codes
HID_DEVICE_SUCCESS = 0x00
HID_DEVICE_NOT_FOUND = 0x01
HID_DEVICE_NOT_OPENED = 0x02
HID_DEVICE_ALREADY_OPENED = 0x03
HID_DEVICE_TRANSFER_TIMEOUT = 0x04
HID_DEVICE_TRANSFER_FAILED = 0x05
HID_DEVICE_CANNOT_GET_HID_INFO = 0x06
HID_DEVICE_HANDLE_ERROR = 0x07
HID_DEVICE_INVALID_BUFFER_SIZE = 0x08
HID_DEVICE_SYSTEM_CODE = 0x09
HID_DEVICE_UNSUPPORTED_FUNCTION = 0x0A
HID_DEVICE_UNKNOWN_ERROR = 0xFF
# String Types
HID_VID_STRING = 0x01
HID_PID_STRING = 0x02
HID_PATH_STRING = 0x03
HID_SERIAL_STRING = 0x04
HID_MANUFACTURER_STRING = 0x05
HID_PRODUCT_STRING = 0x06
MAX_PATH_LENGTH = 260
MAX_REPORT_REQUEST_XP = 512
if sys.platform == 'win32':
# Prebuilt Silicon Labs DLL; its exports are WINAPI (stdcall)
_dllPath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'USBDriver', 'SLABHIDDevice.dll')
try:
_mod = ctypes.WinDLL(_dllPath)
except OSError as e:
if ctypes.sizeof(ctypes.c_void_p) == 8:
raise OSError("Unable to load {}: the DLL is 32-bit, run with 32-bit Python".format(_dllPath)) from e
raise
else:
_mod = ctypes.cdll.LoadLibrary('libslabhiddevice.so')
HidDevice_GetNumHidDevices = _mod.HidDevice_GetNumHidDevices
HidDevice_GetNumHidDevices.argtypes = (ctypes.c_int, ctypes.c_int)
HidDevice_GetNumHidDevices.restype = ctypes.c_int
HidDevice_GetMaxReportRequest = _mod.HidDevice_GetMaxReportRequest
HidDevice_GetMaxReportRequest.argtypes = (ctypes.c_void_p,)
HidDevice_GetMaxReportRequest.restype = ctypes.c_int
HidDevice_GetHidString = _mod.HidDevice_GetHidString
HidDevice_GetHidString.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_byte, ctypes.c_char_p, ctypes.c_int)
HidDevice_GetHidString.restype = ctypes.c_byte
HidDevice_GetString = _mod.HidDevice_GetString
HidDevice_GetString.argtypes = (ctypes.c_void_p, ctypes.c_byte, ctypes.c_int)
HidDevice_GetString.restype = ctypes.c_byte
HidDevice_Open = _mod.HidDevice_Open
HidDevice_Open.argtypes = (ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int)
HidDevice_Open.restype = ctypes.c_byte
HidDevice_SetTimeouts = _mod.HidDevice_SetTimeouts
HidDevice_SetTimeouts.argtypes = (ctypes.c_void_p, ctypes.c_int, ctypes.c_int)
HidDevice_SetTimeouts.restype = None
HidDevice_Close = _mod.HidDevice_Close
HidDevice_Close.argtypes = (ctypes.c_void_p,)
HidDevice_Close.restype = ctypes.c_int
HidDevice_IsOpened = _mod.HidDevice_IsOpened
HidDevice_IsOpened.argtypes = (ctypes.c_void_p,)
HidDevice_IsOpened.restype = ctypes.c_bool
HidDevice_SetOutputReport_Interrupt = _mod.HidDevice_SetOutputReport_Interrupt
HidDevice_SetOutputReport_Interrupt.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int)
HidDevice_SetOutputReport_Interrupt.restype = ctypes.c_byte
HidDevice_GetInputReport_Interrupt = _mod.HidDevice_GetInputReport_Interrupt
HidDevice_GetInputReport_Interrupt.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
HidDevice_GetInputReport_Interrupt.restype = ctypes.c_byte
HidDevice_GetOutputReportBufferLength = _mod.HidDevice_GetOutputReportBufferLength
HidDevice_GetOutputReportBufferLength.argtypes = (ctypes.c_void_p,)
HidDevice_GetOutputReportBufferLength.restype = ctypes.c_int16
def GetNumHidDevices():
return HidDevice_GetNumHidDevices(VID, PID)
def GetMaxReportRequest(device):
return HidDevice_GetMaxReportRequest(device)
def GetHidString(deviceIndex):
pnt = ctypes.create_string_buffer(MAX_PATH_LENGTH)
status = HidDevice_GetHidString(deviceIndex, VID, PID, HID_PATH_STRING, pnt, MAX_PATH_LENGTH)
if status == HID_DEVICE_SUCCESS:
# Stop at the NUL: the Windows DLL leaves junk in the rest of the buffer
return pnt.value.decode("utf-8")
return ""
def Open(deviceIndex):
handle = ctypes.c_void_p(0)
status = HidDevice_Open(ctypes.byref(handle), deviceIndex, VID, PID, MAX_REPORT_REQUEST_XP)
if status == HID_DEVICE_SUCCESS:
HidDevice_SetTimeouts(handle, HID_READ_TIMEOUT, HID_WRITE_TIMEOUT)
return handle.value
return None
def Close(handle):
hdl = ctypes.c_void_p(handle)
if HidDevice_Close(hdl) == HID_DEVICE_SUCCESS:
return True
else:
return False
def IsOpen(handle):
hdl = ctypes.c_void_p(handle)
return HidDevice_IsOpened(hdl)
def TransmitData(handle, buffer):
hdl = ctypes.c_void_p(handle)
success = False
reportSize = HidDevice_GetOutputReportBufferLength(hdl)
report = bytearray(reportSize)
if reportSize >= SIZE_OUT_DATA:
bytesWritten = 0
bytesToWrite = len(buffer)
pnt = bytes(reportSize)
while bytesWritten < bytesToWrite:
transferSize = min(bytesToWrite - bytesWritten, SIZE_MAX_WRITE)
report = bytearray(reportSize)
report[0] = ID_OUT_DATA
report[1] = transferSize
report[2:2+transferSize] = buffer[bytesWritten:bytesWritten+transferSize]
# pnt = ctypes.cast(bytes(report), ctypes.POINTER(ctypes.c_byte))
if HidDevice_SetOutputReport_Interrupt(hdl, bytes(report), reportSize) != HID_DEVICE_SUCCESS:
# Stop transmitting if there was an error
break
bytesWritten += transferSize
# Write completed successfully
if bytesWritten == bytesToWrite:
success = True
return success
def ReceiveData(handle, bufferSize):
hdl = ctypes.c_void_p(handle)
success = False
buffer = bytearray(bufferSize)
bytesRead = 0
reportSize = HidDevice_GetOutputReportBufferLength(hdl)
if bufferSize >= SIZE_MAX_READ:
numReports = int(bufferSize / SIZE_MAX_READ)
reportBufferSize = numReports * reportSize
reportBuffer = bytearray(reportBufferSize)
reportBufferRead = ctypes.c_int()
pnt = bytes(reportBufferSize)
status = HidDevice_GetInputReport_Interrupt(hdl, pnt, reportBufferSize, numReports, reportBufferRead)
if status == HID_DEVICE_SUCCESS or status == HID_DEVICE_TRANSFER_TIMEOUT:
reportBuffer[:reportBufferSize] = pnt[:reportBufferSize]
for i in range(0, reportBufferRead.value, reportSize):
bytesInReport = reportBuffer[i + 1]
buffer[bytesRead:bytesRead+bytesInReport] = reportBuffer[i+2:i+2+bytesInReport]
bytesRead += bytesInReport
success = True
return success, bytes(buffer[:bytesRead])
def main():
# Module unit testing
handle = 0
NumOfConnectedDevices = GetNumHidDevices()
print("CS108 USB library loaded: ", _mod)
print("Number of USB device(s) connected: ", NumOfConnectedDevices)
for i in range(NumOfConnectedDevices):
print("Device {}: HIDString={}".format(i, GetHidString(i)))
if NumOfConnectedDevices > 0:
handle = Open(0)
if handle != None:
print("Device 0 opened: {}".format(handle))
else:
print("Unable to open device 0")
return
print("Get BT firmware version")
command = BTCommands.GetVersion()
if not TransmitData(handle, command):
print("Device failed to transmit data.")
else:
bufferSize = GetMaxReportRequest(handle) * SIZE_MAX_READ
status, result = ReceiveData(handle, bufferSize)
if not status:
print("Device failed to receive data.")
return
else:
print("Received Data: {}".format(result.hex().upper()))
if Close(handle):
print("Device 0 closed")
else:
print("Unable to close device 0")
if __name__ == '__main__':
main()