summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Auras <yak54@inkennet.de>2011-09-23 22:16:43 +0200
committerAndreas Auras <yak54@inkennet.de>2011-09-23 22:16:43 +0200
commite13185dcc397297442e815cb4372537c86e89afa (patch)
tree282e25b9d62d263280236993b655c0502d80c1b7
parenta9fd3ff0b95b45ea419c701448270a061b28c570 (diff)
downloaddf10ch-atmolight-controller-e13185dcc397297442e815cb4372537c86e89afa.tar.gz
df10ch-atmolight-controller-e13185dcc397297442e815cb4372537c86e89afa.tar.bz2
Setup program version 4:
Exchange pyusb with extracted modules from python-libusb1 project. Add generating .exe file for win32 platform with py2exe. Controller test application version 2: Port application to win32 platform. Added win32 binary distribution generation. Update README and HISTORY.
-rw-r--r--.project4
-rw-r--r--.pydevproject4
-rw-r--r--HISTORY10
-rw-r--r--Makefile10
-rw-r--r--README64
-rw-r--r--df10ch_setup.py2
-rw-r--r--df10ch_setup_pkg/device_dlg.py9
-rw-r--r--df10ch_setup_pkg/device_drv.py137
-rw-r--r--df10ch_setup_pkg/firmware.py3
-rw-r--r--df10ch_setup_pkg/libusb1.py917
-rw-r--r--df10ch_setup_pkg/usb1.py1507
-rw-r--r--project/df10ch_test/df10ch_test.sln20
-rw-r--r--project/df10ch_test/df10ch_test.vcxproj91
-rw-r--r--project/df10ch_test/df10ch_test.vcxproj.filters27
-rw-r--r--setup.py6
-rw-r--r--test_appl/df10ch_test.c101
-rw-r--r--windows/DF10CH.cat3
-rw-r--r--windows/DF10CH.inf132
-rw-r--r--windows/df10ch_setup.bat4
-rw-r--r--winsetup.py50
20 files changed, 2832 insertions, 269 deletions
diff --git a/.project b/.project
index ac8d1ad..2c52d78 100644
--- a/.project
+++ b/.project
@@ -36,7 +36,7 @@
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildLocation</key>
- <value>${workspace_loc:/df10ch/pwm_appl}</value>
+ <value>${workspace_loc:/df10ch/usb_boot}</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
@@ -68,7 +68,7 @@
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
- <value>true</value>
+ <value>false</value>
</dictionary>
</arguments>
</buildCommand>
diff --git a/.pydevproject b/.pydevproject
index f8c0075..46125ea 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -4,4 +4,8 @@
<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/df10ch/df10ch_setup_pkg</path>
+<path>/df10ch</path>
+</pydev_pathproperty>
</pydev_project>
diff --git a/HISTORY b/HISTORY
index a5b8ddb..be80617 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,16 @@
History of changes from newest to oldest:
-----------------------------------------
+Setup program version 4:
+ Exchange pyusb with extracted modules from python-libusb1 project.
+ Add generating .exe file for win32 platform with py2exe.
+
+Controller test application version 2:
+ Port application to win32 platform.
+
+Added win32 binary distribution generation. Everything you need on windows
+is in this package: df10ch_setup, df10ch_test, libusb-1.0, zadig and all firmware files.
+
Added sub directory "windows/" with files for libusb driver installation on MS-Windows.
Added description about libusb driver installation on MS-Windows in file README.
diff --git a/Makefile b/Makefile
index edcaad4..466651c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Andreas Auras
+# Copyright (C) 2011 Andreas Auras
#
# This file is part of the DF10CH Atmolight controller project.
#
@@ -22,11 +22,11 @@
# ################################
FIRMWARE_DIRS = usb_boot usb_appl pwm_boot pwm_appl
-.PHONY: all dist srcdist clean firmware $(FIRMWARE_DIRS)
+.PHONY: all dist srcdist windist clean firmware $(FIRMWARE_DIRS)
all: firmware
-# Build binary distribution (setup program and *.dff firmware files)
+# Build binary distribution (linux) (setup program and *.dff firmware files)
dist: clean firmware
mkdir -p dist
mkdir -p build/firmware
@@ -35,6 +35,10 @@ dist: clean firmware
cp pwm_appl/df10ch_pwm_appl.dff build/firmware/df10ch_pwm_appl.dff
tar -C build -cvzf dist/df10ch_firmware.tar.gz firmware
+# Build binary distribution (windows)
+windist:
+ python winsetup.py py2exe
+
# Build source distribution
srcdist: clean
mkdir -p dist
diff --git a/README b/README
index 63f9525..9719752 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
This is the README file to the DF10CH Atmolight Controller Project.
-Written by: Andreas Auras (yak54@gmx.net)
+Written by: Andreas Auras (yak54@inkennet.de)
See the file COPYING for license information.
@@ -35,10 +35,11 @@ df10ch_common.h Common include file used by firmware
df10ch_usb_proto.h Include file with definitions of implemented USB communication protocol
df10ch_setup.py Main python script of DF10CH setup program
setup.py Python script used for installation of Df10CH setup program
+winsetup.py Python script used for building the Df10CH binary distribution for Windows
MANIFEST.in File used by Python installation script
windows/ MS Windows related files
linux/ Linux related files
-
+project/ Visual C++ 2010 project files for building the df10ch_test program for windows
----------------------
@@ -91,37 +92,34 @@ lose the firmware update feature of the DF10CH setup program.
Installation of USB driver for DF10CH controller
------------------------------------------------
-The DF10CH setup program and test application uses the USB library "libusb" for communication to the controllers.
-Currently there exists two different version of this library called "libusb 0.1" and libusb 1.0".
+The DF10CH setup program and test application uses the USB library "libusb 1.0" for communication to the controllers.
-For Linux you must install the newer implementation "libusb 1.0".
On debian based systems this is packages: libusb-1.0-0.
-For MS Windows you need to install the "libusb-win32 device driver" which is a port of "libusb 0.1":
-
- * Log in as a user with administrator privileges.
- * Download the latest device driver binary package (libusb-win32-device-bin-x.x.x.x.zip or tar.gz) from http://sourceforge.net/projects/libusb-win32/files/
- * Extract it to a temporary directory.
- * Copy the DF10CH.inf and DF10CH.cat files from the windows/ subdirectory to the temporary directory
- * Unplug the device(s) from the system.
- * Open the Windows Device Manager and remove all incorrectly installed USB devices (device entries with a yellow exclamation mark).
- * Reconnect the device(s) to the system.
- * When Windows asks for a driver, choose the inf-file(s) copyed above. On Win2k, WinXP, Windows will warn that the driver is is not 'digitally signed'.
- Ignore this message and continue with the installation. It is similar for Windows Vista and Windows 7 32bit systems.
- For 64bit Vista and Windows 7 systems, a valid digital signature is required. Please read more about the Microsoft Kernel Mode Code Signing (KMCS) policy for more information.
- * Open the Windows Device Manager to verify that the device is installed correctly. Run the test program (testlibusb-win.exe) from the 'bin directory'.
- It should print out the descriptors of your device(s).
- * A reboot isn't necessary.
+For MS Windows you need to install the "WinUSB" device driver which can be installed with a nice dedicated setup
+program called 'zadig' that could be downloaded from here:
+ http://sourceforge.net/apps/mediawiki/libwdi/index.php?title=Main_Page
+
+ Attach your controller to your windows box and follow the usage instructions for 'zadig' that could be found here:
+
+ http://sourceforge.net/apps/mediawiki/libwdi/index.php?title=Zadig
+
+The program should show the DF10CH controller in the device selection box.
+Select the device and install the 'WinUSB' driver for it.
+
+In case there is already a (older) driver installed for the controller the device will not be shown. Select
+"Options/List all Devices", select the DF10CH device and reinstall the 'WinUSB' driver.
+
------------------------------------
Installation of DF10CH setup program
------------------------------------
-For running the DF10CH setup program you need a installed python environment version 2.6,
-the python modules TKinter, Image, ImageTk, ImageDraw and PyUSB and a installed libusb library.
+For running the DF10CH setup program under Linux you need a installed python environment version 2.6,
+the python modules TKinter, Image, ImageTk, ImageDraw and a installed 'libusb 1.0' library.
On debian based systems these are packages: python2.6, python-tk, python-imaging, python-imaging-tk,
-python-usb, libusb-1.0-0
+libusb-1.0-0
You can start the program directly from the distribution directory with:
@@ -135,17 +133,25 @@ Now df10ch_setup.py should be simply in your standard PATH for execution. Start
df10ch_setup.py
-If the setup program does not find any controller(s) under linux the problem may be missing access rights to the
+If the setup program does not find any controller(s) under Linux the problem may be missing access rights to the
usb device. Either execute the program with 'root' privileges and/or install the udev rule file
'linux/45-df10ch.rules' after customizing it for your needs to /etc/udev/rules.d to change the privileges
settings for the USB device.
-
+
+
+Windows users should use the ready compiled df10ch_setup program from the windows binary distribution.
+From within the binary distribution directory start the setup program with:
+
+ .\df10ch_setup.bat
+
+
The setup program understands the following command line option:
-d N Set debug level to N
-s N Set number of simulated controllers. With this option you can play with
the program without having hardware.
+
-----------------------------------------------------
Compiling and running the controller test application
@@ -160,8 +166,6 @@ already changed the channel mapping with the setup program.
For compiling the application you need a installed libusb 1.0 library.
On debian based systems this is packages: libusb-1.0-0.
-Currently this application is not tested against MS-Windows because there is no existing
-port of libusb 1.0 for this platform!!
cd test_appl
make
@@ -171,6 +175,12 @@ Running the application:
./df10ch-test <number-of-test-loops>
e.g. ./df10ch-test 50
+
+Again windows users should use the ready compiled df10ch_test program from the windows binary distribution.
+From within the binary distribution directory start the test program with:
+
+ .\df10ch_test.exe <number-of-test-loops>
+
diff --git a/df10ch_setup.py b/df10ch_setup.py
index d7eddf1..34aba7a 100644
--- a/df10ch_setup.py
+++ b/df10ch_setup.py
@@ -35,7 +35,7 @@ from df10ch_setup_pkg.white_cal_dlg import WhiteCalDialog
from df10ch_setup_pkg.bright_dlg import BrightDialog
import df10ch_setup_pkg.device_drv
-TITLE = "DF10CH Setup V3"
+TITLE = "DF10CH Setup V4"
print
parser = OptionParser(version=TITLE)
parser.add_option("-s", "--simulate", action="store", type="int", dest="simulate", default=0, help="Set simulated number of DF10CH controller's")
diff --git a/df10ch_setup_pkg/device_dlg.py b/df10ch_setup_pkg/device_dlg.py
index 4606a7b..4d7968d 100644
--- a/df10ch_setup_pkg/device_dlg.py
+++ b/df10ch_setup_pkg/device_dlg.py
@@ -24,7 +24,6 @@ from Tkinter import *
import tkFont
import tkMessageBox
import tkFileDialog
-import usb
import pickle
import string
import time
@@ -170,7 +169,7 @@ class DeviceDialog:
while retry:
try:
device_drv.LoadConfigs()
- except (device_drv.AtmoControllerError, usb.USBError) as err:
+ except (device_drv.AtmoControllerError, device_drv.DeviceError) as err:
if not tkMessageBox.askretrycancel(self.root.winfo_toplevel().title(), "Scanning for controllers fails:" + err.__str__(), icon=tkMessageBox.ERROR):
if len(device_drv.DeviceList):
retry = False
@@ -206,9 +205,9 @@ class DeviceDialog:
self.loadDeviceValues()
else:
if dev.bootloader_mode():
- s = "Bootloader USB:{0}".format(dev.version)
+ s = "Bootloader USB:{0:04X}".format(dev.version)
else:
- s = "USB:{0} Bootloader PWM:{1:04X}".format(dev.version, dev.get_pwm_version())
+ s = "USB:{0:04X} Bootloader PWM:{1:04X}".format(dev.version, dev.get_pwm_version())
self.varVersion.set(s)
self.lbDevices.selection_clear(0, END)
self.lbDevices.selection_set(i)
@@ -351,7 +350,7 @@ class DeviceDialog:
time.sleep(5.0)
try:
device_drv.FindDevices()
- except (device_drv.AtmoControllerError, usb.USBError) as err:
+ except (device_drv.AtmoControllerError, device_drv.DeviceError) as err:
tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
doFlash = False
diff --git a/df10ch_setup_pkg/device_drv.py b/df10ch_setup_pkg/device_drv.py
index 61e5e2b..ddb22d0 100644
--- a/df10ch_setup_pkg/device_drv.py
+++ b/df10ch_setup_pkg/device_drv.py
@@ -21,10 +21,10 @@
#
import os
-import usb
import time
import pickle
import string
+import array
# ---
# Communication protocol related defines for 10 channel RGB Controller.
@@ -287,13 +287,21 @@ def AreaCode(area, color):
return ((areaIdx << 2) + (color & 0x03)), areaNum
+class DeviceError(Exception):
+ def __init__(self, msg):
+ self.message = msg
+
+ def __str__(self):
+ return self.message
+
+
class AtmoControllerError(Exception):
- def __init__(self, dev, msg):
- self.id = dev.id
- self.message = msg
+ def __init__(self, dev, msg):
+ self.id = dev.id
+ self.message = msg
- def __str__(self):
- return '{0}: {1}'.format(self.id, self.message)
+ def __str__(self):
+ return '{0}: {1}'.format(self.id, self.message)
@@ -312,20 +320,34 @@ class DF10CHController:
self.error_count = 0
def release(self):
- self.usbdev.releaseInterface()
+ self.usbdev.releaseInterface(0)
+ self.usbdev.close()
def bootloader_mode(self):
return self.serial == "BL"
def ctrl_write(self, req, value, index, data, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
+ if isinstance(data, basestring):
+ sdata = data
+ else:
+ if isinstance(data, bytearray):
+ bdata = data
+ else:
+ l = len(data)
+ bdata = bytearray(l)
+ while l:
+ l = l - 1
+ bdata[l] = data[l]
+ sdata = str(bdata)
+
while retry > 0:
try:
retry = retry - 1
- written = self.usbdev.controlMsg(usb.ENDPOINT_OUT|usb.RECIP_DEVICE|usb.TYPE_VENDOR, req, data, value, index, timeout)
- except usb.USBError as err:
+ written = self.usbdev.controlWrite(libusb1.LIBUSB_RECIPIENT_DEVICE|libusb1.LIBUSB_TYPE_VENDOR, req, value, index, sdata, timeout)
+ except libusb1.USBError as err:
self.error_count = self.error_count + 1
print 'write req={0}, retry={1}: {2}'.format(req, retry, err.__str__())
- if retry == 0:
+ if retry == 0 or err.value != libusb1.LIBUSB_ERROR_PIPE:
raise AtmoControllerError(self, 'write req={0}: {1}'.format(req, err.__str__()))
else:
if written != len(data):
@@ -334,13 +356,17 @@ class DF10CHController:
break
def ctrl_read(self, req, value = 0, index = 0, size = 0, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
+ if size > 0:
+ n = size
+ else:
+ n = 1
while retry > 0:
try:
retry = retry - 1
- data = self.usbdev.controlMsg(usb.ENDPOINT_IN|usb.RECIP_DEVICE|usb.TYPE_VENDOR, req, size, value, index, timeout)
- except usb.USBError as err:
+ data = self.usbdev.controlRead(libusb1.LIBUSB_RECIPIENT_DEVICE|libusb1.LIBUSB_TYPE_VENDOR, req, value, index, n, timeout)
+ except libusb1.USBError as err:
print 'read req={0}, retry={1}: {2}'.format(req, retry, err.__str__())
- if retry == 0:
+ if retry == 0 or err.value != libusb1.LIBUSB_ERROR_PIPE:
self.error_count = self.error_count + 1
raise AtmoControllerError(self, 'read req={0}: {1}'.format(req, err.__str__()))
else:
@@ -348,7 +374,7 @@ class DF10CHController:
self.error_count = self.error_count + 1
raise AtmoControllerError(self, 'read req={0}: could not read all payload data'.format(req))
break
- return data
+ return bytearray(data)
def pwm_ctrl_write(self, req, value, index, data, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
if len(data) > MAX_PWM_REQ_PAYLOAD_SIZE:
@@ -413,22 +439,24 @@ class DF10CHController:
return data[0]
def set_brightness(self, start, values):
- data = list();
- for i in range(len(values)):
- data.append(values[i] & 0x00FF)
- data.append(values[i] / 256)
+ l = len(values)
+ data = bytearray(l*2)
+ for i in range(l):
+ data[i*2] = values[i] & 0x00FF
+ data[i*2+1] = values[i] / 256
self.pwm_ctrl_write(PWM_REQ_SET_BRIGHTNESS, 0, start, data)
def set_brightness_synced(self, start, values):
- data = list();
- for i in range(len(values)):
- data.append(values[i] & 0x00FF)
- data.append(values[i] / 256)
+ l = len(values)
+ data = bytearray(l*2)
+ for i in range(l):
+ data[i*2] = values[i] & 0x00FF
+ data[i*2+1] = values[i] / 256
self.pwm_ctrl_write(PWM_REQ_SET_BRIGHTNESS_SYNCED, 0, start, data)
def get_brightness(self, start, nch):
data = self.pwm_ctrl_read(PWM_REQ_GET_BRIGHTNESS, 0, start, nch * 2)
- values = list()
+ values = array.array('H')
for i in range(nch):
values.append(data[i*2] + data[i*2+1] * 256)
return values;
@@ -441,7 +469,7 @@ class DF10CHController:
return map;
def set_channel_map(self, start, map):
- data = list()
+ data = bytearray()
for mapRec in map:
data.append(CM_CODE(mapRec['port'], mapRec['channel']))
data.append(mapRec['pins'])
@@ -727,7 +755,7 @@ class ControllerConfig:
self.edgeWeighting = max(min(eedata[p + 2], MAX_EDGE_WEIGHTING), MIN_EDGE_WEIGHTING)
else:
configVersionStr = ""
- self.version = "USB:{0} PWM:{1:04X} CONFIG:{2}".format(self.ctrl.version, self.ctrl.get_pwm_version(), configVersionStr)
+ self.version = "USB:{0:04X} PWM:{1:04X} CONFIG:{2}".format(self.ctrl.version, self.ctrl.get_pwm_version(), configVersionStr)
pwmChannelMap = self.ctrl.get_channel_map(0, NCHANNELS)
#print "read pwmChannelMap", pwmChannelMap
self.channelMap = dict()
@@ -760,7 +788,7 @@ class ControllerConfig:
def write(self):
#print "write channelMap:", self.channelMap
- eedata = list()
+ eedata = bytearray()
eedata.append(CONFIG_VALID_ID & 0x00FF)
eedata.append(CONFIG_VALID_ID >> 8)
eedata.append(CONFIG_VERSION & 0x00FF)
@@ -829,50 +857,49 @@ class ControllerConfig:
self.pwmFreq = v
+UsbContext = None
DeviceList = list()
def FindDevices():
- global DeviceList
+ global DeviceList, UsbContext, libusb1, usb1
+ if UsbContext == None and SimulatedControllers == 0:
+ try:
+ import libusb1
+ import usb1
+ UsbContext = usb1.LibUSBContext()
+ except Exception as err:
+ raise DeviceError(str(err))
+
ReleaseDevices()
- if SimulatedControllers:
+ if SimulatedControllers > 0:
DeviceList = loadDummyDevices()
return
- busses = usb.busses()
- busnum = 0
- for bus in busses:
- devnum = 0
- for dev in bus.devices:
- if dev.idProduct == PRODUCT_ID and dev.idVendor == VENDOR_ID:
- try:
- handle = dev.open()
- if handle.getString(dev.iManufacturer, 64) == VENDOR_NAME and handle.getString(dev.iProduct, 64) == DEVICE_NAME:
- handle.setConfiguration(1)
- handle.claimInterface(0)
- serial = handle.getString(dev.iSerialNumber, 64)
- if os.name == "nt":
- bn = bus.location
- dn = dev.devnum
- else:
- bn = busnum
- dn = devnum
- ctrl = DF10CHController(handle, bn, dn, dev.deviceVersion, serial)
- DeviceList.append(ctrl)
- except usb.USBError:
- pass
- devnum = devnum + 1
- busnum = busnum + 1
+ for dev in UsbContext.getDeviceList():
+ try:
+ if dev.getVendorID() == VENDOR_ID and dev.getProductID() == PRODUCT_ID and dev.getManufacturer() == VENDOR_NAME and dev.getProduct() == DEVICE_NAME:
+ serial = dev.getSerialNumber()
+ handle = dev.open()
+ handle.setConfiguration(1)
+ handle.claimInterface(0)
+ ctrl = DF10CHController(handle, dev.getBusNumber(), dev.getDeviceAddress(), dev.getbcdDevice(), serial)
+ DeviceList.append(ctrl)
+ except libusb1.USBError:
+ pass
def ReleaseDevices():
global DeviceList
for dev in DeviceList:
- try:
+ if SimulatedControllers > 0:
dev.release()
- except usb.USBError:
- pass
+ else:
+ try:
+ dev.release()
+ except libusb1.USBError:
+ pass
DeviceList = list()
diff --git a/df10ch_setup_pkg/firmware.py b/df10ch_setup_pkg/firmware.py
index 24dc577..94c66cb 100644
--- a/df10ch_setup_pkg/firmware.py
+++ b/df10ch_setup_pkg/firmware.py
@@ -20,7 +20,6 @@
# This file is part of the DF10CH setup program
#
-import array
import fileinput
import string
@@ -37,7 +36,7 @@ class FlashPage:
def __init__(self, addr, pageSize):
self.pageSize = pageSize
self.baseAddr = addr - addr % pageSize
- self.data = array.array('B', [ 0xFF ] * pageSize)
+ self.data = bytearray([ 0xFF ] * pageSize)
def insert(self, addr, value):
self.data[addr % self.pageSize] = value
diff --git a/df10ch_setup_pkg/libusb1.py b/df10ch_setup_pkg/libusb1.py
new file mode 100644
index 0000000..3cf408f
--- /dev/null
+++ b/df10ch_setup_pkg/libusb1.py
@@ -0,0 +1,917 @@
+"""
+Pythonic wrapper for libusb-1.0.
+
+This file has been extracted from the python-libusb1 project:
+ http://github.com/vpelletier/python-libusb1
+
+"""
+
+from ctypes import Structure, \
+ CFUNCTYPE, POINTER, addressof, sizeof, cast, \
+ c_short, c_int, c_uint, c_size_t, c_long, \
+ c_uint8, c_uint16, \
+ c_void_p, c_char, c_char_p, py_object, string_at
+from ctypes.util import find_library
+import platform
+import os.path
+import sys
+
+class Enum(object):
+ def __init__(self, member_dict):
+ forward_dict = {}
+ reverse_dict = {}
+ module_globals = globals()
+ next_value = 0
+ for name, value in member_dict.iteritems():
+ 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
+ module_globals[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)
+
+class USBError(Exception):
+ def __init__(self, value):
+ Exception.__init__(self)
+ self.value = value
+
+ def __str__(self):
+ return '%s [%s]' % (libusb_error.get(self.value, 'Unknown error'),
+ self.value)
+
+c_uchar = c_uint8
+c_int_p = POINTER(c_int)
+
+PATH_MAX = 4096 # XXX: True on linux, no idea about others.
+LITTLE_ENDIAN = sys.byteorder == 'little'
+
+class timeval(Structure):
+ _fields_ = [('tv_sec', c_long),
+ ('tv_usec', c_long)]
+timeval_p = POINTER(timeval)
+
+def _loadLibrary():
+ system = platform.system()
+ if system == 'Windows':
+ from ctypes import WinDLL as dll_loader
+ libusb_path = find_library("libusb-1.0.dll")
+ else:
+ from ctypes import CDLL as dll_loader
+ libusb_path = find_library("usb-1.0")
+ if libusb_path is None and system == 'Darwin':
+ # macport standard library path
+ libusb_path = '/opt/local/lib/libusb-1.0.dylib'
+ if not os.path.isfile(libusb_path):
+ libusb_path = None
+ if libusb_path is None:
+ raise Exception('Can\'t locate usb-1.0 library')
+ loader_kw = {}
+ if sys.version_info[:2] >= (2, 6):
+ loader_kw['use_errno'] = True
+ loader_kw['use_last_error'] = True
+ return dll_loader(libusb_path, **loader_kw)
+
+libusb = _loadLibrary()
+
+# libusb.h
+def bswap16(x):
+ return (((x & 0xff) << 8) | (x >> 8))
+
+if LITTLE_ENDIAN:
+ def libusb_cpu_to_le16(x):
+ return x
+ def libusb_le16_to_cpu(x):
+ return x
+else:
+ libusb_cpu_to_le16 = bswap16
+ libusb_le16_to_cpu = bswap16
+
+# standard USB stuff
+
+# Device and/or Interface Class codes
+libusb_class_code = Enum({
+# In the context of a device descriptor,
+# this bDeviceClass value indicates that each interface specifies its
+# own class information and all interfaces operate independently.
+'LIBUSB_CLASS_PER_INTERFACE': 0,
+# Audio class
+'LIBUSB_CLASS_AUDIO': 1,
+# Communications class
+'LIBUSB_CLASS_COMM': 2,
+# Human Interface Device class
+'LIBUSB_CLASS_HID': 3,
+# Printer dclass
+'LIBUSB_CLASS_PRINTER': 7,
+# Picture transfer protocol class
+'LIBUSB_CLASS_PTP': 6,
+# Mass storage class
+'LIBUSB_CLASS_MASS_STORAGE': 8,
+# Hub class
+'LIBUSB_CLASS_HUB': 9,
+# Data class
+'LIBUSB_CLASS_DATA': 10,
+# Wireless class
+'LIBUSB_CLASS_WIRELESS': 0xe0,
+# Application class
+'LIBUSB_CLASS_APPLICATION': 0xfe,
+# Class is vendor-specific
+'LIBUSB_CLASS_VENDOR_SPEC': 0xff
+})
+
+# Descriptor types as defined by the USB specification.
+libusb_descriptor_type = Enum({
+# Device descriptor. See libusb_device_descriptor.
+'LIBUSB_DT_DEVICE': 0x01,
+# Configuration descriptor. See libusb_config_descriptor.
+'LIBUSB_DT_CONFIG': 0x02,
+# String descriptor
+'LIBUSB_DT_STRING': 0x03,
+# Interface descriptor. See libusb_interface_descriptor.
+'LIBUSB_DT_INTERFACE': 0x04,
+# Endpoint descriptor. See libusb_endpoint_descriptor.
+'LIBUSB_DT_ENDPOINT': 0x05,
+# HID descriptor
+'LIBUSB_DT_HID': 0x21,
+# HID report descriptor
+'LIBUSB_DT_REPORT': 0x22,
+# Physical descriptor
+'LIBUSB_DT_PHYSICAL': 0x23,
+# Hub descriptor
+'LIBUSB_DT_HUB': 0x29
+})
+
+# Descriptor sizes per descriptor type
+LIBUSB_DT_DEVICE_SIZE = 18
+LIBUSB_DT_CONFIG_SIZE = 9
+LIBUSB_DT_INTERFACE_SIZE = 9
+LIBUSB_DT_ENDPOINT_SIZE = 7
+LIBUSB_DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
+LIBUSB_DT_HUB_NONVAR_SIZE = 7
+
+USB_ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
+USB_ENDPOINT_DIR_MASK = 0x80
+
+# Endpoint direction. Values for bit 7 of the endpoint address scheme.
+libusb_endpoint_direction = Enum({
+# In: device-to-host
+'LIBUSB_ENDPOINT_IN': 0x80,
+# Out: host-to-device
+'LIBUSB_ENDPOINT_OUT': 0x00
+})
+
+LIBUSB_TRANSFER_TYPE_MASK = 0x03 # in bmAttributes
+
+# Endpoint transfer type. Values for bits 0:1 of the endpoint attributes field.
+libusb_transfer_type = Enum({
+# Control endpoint
+'LIBUSB_TRANSFER_TYPE_CONTROL': 0,
+# Isochronous endpoint
+'LIBUSB_TRANSFER_TYPE_ISOCHRONOUS': 1,
+# Bulk endpoint
+'LIBUSB_TRANSFER_TYPE_BULK': 2,
+# Interrupt endpoint
+'LIBUSB_TRANSFER_TYPE_INTERRUPT': 3
+})
+
+# Standard requests, as defined in table 9-3 of the USB2 specifications
+libusb_standard_request = Enum({
+# Request status of the specific recipient
+'LIBUSB_REQUEST_GET_STATUS': 0x00,
+# Clear or disable a specific feature
+'LIBUSB_REQUEST_CLEAR_FEATURE': 0x01,
+# 0x02 is reserved
+# Set or enable a specific feature
+'LIBUSB_REQUEST_SET_FEATURE': 0x03,
+# 0x04 is reserved
+# Set device address for all future accesses
+'LIBUSB_REQUEST_SET_ADDRESS': 0x05,
+# Get the specified descriptor
+'LIBUSB_REQUEST_GET_DESCRIPTOR': 0x06,
+# Used to update existing descriptors or add new descriptors
+'LIBUSB_REQUEST_SET_DESCRIPTOR': 0x07,
+# Get the current device configuration value
+'LIBUSB_REQUEST_GET_CONFIGURATION': 0x08,
+# Set device configuration
+'LIBUSB_REQUEST_SET_CONFIGURATION': 0x09,
+# Return the selected alternate setting for the specified interface
+'LIBUSB_REQUEST_GET_INTERFACE': 0x0a,
+# Select an alternate interface for the specified interface
+'LIBUSB_REQUEST_SET_INTERFACE': 0x0b,
+# Set then report an endpoint's synchronization frame
+'LIBUSB_REQUEST_SYNCH_FRAME': 0x0c
+})
+
+# Request type bits of the bmRequestType field in control transfers.
+libusb_request_type = Enum({
+# Standard
+'LIBUSB_TYPE_STANDARD': (0x00 << 5),
+# Class
+'LIBUSB_TYPE_CLASS': (0x01 << 5),
+# Vendor
+'LIBUSB_TYPE_VENDOR': (0x02 << 5),
+# Reserved
+'LIBUSB_TYPE_RESERVED': (0x03 << 5)
+})
+
+# Recipient bits of the bmRequestType field in control transfers. Values 4
+# through 31 are reserved.
+libusb_request_recipient = Enum({
+# Device
+'LIBUSB_RECIPIENT_DEVICE': 0x00,
+# Interface
+'LIBUSB_RECIPIENT_INTERFACE': 0x01,
+# Endpoint
+'LIBUSB_RECIPIENT_ENDPOINT': 0x02,
+# Other
+'LIBUSB_RECIPIENT_OTHER': 0x03
+})
+
+LIBUSB_ISO_SYNC_TYPE_MASK = 0x0c
+
+# Synchronization type for isochronous endpoints. Values for bits 2:3 of the
+# bmAttributes field in libusb_endpoint_descriptor.
+libusb_iso_sync_type = Enum({
+# No synchronization
+'LIBUSB_ISO_SYNC_TYPE_NONE': 0,
+# Asynchronous
+'LIBUSB_ISO_SYNC_TYPE_ASYNC': 1,
+# Adaptive
+'LIBUSB_ISO_SYNC_TYPE_ADAPTIVE': 2,
+# Synchronous
+'LIBUSB_ISO_SYNC_TYPE_SYNC': 3
+})
+
+LIBUSB_ISO_USAGE_TYPE_MASK = 0x30
+
+# Usage type for isochronous endpoints. Values for bits 4:5 of the
+# bmAttributes field in libusb_endpoint_descriptor.
+libusb_iso_usage_type = Enum({
+# Data endpoint
+'LIBUSB_ISO_USAGE_TYPE_DATA': 0,
+# Feedback endpoint
+'LIBUSB_ISO_USAGE_TYPE_FEEDBACK': 1,
+# Implicit feedback Data endpoint
+'LIBUSB_ISO_USAGE_TYPE_IMPLICIT': 2
+})
+
+# A structure representing the standard USB device descriptor. This
+# descriptor is documented in section 9.6.1 of the USB 2.0 specification.
+# All multiple-byte fields are represented in host-endian format.
+class libusb_device_descriptor(Structure):
+ _fields_ = [# Size of this descriptor (in bytes)
+ ('bLength', c_uint8),
+ # Descriptor type. Will have value LIBUSB_DT_DEVICE in this
+ # context.
+ ('bDescriptorType', c_uint8),
+ # USB specification release number in binary-coded decimal. A
+ # value of 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1,
+ # etc.
+ ('bcdUSB', c_uint16),
+ # USB-IF class code for the device. See libusb_class_code.
+ ('bDeviceClass', c_uint8),
+ # USB-IF subclass code for the device, qualified by the
+ # bDeviceClass value
+ ('bDeviceSubClass', c_uint8),
+ # USB-IF protocol code for the device, qualified by the
+ # bDeviceClass and bDeviceSubClass values
+ ('bDeviceProtocol', c_uint8),
+ # Maximum packet size for endpoint 0
+ ('bMaxPacketSize0', c_uint8),
+ # USB-IF vendor ID
+ ('idVendor', c_uint16),
+ # USB-IF product ID
+ ('idProduct', c_uint16),
+ # Device release number in binary-coded decimal
+ ('bcdDevice', c_uint16),
+ # Index of string descriptor describing manufacturer
+ ('iManufacturer', c_uint8),
+ # Index of string descriptor describing product
+ ('iProduct', c_uint8),
+ # Index of string descriptor containing device serial number
+ ('iSerialNumber', c_uint8),
+ # Number of possible configurations
+ ('bNumConfigurations', c_uint8)]
+libusb_device_descriptor_p = POINTER(libusb_device_descriptor)
+
+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)
+
+class libusb_interface_descriptor(Structure):
+ _fields_ = [('bLength', c_uint8),
+ ('bDescriptorType', c_uint8),
+ ('bInterfaceNumber', c_uint8),
+ ('bAlternateSetting', c_uint8),
+ ('bNumEndpoints', c_uint8),
+ ('bInterfaceClass', c_uint8),
+ ('bInterfaceSubClass', c_uint8),
+ ('bInterfaceProtocol', c_uint8),
+ ('iInterface', c_uint8),
+ ('endpoint', libusb_endpoint_descriptor_p),
+ ('extra', c_void_p),
+ ('extra_length', c_int)]
+libusb_interface_descriptor_p = POINTER(libusb_interface_descriptor)
+
+class libusb_interface(Structure):
+ _fields_ = [('altsetting', libusb_interface_descriptor_p),
+ ('num_altsetting', c_int)]
+libusb_interface_p = POINTER(libusb_interface)
+
+class libusb_config_descriptor(Structure):
+ _fields_ = [('bLength', c_uint8),
+ ('bDescriptorType', c_uint8),
+ ('wTotalLength', c_uint16),
+ ('bNumInterfaces', c_uint8),
+ ('bConfigurationValue', c_uint8),
+ ('iConfiguration', c_uint8),
+ ('bmAttributes', c_uint8),
+ ('MaxPower', c_uint8),
+ ('interface', libusb_interface_p),
+ ('extra', c_void_p),
+ ('extra_length', c_int)]
+libusb_config_descriptor_p = POINTER(libusb_config_descriptor)
+libusb_config_descriptor_p_p = POINTER(libusb_config_descriptor_p)
+
+class libusb_control_setup(Structure):
+ _fields_ = [('bRequestType', c_uint8),
+ ('bRequest', c_uint8),
+ ('wValue', c_uint16),
+ ('wIndex', c_uint16),
+ ('wLength', c_uint16)]
+libusb_control_setup_p = POINTER(libusb_control_setup)
+
+LIBUSB_CONTROL_SETUP_SIZE = sizeof(libusb_control_setup)
+
+# Structure representing a libusb session. The concept of individual libusb
+# sessions allows for your program to use two libraries (or dynamically
+# load two modules) which both independently use libusb. This will prevent
+# interference between the individual libusb users - for example
+# libusb_set_debug() will not affect the other user of the library, and
+# libusb_exit() will not destroy resources that the other user is still
+# using.
+#
+# Sessions are created by libusb_init() and destroyed through libusb_exit().
+# If your application is guaranteed to only ever include a single libusb
+# user (i.e. you), you do not have to worry about contexts: pass NULL in
+# every function call where a context is required. The default context
+# will be used.
+#
+# For more information, see \ref contexts.
+class libusb_context(Structure):
+ pass
+libusb_context_p = POINTER(libusb_context)
+libusb_context_p_p = POINTER(libusb_context_p)
+
+# Structure representing a USB device detected on the system. This is an
+# opaque type for which you are only ever provided with a pointer, usually
+# originating from libusb_get_device_list().
+#
+# Certain operations can be performed on a device, but in order to do any
+# I/O you will have to first obtain a device handle using libusb_open().
+#
+# Devices are reference counted with libusb_device_ref() and
+# libusb_device_unref(), and are freed when the reference count reaches 0.
+# New devices presented by libusb_get_device_list() have a reference count of
+# 1, and libusb_free_device_list() can optionally decrease the reference count
+# on all devices in the list. libusb_open() adds another reference which is
+# later destroyed by libusb_close().
+class libusb_device(Structure):
+ pass
+libusb_device_p = POINTER(libusb_device)
+libusb_device_p_p = POINTER(libusb_device_p)
+libusb_device_p_p_p = POINTER(libusb_device_p_p)
+
+# Structure representing a handle on a USB device. This is an opaque type for
+# which you are only ever provided with a pointer, usually originating from
+# libusb_open().
+#
+# A device handle is used to perform I/O and other operations. When finished
+# with a device handle, you should call libusb_close().
+class libusb_device_handle(Structure):
+ pass
+libusb_device_handle_p = POINTER(libusb_device_handle)
+libusb_device_handle_p_p = POINTER(libusb_device_handle_p)
+
+# Error codes. Most libusb functions return 0 on success or one of these
+# codes on failure.
+libusb_error = Enum({
+# Success (no error)
+'LIBUSB_SUCCESS': 0,
+# Input/output error
+'LIBUSB_ERROR_IO': -1,
+# Invalid parameter
+'LIBUSB_ERROR_INVALID_PARAM': -2,
+# Access denied (insufficient permissions)
+'LIBUSB_ERROR_ACCESS': -3,
+# No such device (it may have been disconnected)
+'LIBUSB_ERROR_NO_DEVICE': -4,
+# Entity not found
+'LIBUSB_ERROR_NOT_FOUND': -5,
+# Resource busy
+'LIBUSB_ERROR_BUSY': -6,
+# Operation timed out
+'LIBUSB_ERROR_TIMEOUT': -7,
+# Overflow
+'LIBUSB_ERROR_OVERFLOW': -8,
+# Pipe error
+'LIBUSB_ERROR_PIPE': -9,
+# System call interrupted (perhaps due to signal)
+'LIBUSB_ERROR_INTERRUPTED': -10,
+# Insufficient memory
+'LIBUSB_ERROR_NO_MEM': -11,
+# Operation not supported or unimplemented on this platform
+'LIBUSB_ERROR_NOT_SUPPORTED': -12,
+# Other error
+'LIBUSB_ERROR_OTHER': -99
+})
+
+# Transfer status codes
+libusb_transfer_status = Enum({
+# Transfer completed without error. Note that this does not indicate
+# that the entire amount of requested data was transferred.
+'LIBUSB_TRANSFER_COMPLETED': 0,
+# Transfer failed
+'LIBUSB_TRANSFER_ERROR': 1,
+# Transfer timed out
+'LIBUSB_TRANSFER_TIMED_OUT': 2,
+# Transfer was cancelled
+'LIBUSB_TRANSFER_CANCELLED': 3,
+# For bulk/interrupt endpoints: halt condition detected (endpoint
+# stalled). For control endpoints: control request not supported.
+'LIBUSB_TRANSFER_STALL': 4,
+# Device was disconnected
+'LIBUSB_TRANSFER_NO_DEVICE': 5,
+# Device sent more data than requested
+'LIBUSB_TRANSFER_OVERFLOW': 6
+})
+
+# libusb_transfer.flags values
+libusb_transfer_flags = Enum({
+# Report short frames as errors
+'LIBUSB_TRANSFER_SHORT_NOT_OK': 1<<0,
+# Automatically free() transfer buffer during libusb_free_transfer()
+'LIBUSB_TRANSFER_FREE_BUFFER': 1<<1,
+# Automatically call libusb_free_transfer() after callback returns.
+# If this flag is set, it is illegal to call libusb_free_transfer()
+# from your transfer callback, as this will result in a double-free
+# when this flag is acted upon.
+'LIBUSB_TRANSFER_FREE_TRANSFER': 1<<2
+})
+
+# Isochronous packet descriptor.
+class libusb_iso_packet_descriptor(Structure):
+ _fields_ = [('length', c_uint),
+ ('actual_length', c_uint),
+ ('status', c_int)] # enum libusb_transfer_status
+libusb_iso_packet_descriptor_p = POINTER(libusb_iso_packet_descriptor)
+
+class libusb_transfer(Structure):
+ pass
+libusb_transfer_p = POINTER(libusb_transfer)
+
+libusb_transfer_cb_fn_p = CFUNCTYPE(None, libusb_transfer_p)
+
+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', py_object),
+ ('buffer', c_void_p),
+ ('num_iso_packets', c_int),
+ ('iso_packet_desc', libusb_iso_packet_descriptor)
+]
+
+#int libusb_init(libusb_context **ctx);
+libusb_init = libusb.libusb_init
+libusb_init.argtypes = [libusb_context_p_p]
+#void libusb_exit(libusb_context *ctx);
+libusb_exit = libusb.libusb_exit
+libusb_exit.argtypes = [libusb_context_p]
+libusb_exit.restype = None
+#void libusb_set_debug(libusb_context *ctx, int level);
+libusb_set_debug = libusb.libusb_set_debug
+libusb_set_debug.argtypes = [libusb_context_p, c_int]
+libusb_set_debug.restype = None
+try:
+ #char *libusb_strerror(enum libusb_error errcode);
+ libusb_strerror = libusb.libusb_strerror
+except AttributeError:
+ # Place holder
+ def libusb_strerror(errcode):
+ return None
+else:
+ libusb_strerror.argtypes = [c_int]
+ libusb_strerror.restype = c_char_p
+
+#ssize_t libusb_get_device_list(libusb_context *ctx,
+# libusb_device ***list);
+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_size_t
+#void libusb_free_device_list(libusb_device **list, int unref_devices);
+libusb_free_device_list = libusb.libusb_free_device_list
+libusb_free_device_list.argtypes = [libusb_device_p_p, c_int]
+libusb_free_device_list.restype = None
+#libusb_device *libusb_ref_device(libusb_device *dev);
+libusb_ref_device = libusb.libusb_ref_device
+libusb_ref_device.argtypes = [libusb_device_p]
+libusb_ref_device.restype = libusb_device_p
+#void libusb_unref_device(libusb_device *dev);
+libusb_unref_device = libusb.libusb_unref_device
+libusb_unref_device.argtypes = [libusb_device_p]
+libusb_unref_device.restype = None
+
+#int libusb_get_configuration(libusb_device_handle *dev, int *config);
+libusb_get_configuration = libusb.libusb_get_configuration
+libusb_get_configuration.argtypes = [libusb_device_handle_p, c_int_p]
+#int libusb_get_device_descriptor(libusb_device *dev,
+# struct libusb_device_descriptor *desc);
+libusb_get_device_descriptor = libusb.libusb_get_device_descriptor
+libusb_get_device_descriptor.argtypes = [libusb_device_p,
+ libusb_device_descriptor_p]
+#int libusb_get_active_config_descriptor(libusb_device *dev,
+# struct libusb_config_descriptor **config);
+libusb_get_active_config_descriptor = libusb.libusb_get_active_config_descriptor
+libusb_get_active_config_descriptor.argtypes = [libusb_device_p,
+ libusb_config_descriptor_p_p]
+#int libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index,
+# struct libusb_config_descriptor **config);
+libusb_get_config_descriptor = libusb.libusb_get_config_descriptor
+libusb_get_config_descriptor.argtypes = [libusb_device_p, c_uint8,
+ libusb_config_descriptor_p_p]
+#int libusb_get_config_descriptor_by_value(libusb_device *dev,
+# uint8_t bConfigurationValue, struct libusb_config_descriptor **config);
+libusb_get_config_descriptor_by_value = \
+ libusb.libusb_get_config_descriptor_by_value
+libusb_get_config_descriptor_by_value.argtypes = [libusb_device_p, c_uint8,
+ libusb_config_descriptor_p_p]
+#void libusb_free_config_descriptor(struct libusb_config_descriptor *config);
+libusb_free_config_descriptor = libusb.libusb_free_config_descriptor
+libusb_free_config_descriptor.argtypes = [libusb_config_descriptor_p]
+libusb_free_config_descriptor.restype = None
+#uint8_t libusb_get_bus_number(libusb_device *dev);
+libusb_get_bus_number = libusb.libusb_get_bus_number
+libusb_get_bus_number.argtypes = [libusb_device_p]
+libusb_get_bus_number.restype = c_uint8
+#uint8_t libusb_get_device_address(libusb_device *dev);
+libusb_get_device_address = libusb.libusb_get_device_address
+libusb_get_device_address.argtypes = [libusb_device_p]
+libusb_get_device_address.restype = c_uint8
+#int libusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint);
+libusb_get_max_packet_size = libusb.libusb_get_max_packet_size
+libusb_get_max_packet_size.argtypes = [libusb_device_p, c_uchar]
+#int libusb_get_max_iso_packet_size(libusb_device *dev, unsigned char endpoint);
+libusb_get_max_iso_packet_size = libusb.libusb_get_max_iso_packet_size
+libusb_get_max_iso_packet_size.argtypes = [libusb_device_p, c_uchar]
+
+#int libusb_open(libusb_device *dev, libusb_device_handle **handle);
+libusb_open = libusb.libusb_open
+libusb_open.argtypes = [libusb_device_p, libusb_device_handle_p_p]
+#void libusb_close(libusb_device_handle *dev_handle);
+libusb_close = libusb.libusb_close
+libusb_close.argtypes = [libusb_device_handle_p]
+libusb_close.restype = None
+#libusb_device *libusb_get_device(libusb_device_handle *dev_handle);
+libusb_get_device = libusb.libusb_get_device
+libusb_get_device.argtypes = [libusb_device_handle_p]
+libusb_get_device.restype = libusb_device_p
+
+#int libusb_set_configuration(libusb_device_handle *dev, int configuration);
+libusb_set_configuration = libusb.libusb_set_configuration
+libusb_set_configuration.argtypes = [libusb_device_handle_p, c_int]
+#int libusb_claim_interface(libusb_device_handle *dev, int iface);
+libusb_claim_interface = libusb.libusb_claim_interface
+libusb_claim_interface.argtypes = [libusb_device_handle_p, c_int]
+#int libusb_release_interface(libusb_device_handle *dev, int iface);
+libusb_release_interface = libusb.libusb_release_interface
+libusb_release_interface.argtypes = [libusb_device_handle_p, c_int]
+
+#libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context *ctx,
+# uint16_t vendor_id, uint16_t product_id);
+libusb_open_device_with_vid_pid = libusb.libusb_open_device_with_vid_pid
+libusb_open_device_with_vid_pid.argtypes = [libusb_context_p, c_uint16,
+ c_uint16]
+libusb_open_device_with_vid_pid.restype = libusb_device_handle_p
+
+#int libusb_set_interface_alt_setting(libusb_device_handle *dev,
+# int interface_number, int alternate_setting);
+libusb_set_interface_alt_setting = libusb.libusb_set_interface_alt_setting
+libusb_set_interface_alt_setting.argtypes = [libusb_device_handle_p, c_int,
+ c_int]
+#int libusb_clear_halt(libusb_device_handle *dev, unsigned char endpoint);
+libusb_clear_halt = libusb.libusb_clear_halt
+libusb_clear_halt.argtypes = [libusb_device_handle_p, c_uchar]
+#int libusb_reset_device(libusb_device_handle *dev);
+libusb_reset_device = libusb.libusb_reset_device
+libusb_reset_device.argtypes = [libusb_device_handle_p]
+
+#int libusb_kernel_driver_active(libusb_device_handle *dev, int interface);
+libusb_kernel_driver_active = libusb.libusb_kernel_driver_active
+libusb_kernel_driver_active.argtypes = [libusb_device_handle_p, c_int]
+#int libusb_detach_kernel_driver(libusb_device_handle *dev, int interface);
+libusb_detach_kernel_driver = libusb.libusb_detach_kernel_driver
+libusb_detach_kernel_driver.argtypes = [libusb_device_handle_p, c_int]
+#int libusb_attach_kernel_driver(libusb_device_handle *dev, int interface);
+libusb_attach_kernel_driver = libusb.libusb_attach_kernel_driver
+libusb_attach_kernel_driver.argtypes = [libusb_device_handle_p, c_int]
+
+# Get the data section of a control transfer. This convenience function is here
+# to remind you that the data does not start until 8 bytes into the actual
+# buffer, as the setup packet comes first.
+#
+# Calling this function only makes sense from a transfer callback function,
+# or situations where you have already allocated a suitably sized buffer at
+# transfer->buffer.
+#
+# \param transfer a transfer
+# \returns pointer to the first byte of the data section
+
+def libusb_control_transfer_get_data(transfer_p):
+ transfer = transfer_p.contents
+ return string_at(transfer.buffer, transfer.length)[
+ LIBUSB_CONTROL_SETUP_SIZE:]
+
+def libusb_control_transfer_get_setup(transfer_p):
+ return cast(transfer_p.contents.buffer, libusb_control_setup_p)
+
+def libusb_fill_control_setup(setup_p, bmRequestType, bRequest, wValue, wIndex,
+ wLength):
+ 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)
+
+#struct libusb_transfer *libusb_alloc_transfer(int iso_packets);
+libusb_alloc_transfer = libusb.libusb_alloc_transfer
+libusb_alloc_transfer.argtypes = [c_int]
+libusb_alloc_transfer.restype = libusb_transfer_p
+#int libusb_submit_transfer(struct libusb_transfer *transfer);
+libusb_submit_transfer = libusb.libusb_submit_transfer
+libusb_submit_transfer.argtypes = [libusb_transfer_p]
+#int libusb_cancel_transfer(struct libusb_transfer *transfer);
+libusb_cancel_transfer = libusb.libusb_cancel_transfer
+libusb_cancel_transfer.argtypes = [libusb_transfer_p]
+#void libusb_free_transfer(struct libusb_transfer *transfer);
+libusb_free_transfer = libusb.libusb_free_transfer
+libusb_free_transfer.argtypes = [libusb_transfer_p]
+libusb_free_transfer.restype = None
+
+def libusb_fill_control_transfer(transfer_p, dev_handle, buffer, callback,
+ user_data, timeout):
+ transfer = transfer_p.contents
+ transfer.dev_handle = dev_handle
+ transfer.endpoint = 0
+ transfer.type = LIBUSB_TRANSFER_TYPE_CONTROL
+ transfer.timeout = timeout
+ transfer.buffer = cast(buffer, c_void_p)
+ if buffer is not None:
+ setup = cast(buffer, libusb_control_setup_p).contents
+ transfer.length = LIBUSB_CONTROL_SETUP_SIZE + \
+ libusb_le16_to_cpu(setup.wLength)
+ transfer.user_data = user_data
+ transfer.callback = callback
+
+def libusb_fill_bulk_transfer(transfer_p, dev_handle, endpoint, buffer, length,
+ callback, user_data, timeout):
+ transfer = transfer_p.contents
+ transfer.dev_handle = dev_handle
+ transfer.endpoint = endpoint
+ transfer.type = LIBUSB_TRANSFER_TYPE_BULK
+ transfer.timeout = timeout
+ transfer.buffer = cast(buffer, c_void_p)
+ transfer.length = length
+ transfer.user_data = user_data
+ transfer.callback = callback
+
+def libusb_fill_interrupt_transfer(transfer_p, dev_handle, endpoint, buffer,
+ length, callback, user_data, timeout):
+ transfer = transfer_p.contents
+ transfer.dev_handle = dev_handle
+ transfer.endpoint = endpoint
+ transfer.type = LIBUSB_TRANSFER_TYPE_INTERRUPT
+ transfer.timeout = timeout
+ transfer.buffer = cast(buffer, c_void_p)
+ transfer.length = length
+ transfer.user_data = user_data
+ transfer.callback = callback
+
+def libusb_fill_iso_transfer(transfer_p, dev_handle, endpoint, buffer, length,
+ num_iso_packets, callback, user_data, timeout):
+ transfer = transfer_p.contents
+ transfer.dev_handle = dev_handle
+ transfer.endpoint = endpoint
+ transfer.type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
+ transfer.timeout = timeout
+ transfer.buffer = cast(buffer, c_void_p)
+ transfer.length = length
+ transfer.num_iso_packets = num_iso_packets
+ transfer.user_data = user_data
+ transfer.callback = callback
+
+def _get_iso_packet_list(transfer):
+ list_type = libusb_iso_packet_descriptor * transfer.num_iso_packets
+ return list_type.from_address(addressof(transfer.iso_packet_desc))
+
+def get_iso_packet_list(transfer_p):
+ """
+ Python-specific helper extracting a list of iso packet descriptors,
+ because it's not as straight-forward as in C.
+ """
+ return _get_iso_packet_list(transfer_p.contents)
+
+def _get_iso_packet_buffer(transfer, offset, length):
+ return string_at(addressof(transfer.buffer) + offset, length)
+
+def get_iso_packet_buffer_list(transfer_p):
+ """
+ Python-specific helper extracting a list of iso packet buffers.
+ """
+ transfer = transfer_p.contents
+ offset = 0
+ result = []
+ append = result.append
+ for iso_transfer in _get_iso_packet_list(transfer):
+ length = iso_transfer.length
+ append(_get_iso_packet_buffer(transfer, offset, length))
+ offset += length
+ return result
+
+def get_extra(descriptor):
+ """
+ Python-specific helper to access "extra" field of descriptors,
+ because it's not as straight-forward as in C.
+ Returns a list, where each entry is an individual extra descriptor.
+ """
+ result = []
+ extra_length = descriptor.extra_length
+ if extra_length:
+ extra = string_at(descriptor.extra, extra_length)
+ append = result.append
+ while extra:
+ length = ord(extra[0])
+ if not (0 < length <= len(extra)):
+ raise ValueError('Extra descriptor %i is incomplete/invalid' % (
+ len(result), ))
+ append(extra[:length])
+ extra = extra[length:]
+ return result
+
+def libusb_set_iso_packet_lengths(transfer_p, length):
+ transfer = transfer_p.contents
+ for iso_packet_desc in _get_iso_packet_list(transfer):
+ iso_packet_desc.length = length
+
+def libusb_get_iso_packet_buffer(transfer_p, packet):
+ transfer = transfer_p.contents
+ offset = 0
+ if packet >= transfer.num_iso_packets:
+ return None
+ iso_packet_desc_list = _get_iso_packet_list(transfer)
+ for i in xrange(packet):
+ offset += iso_packet_desc_list[i].length
+ return _get_iso_packet_buffer(transfer, offset,
+ iso_packet_desc_list[packet].length)
+
+def libusb_get_iso_packet_buffer_simple(transfer_p, packet):
+ transfer = transfer_p.contents
+ if packet >= transfer.num_iso_packets:
+ return None
+ iso_length = transfer.iso_packet_desc.length
+ return _get_iso_packet_buffer(transfer, iso_length * packet, iso_length)
+
+# sync I/O
+
+#int libusb_control_transfer(libusb_device_handle *dev_handle,
+# uint8_t request_type, uint8_t request, uint16_t value, uint16_t index,
+# unsigned char *data, uint16_t length, unsigned int timeout);
+libusb_control_transfer = libusb.libusb_control_transfer
+libusb_control_transfer.argtypes = [libusb_device_handle_p, c_uint8, c_uint8,
+ c_uint16, c_uint16, c_void_p, c_uint16,
+ c_uint]
+
+#int libusb_bulk_transfer(libusb_device_handle *dev_handle,
+# unsigned char endpoint, unsigned char *data, int length,
+# int *actual_length, unsigned int timeout);
+libusb_bulk_transfer = libusb.libusb_bulk_transfer
+libusb_bulk_transfer.argtypes = [libusb_device_handle_p, c_uchar, c_void_p,
+ c_int, c_int_p, c_uint]
+
+#int libusb_interrupt_transfer(libusb_device_handle *dev_handle,
+# unsigned char endpoint, unsigned char *data, int length,
+# int *actual_length, unsigned int timeout);
+libusb_interrupt_transfer = libusb.libusb_interrupt_transfer
+libusb_interrupt_transfer.argtypes = [libusb_device_handle_p, c_uchar,
+ c_void_p, c_int, c_int_p, c_uint]
+
+def libusb_get_descriptor(dev, desc_type, desc_index, data, length):
+ return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR,
+ (desc_type << 8) | desc_index, 0, data,
+ length, 1000)
+
+def libusb_get_string_descriptor(dev, desc_index, langid, data, length):
+ return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR,
+ (LIBUSB_DT_STRING << 8) | desc_index,
+ langid, data, length, 1000)
+
+#int libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
+# uint8_t index, unsigned char *data, int length);
+libusb_get_string_descriptor_ascii = libusb.libusb_get_string_descriptor_ascii
+libusb_get_string_descriptor_ascii.argtypes = [libusb_device_handle_p,
+ c_uint8, c_void_p, c_int]
+
+# polling and timeouts
+
+#int libusb_try_lock_events(libusb_context *ctx);
+libusb_try_lock_events = libusb.libusb_try_lock_events
+libusb_try_lock_events.argtypes = [libusb_context_p]
+#void libusb_lock_events(libusb_context *ctx);
+libusb_lock_events = libusb.libusb_lock_events
+libusb_lock_events.argtypes = [libusb_context_p]
+#void libusb_unlock_events(libusb_context *ctx);
+libusb_unlock_events = libusb.libusb_unlock_events
+libusb_unlock_events.argtypes = [libusb_context_p]
+libusb_unlock_events.restype = None
+#int libusb_event_handling_ok(libusb_context *ctx);
+libusb_event_handling_ok = libusb.libusb_event_handling_ok
+libusb_event_handling_ok.argtypes = [libusb_context_p]
+#int libusb_event_handler_active(libusb_context *ctx);
+libusb_event_handler_active = libusb.libusb_event_handler_active
+libusb_event_handler_active.argtypes = [libusb_context_p]
+#void libusb_lock_event_waiters(libusb_context *ctx);
+libusb_lock_event_waiters = libusb.libusb_lock_event_waiters
+libusb_lock_event_waiters.argtypes = [libusb_context_p]
+libusb_lock_event_waiters.restype = None
+#void libusb_unlock_event_waiters(libusb_context *ctx);
+libusb_unlock_event_waiters = libusb.libusb_unlock_event_waiters
+libusb_unlock_event_waiters.argtypes = []
+libusb_unlock_event_waiters.restype = None
+#int libusb_wait_for_event(libusb_context *ctx, struct timeval *tv);
+libusb_wait_for_event = libusb.libusb_wait_for_event
+libusb_wait_for_event.argtypes = [libusb_context_p, timeval_p]
+
+#int libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv);
+libusb_handle_events_timeout = libusb.libusb_handle_events_timeout
+libusb_handle_events_timeout.argtypes = [libusb_context_p, timeval_p]
+#int libusb_handle_events(libusb_context *ctx);
+libusb_handle_events = libusb.libusb_handle_events
+libusb_handle_events.argtypes = [libusb_context_p]
+#int libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv);
+libusb_handle_events_locked = libusb.libusb_handle_events_locked
+libusb_handle_events_locked.argtypes = [libusb_context_p, timeval_p]
+#int libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv);
+libusb_get_next_timeout = libusb.libusb_get_next_timeout
+libusb_get_next_timeout.argtypes = [libusb_context_p, timeval_p]
+
+class libusb_pollfd(Structure):
+ _fields_ = [('fd', c_int),
+ ('events', c_short)]
+libusb_pollfd_p = POINTER(libusb_pollfd)
+libusb_pollfd_p_p = POINTER(libusb_pollfd_p)
+
+libusb_pollfd_added_cb_p = CFUNCTYPE(None, c_int, c_short, py_object)
+libusb_pollfd_removed_cb_p = CFUNCTYPE(None, c_int, py_object)
+
+#const struct libusb_pollfd **libusb_get_pollfds(libusb_context *ctx);
+libusb_get_pollfds = libusb.libusb_get_pollfds
+libusb_get_pollfds.argtypes = [libusb_context_p]
+libusb_get_pollfds.restype = libusb_pollfd_p_p
+#void libusb_set_pollfd_notifiers(libusb_context *ctx,
+# libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+# void *user_data);
+libusb_set_pollfd_notifiers = libusb.libusb_set_pollfd_notifiers
+libusb_set_pollfd_notifiers.argtypes = [libusb_context_p,
+ libusb_pollfd_added_cb_p,
+ libusb_pollfd_removed_cb_p, py_object]
+libusb_set_pollfd_notifiers.restype = None
+
+# /libusb.h
+
diff --git a/df10ch_setup_pkg/usb1.py b/df10ch_setup_pkg/usb1.py
new file mode 100644
index 0000000..bc0d8db
--- /dev/null
+++ b/df10ch_setup_pkg/usb1.py
@@ -0,0 +1,1507 @@
+"""
+Pythonic wrapper for libusb-1.0.
+
+This file has been extracted from the python-libusb1 project:
+ http://github.com/vpelletier/python-libusb1
+
+The first thing you must do is to get an "USB context". To do so, create a
+LibUSBContext instance.
+Then, you can use it to browse available USB devices and open the one you want
+to talk to.
+At this point, you should have a USBDeviceHandle instance (as returned by
+LibUSBContext or USBDevice instances), and you can start exchanging with the
+device.
+
+Features:
+- Basic device settings (configuration & interface selection, ...)
+- String descriptor lookups (ASCII & unicode), and list supported language
+ codes
+- Synchronous I/O (control, bulk, interrupt)
+- Asynchronous I/O (control, bulk, interrupt, isochronous)
+ Note: Isochronous support is experimental.
+ See USBPoller, USBTransfer and USBTransferHelper.
+"""
+
+import libusb1
+from ctypes import byref, create_string_buffer, c_int, sizeof, POINTER, \
+ create_unicode_buffer, c_wchar, cast, c_uint16, c_ubyte, string_at, \
+ addressof, c_void_p, cdll
+from cStringIO import StringIO
+import sys
+from ctypes.util import find_library
+
+__all__ = ['LibUSBContext', 'USBDeviceHandle', 'USBDevice',
+ 'USBPoller', 'USBTransfer', 'USBTransferHelper', 'EVENT_CALLBACK_SET']
+
+if sys.version_info[:2] >= (2, 6):
+ if sys.platform == 'win32':
+ from ctypes import get_last_error as get_errno
+ else:
+ from ctypes import get_errno
+else:
+ def get_errno():
+ raise NotImplementedError("Your python version doesn't support "
+ "errno/last_error")
+
+__libc_name = find_library('c')
+if __libc_name is None:
+ # Of course, will leak memory.
+ # Should we warn user ? How ?
+ _free = lambda x: None
+else:
+ _free = getattr(cdll, __libc_name).free
+del __libc_name
+
+# Default string length
+# From a comment in libusb-1.0: "Some devices choke on size > 255"
+STRING_LENGTH = 255
+
+EVENT_CALLBACK_SET = frozenset((
+ libusb1.LIBUSB_TRANSFER_COMPLETED,
+ libusb1.LIBUSB_TRANSFER_ERROR,
+ libusb1.LIBUSB_TRANSFER_TIMED_OUT,
+ libusb1.LIBUSB_TRANSFER_CANCELLED,
+ libusb1.LIBUSB_TRANSFER_STALL,
+ libusb1.LIBUSB_TRANSFER_NO_DEVICE,
+ libusb1.LIBUSB_TRANSFER_OVERFLOW,
+))
+
+DEFAULT_ASYNC_TRANSFER_ERROR_CALLBACK = lambda x: False
+
+def create_binary_buffer(string_or_len):
+ # Prevent ctypes from adding a trailing null char.
+ if isinstance(string_or_len, basestring):
+ result = create_string_buffer(string_or_len, len(string_or_len))
+ else:
+ result = create_string_buffer(string_or_len)
+ return result
+
+class USBTransfer(object):
+ """
+ USB asynchronous transfer control & data.
+
+ All modification methods will raise if called on a submitted transfer.
+ Methods noted as "should not be called on a submitted transfer" will not
+ prevent you from reading, but returned value is unspecified.
+ """
+ # Prevent garbage collector from freeing the free function before our
+ # instances, as we need it to property destruct them.
+ __libusb_free_transfer = libusb1.libusb_free_transfer
+ __libusb_cancel_transfer = libusb1.libusb_cancel_transfer
+ __USBError = libusb1.USBError
+ __LIBUSB_ERROR_NOT_FOUND = libusb1.LIBUSB_ERROR_NOT_FOUND
+ __transfer = None
+ __initialized = False
+ __submitted = False
+ __callback = None
+ __ctypesCallbackWrapper = None
+
+ def __init__(self, handle, iso_packets=0):
+ """
+ You should not instanciate this class directly.
+ Call "getTransfer" method on an USBDeviceHandle instance to get
+ instances of this class.
+ """
+ if iso_packets < 0:
+ raise ValueError('Cannot request a negative number of iso '
+ 'packets.')
+ self.__handle = handle
+ self.__num_iso_packets = iso_packets
+ result = libusb1.libusb_alloc_transfer(iso_packets)
+ if not result:
+ raise libusb1.USBError('Unable to get a transfer object')
+ self.__transfer = result
+ self.__ctypesCallbackWrapper = libusb1.libusb_transfer_cb_fn_p(
+ self.__callbackWrapper)
+
+ def close(self):
+ """
+ Stop using this transfer.
+ This removes some references to other python objects, to help garbage
+ collection.
+ Raises if called on a submitted transfer.
+ This does not prevent future reuse of instance (calling one of
+ "setControl", "setBulk", "setInterrupt" or "setIsochronous" methods
+ will initialize it properly again), just makes it ready to be
+ garbage-collected.
+ It is not mandatory to call it either, if you have no problems with
+ garbage collection.
+ """
+ if self.__submitted:
+ raise ValueError('Cannot close a submitted transfer')
+ self.__initialized = False
+ self.__callback = None
+
+ def __del__(self):
+ if self.__transfer is not None:
+ try:
+ # If this doesn't raise, we're doomed; transfer was submitted,
+ # still python decided to garbage-collect this instance.
+ # Stick to libusb's documentation, and don't free the
+ # transfer. If interpreter is shutting down, kernel will
+ # reclaim memory anyway.
+ # Note: we can't prevent transfer's buffer from being
+ # garbage-collected as soon as there will be no remaining
+ # reference to transfer, so a segfault might happen anyway.
+ # Should we warn user ? How ?
+ self.cancel()
+ except self.__USBError, exception:
+ if exception.value == self.__LIBUSB_ERROR_NOT_FOUND:
+ # Transfer was not submitted, we can free it.
+ self.__libusb_free_transfer(self.__transfer)
+ else:
+ raise
+
+ def __callbackWrapper(self, transfer_p):
+ """
+ Makes it possible for user-provided callback to alter transfer when
+ fired (ie, mark transfer as not submitted upon call).
+ """
+ self.__submitted = False
+ callback = self.__callback
+ if callback is not None:
+ callback(self)
+
+ def setCallback(self, callback):
+ """
+ Change transfer's callback.
+ """
+ if self.__submitted:
+ raise ValueError('Cannot alter a submitted transfer')
+ self.__callback = callback
+
+ def getCallback(self):
+ """
+ Get currently set callback.
+ """
+ return self.__callback
+
+ def setControl(self, request_type, request, value, index, buffer_or_len,
+ callback=None, user_data=None, timeout=0):
+ """
+ Setup transfer for control use.
+
+ request_type, request, value, index: See USBDeviceHandle.controlWrite.
+ buffer_or_len: either a string (when sending data), or expected data
+ length (when receiving data)
+ callback: function to call upon event. Called with transfer as
+ parameter, return value ignored.
+ user_data: to pass some data to/from callback
+ timeout: in milliseconds, how long to wait for devices acknowledgement
+ or data. Set to 0 to disable.
+ """
+ if self.__submitted:
+ raise ValueError('Cannot alter a submitted transfer')
+ if isinstance(buffer_or_len, basestring):
+ length = len(buffer_or_len)
+ string_buffer = create_binary_buffer(
+ ' ' * libusb1.LIBUSB_CONTROL_SETUP_SIZE + buffer_or_len)
+ else:
+ length = buffer_or_len
+ string_buffer = create_binary_buffer(length + \
+ libusb1.LIBUSB_CONTROL_SETUP_SIZE)
+ self.__initialized = False
+ libusb1.libusb_fill_control_setup(string_buffer, request_type,
+ request, value, index, length)
+ libusb1.libusb_fill_control_transfer(self.__transfer, self.__handle,
+ string_buffer, self.__ctypesCallbackWrapper, user_data, timeout)
+ self.__callback = callback
+ self.__initialized = True
+
+ def setBulk(self, endpoint, buffer_or_len, callback=None, user_data=None,
+ timeout=0):
+ """
+ Setup transfer for bulk use.
+
+ endpoint: endpoint to submit transfer to (implicitly sets transfer
+ direction).
+ buffer_or_len: either a string (when sending data), or expected data
+ length (when receiving data)
+ callback: function to call upon event. Called with transfer as
+ parameter, return value ignored.
+ user_data: to pass some data to/from callback
+ timeout: in milliseconds, how long to wait for devices acknowledgement
+ or data. Set to 0 to disable.
+ """
+ if self.__submitted:
+ raise ValueError('Cannot alter a submitted transfer')
+ string_buffer = create_binary_buffer(buffer_or_len)
+ self.__initialized = False
+ libusb1.libusb_fill_bulk_transfer(self.__transfer, self.__handle,
+ endpoint, string_buffer, sizeof(string_buffer),
+ self.__ctypesCallbackWrapper, user_data, timeout)
+ self.__callback = callback
+ self.__initialized = True
+
+ def setInterrupt(self, endpoint, buffer_or_len, callback=None,
+ user_data=None, timeout=0):
+ """
+ Setup transfer for interrupt use.
+
+ endpoint: endpoint to submit transfer to (implicitly sets transfer
+ direction).
+ buffer_or_len: either a string (when sending data), or expected data
+ length (when receiving data)
+ callback: function to call upon event. Called with transfer as
+ parameter, return value ignored.
+ user_data: to pass some data to/from callback
+ timeout: in milliseconds, how long to wait for devices acknowledgement
+ or data. Set to 0 to disable.
+ """
+ if self.__submitted:
+ raise ValueError('Cannot alter a submitted transfer')
+ string_buffer = create_binary_buffer(buffer_or_len)
+ self.__initialized = False
+ libusb1.libusb_fill_interrupt_transfer(self.__transfer, self.__handle,
+ endpoint, string_buffer, sizeof(string_buffer),
+ self.__ctypesCallbackWrapper, user_data, timeout)
+ self.__callback = callback
+ self.__initialized = True
+
+ def setIsochronous(self, endpoint, buffer_or_len, callback=None,
+ user_data=None, timeout=0, iso_transfer_length_list=None):
+ """
+ Setup transfer for isochronous use.
+
+ endpoint: endpoint to submit transfer to (implicitly sets transfer
+ direction).
+ buffer_or_len: either a string (when sending data), or expected data
+ length (when receiving data)
+ callback: function to call upon event. Called with transfer as
+ parameter, return value ignored.
+ user_data: to pass some data to/from callback
+ timeout: in milliseconds, how long to wait for devices acknowledgement
+ or data. Set to 0 to disable.
+ iso_transfer_length_list: list of individual transfer sizes. If not
+ provided, buffer_or_len's size will be divided evenly among the
+ number of ISO transfers given to receive current instance, rounded
+ down. Providing a list allows overriding this (both the number of
+ ISO transfers and their individual lengths).
+ """
+ if self.__submitted:
+ raise ValueError('Cannot alter a submitted transfer')
+ num_iso_packets = self.__num_iso_packets
+ if num_iso_packets == 0:
+ raise TypeError('This transfer canot be used for isochronous I/O. '
+ 'You must get another one with a non-zero iso_packets '
+ 'parameter.')
+ string_buffer = create_binary_buffer(buffer_or_len)
+ buffer_length = sizeof(string_buffer)
+ if iso_transfer_length_list is None:
+ iso_length = buffer_length // num_iso_packets
+ iso_transfer_length_list = [iso_length] * num_iso_packets
+ configured_iso_packets = len(iso_transfer_length_list)
+ if configured_iso_packets > num_iso_packets:
+ raise ValueError('Too many ISO transfer lengths (%i), there are '
+ 'only %i ISO transfers available' % (configured_iso_packets,
+ num_iso_packets))
+ if sum(iso_transfer_length_list) > buffer_length:
+ raise ValueError('ISO transfers too long (%i), there are only '
+ '%i bytes available' % (sum(iso_transfer_length_list),
+ buffer_length))
+ transfer_p = self.__transfer
+ max_iso_packet_size = self.__handle.getDevice().getMaxISOPacketSize(
+ endpoint)
+ self.__initialized = False
+ libusb1.libusb_fill_iso_transfer(transfer_p, self.__handle,
+ endpoint, string_buffer, buffer_length, configured_iso_packets,
+ self.__ctypesCallbackWrapper, user_data, timeout)
+ for length, iso_packet_desc in zip(iso_transfer_length_list,
+ libusb1.get_iso_packet_list(transfer_p)):
+ if length <= 0:
+ raise ValueError('Negative/null length transfers are not '
+ 'possible.')
+ if length > max_iso_packet_size:
+ raise ValueError('Packet too big (%i) for this endpoint: %i '
+ 'bytes max')
+ iso_packet_desc.length = length
+ self.__callback = callback
+ self.__initialized = True
+
+ def getType(self):
+ """
+ Get transfer type.
+ See libusb1.libusb_transfer_type.
+ """
+ return self.__transfer.contents.type
+
+ def getEndpoint(self):
+ """
+ Get endpoint.
+ """
+ return self.__transfer.contents.endpoint
+
+ def getStatus(self):
+ """
+ Get transfer status.
+ Should not be called on a submitted transfer.
+ """
+ return self.__transfer.contents.status
+
+ def getActualLength(self):
+ """
+ Get actually transfered data length.
+ Should not be called on a submitted transfer.
+ """
+ return self.__transfer.contents.actual_length
+
+ def getBuffer(self):
+ """
+ Get data buffer content.
+ Should not be called on a submitted transfer.
+ """
+ transfer_p = self.__transfer
+ transfer = transfer_p.contents
+ if transfer.type == libusb1.LIBUSB_TRANSFER_TYPE_CONTROL:
+ result = libusb1.libusb_control_transfer_get_data(transfer_p)
+ else:
+ result = string_at(transfer.buffer, transfer.length)
+ return result
+
+ def getISOBufferList(self):
+ """
+ Get individual ISO transfer's buffer.
+ Returns a list with one item per ISO transfer, with their
+ individually-configured sizes.
+ Should not be called on a submitted transfer.
+ """
+ transfer_p = self.__transfer
+ transfer = transfer_p.contents
+ if transfer.type != libusb1.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ raise TypeError('This method cannot be called on non-iso '
+ 'transfers.')
+ return libusb1.get_iso_packet_buffer_list(transfer_p)
+
+ def getISOSetupList(self):
+ """
+ Get individual ISO transfer's setup.
+ Returns a list of dicts, each containing an individual ISO transfer
+ parameters:
+ - length
+ - actual_length
+ - status
+ (see libusb1's API documentation for their signification)
+ Should not be called on a submitted transfer (except for 'length'
+ values).
+ """
+ transfer_p = self.__transfer
+ transfer = transfer_p.contents
+ if transfer.type != libusb1.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ raise TypeError('This method cannot be called on non-iso '
+ 'transfers.')
+ return [{
+ 'length': x.length,
+ 'actual_length': x.actual_length,
+ 'status': x.status,
+ } for x in libusb1.get_iso_packet_list(transfer_p)]
+
+ def setBuffer(self, buffer_or_len):
+ """
+ Replace buffer with a new one.
+ Allows resizing read buffer and replacing data sent.
+ Note: resizing is not allowed for isochronous buffer (use
+ setIsochronous).
+ Note: disallowed on control transfers (use setControl).
+ """
+ if self.__submitted:
+ raise ValueError('Cannot alter a submitted transfer')
+ transfer = self.__transfer.contents
+ if transfer.type == libusb1.LIBUSB_TRANSFER_TYPE_CONTROL:
+ raise ValueError('To alter control transfer buffer, use '
+ 'setControl')
+ buff = create_binary_buffer(buffer_or_len)
+ if transfer.type == libusb1.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS and \
+ sizeof(buff) != transfer.length:
+ raise ValueError('To alter isochronous transfer buffer length, '
+ 'use setIsochronous')
+ transfer.buffer = cast(buff, c_void_p)
+ transfer.length = sizeof(buff)
+
+ def isSubmitted(self):
+ """
+ Tells if this transfer is submitted and still pending.
+ """
+ return self.__submitted
+
+ def submit(self):
+ """
+ Submit transfer for asynchronous handling.
+ """
+ if self.__submitted:
+ raise ValueError('Cannot submit a submitted transfer')
+ if not self.__initialized:
+ raise ValueError('Cannot submit a transfer until it has been '
+ 'initialized')
+ self.__submitted = True
+ result = libusb1.libusb_submit_transfer(self.__transfer)
+ if result:
+ self.__submitted = False
+ raise libusb1.USBError(result)
+
+ def cancel(self):
+ """
+ Cancel transfer.
+ Note: cancellation happens asynchronously, so you must wait for
+ LIBUSB_TRANSFER_CANCELLED.
+ """
+ result = self.__libusb_cancel_transfer(self.__transfer)
+ if result:
+ raise self.__USBError(result)
+ self.__submitted = False
+
+class USBTransferHelper(object):
+ """
+ Simplifies subscribing to the same transfer over and over, and callback
+ handling:
+ - no need to read event status to execute apropriate code, just setup
+ different functions for each status code
+ - just return True instead of calling submit
+
+ Callbacks used in this class must follow the callback API described in
+ USBTransfer, and are expected to return a boolean:
+ - True if transfer is to be submitted again (to receive/send more data)
+ - False otherwise
+
+ Note: as per libusb1 specifications, isochronous transfer global state
+ might be LIBUSB_TRANSFER_COMPLETED although some individual packets might
+ have an error status. You can check individual packet status by calling
+ getISOSetupList on transfer object in your callback.
+ """
+ def __init__(self, transfer=None):
+ """
+ Create a transfer callback dispatcher.
+
+ transfer parameter is deprecated. If provided, it will be equivalent
+ to:
+ helper = USBTransferHelper()
+ transfer.setCallback(helper)
+ and also allows using deprecated methods on this class (otherwise,
+ they raise AttributeError).
+ """
+ if transfer is not None:
+ # Deprecated: to drop
+ self.__transfer = transfer
+ transfer.setCallback(self)
+ self.__event_callback_dict = {}
+ self.__errorCallback = DEFAULT_ASYNC_TRANSFER_ERROR_CALLBACK
+
+ def submit(self):
+ """
+ Submit the asynchronous read request.
+ Deprecated. Use submit on transfer.
+ """
+ # Deprecated: to drop
+ self.__transfer.submit()
+
+ def cancel(self):
+ """
+ Cancel a pending read request.
+ Deprecated. Use cancel on transfer.
+ """
+ # Deprecated: to drop
+ self.__transfer.cancel()
+
+ def setEventCallback(self, event, callback):
+ """
+ Set a function to call for a given event.
+ Possible event identifiers are listed in EVENT_CALLBACK_SET.
+ """
+ if event not in EVENT_CALLBACK_SET:
+ raise ValueError('Unknown event %r.' % (event, ))
+ self.__event_callback_dict[event] = callback
+
+ def setDefaultCallback(self, callback):
+ """
+ Set the function to call for event which don't have a specific callback
+ registered.
+ The initial default callback does nothing and returns False.
+ """
+ self.__errorCallback = callback
+
+ def getEventCallback(self, event, default=None):
+ """
+ Return the function registered to be called for given event identifier.
+ """
+ return self.__event_callback_dict.get(event, default)
+
+ def __call__(self, transfer):
+ """
+ Callback to set on transfers.
+ """
+ if self.getEventCallback(transfer.getStatus(), self.__errorCallback)(
+ transfer):
+ transfer.submit()
+
+ def isSubmited(self):
+ """
+ Returns whether this reader is currently waiting for an event.
+ Deprecatd. Use isSubmitted on transfer.
+ """
+ # Deprecated: to drop
+ return self.__transfer.isSubmitted()
+
+class USBPoller(object):
+ """
+ Class allowing integration of USB event polling in a file-descriptor
+ monitoring event loop.
+ """
+ def __init__(self, context, poller):
+ """
+ Create a poller for given context.
+ Warning: it will not check if another poller instance was already
+ present for that context, and will replace it.
+
+ poller is a polling instance implementing the following methods:
+ - register(fd, event_flags)
+ event_flags have the same meaning as in poll API (POLLIN & POLLOUT)
+ - unregister(fd)
+ - poll(timeout)
+ timeout being a float in seconds, or None if there is no timeout.
+ It must return a list of (descriptor, event) pairs.
+ Note: USBPoller is itself a valid poller.
+ """
+ self.__context = context
+ self.__poller = poller
+ self.__fd_set = set()
+ context.setPollFDNotifiers(self._registerFD, self._unregisterFD)
+ for fd, events in context.getPollFDList():
+ self._registerFD(fd, events)
+
+ def __del__(self):
+ self.__context.setPollFDNotifiers(None, None)
+
+ def poll(self, timeout=None):
+ """
+ Poll for events.
+ timeout can be a float in seconds, or None for no timeout.
+ Returns a list of (descriptor, event) pairs.
+ """
+ next_usb_timeout = self.__context.getNextTimeout()
+ if timeout is None:
+ usb_timeout = next_usb_timeout
+ elif next_usb_timeout:
+ usb_timeout = min(next_usb_timeout, timeout)
+ else:
+ usb_timeout = timeout
+ event_list = self.__poller.poll(usb_timeout)
+ if event_list:
+ fd_set = self.__fd_set
+ result = [(x, y) for x, y in event_list if x not in fd_set]
+ if len(result) != len(event_list):
+ self.__context.handleEventsTimeout()
+ else:
+ result = event_list
+ self.__context.handleEventsTimeout()
+ return result
+
+ def register(self, fd, events):
+ """
+ Register an USB-unrelated fd to poller.
+ Convenience method.
+ """
+ if fd in self.__fd_set:
+ raise ValueError('This fd is a special USB event fd, it cannot '
+ 'be polled.')
+ self.__poller.register(fd, events)
+
+ def unregister(self, fd):
+ """
+ Unregister an USB-unrelated fd from poller.
+ Convenience method.
+ """
+ if fd in self.__fd_set:
+ raise ValueError('This fd is a special USB event fd, it must '
+ 'stay registered.')
+ self.__poller.unregister(fd)
+
+ def _registerFD(self, fd, events, user_data=None):
+ self.register(fd, events)
+ self.__fd_set.add(fd)
+
+ def _unregisterFD(self, fd, user_data=None):
+ self.__fd_set.discard(fd)
+ self.unregister(fd)
+
+class USBDeviceHandle(object):
+ """
+ Represents an opened USB device.
+ """
+ __handle = None
+ __libusb_close = libusb1.libusb_close
+
+ def __init__(self, context, handle, device):
+ """
+ You should not instanciate this class directly.
+ Call "open" method on an USBDevice instance to get an USBDeviceHandle
+ instance.
+ """
+ # XXX Context parameter is just here as a hint for garbage collector:
+ # It must collect USBDeviceHandle instances before their LibUSBContext.
+ self.__context = context
+ self.__handle = handle
+ self.__device = device
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ """
+ Close this handle. If not called explicitely, will be called by
+ destructor.
+ """
+ handle = self.__handle
+ if handle is not None:
+ self.__libusb_close(handle)
+ self.__handle = None
+
+ def getDevice(self):
+ """
+ Get an USBDevice instance for the device accessed through this handle.
+ Useful for example to query its configurations.
+ """
+ return self.__device
+
+ def getConfiguration(self):
+ """
+ Get the current configuration number for this device.
+ """
+ configuration = c_int()
+ result = libusb1.libusb_get_configuration(self.__handle,
+ byref(configuration))
+ if result:
+ raise libusb1.USBError(result)
+ return configuration
+
+ def setConfiguration(self, configuration):
+ """
+ Set the configuration number for this device.
+ """
+ result = libusb1.libusb_set_configuration(self.__handle, configuration)
+ if result:
+ raise libusb1.USBError(result)
+
+ def claimInterface(self, interface):
+ """
+ Claim (= get exclusive access to) given interface number. Required to
+ receive/send data.
+ """
+ result = libusb1.libusb_claim_interface(self.__handle, interface)
+ if result:
+ raise libusb1.USBError(result)
+
+ def releaseInterface(self, interface):
+ """
+ Release interface, allowing another process to use it.
+ """
+ result = libusb1.libusb_release_interface(self.__handle, interface)
+ if result:
+ raise libusb1.USBError(result)
+
+ def setInterfaceAltSetting(self, interface, alt_setting):
+ """
+ Set interface's alternative setting (both parameters are integers).
+ """
+ result = libusb1.libusb_set_interface_alt_setting(self.__handle,
+ interface,
+ alt_setting)
+ if result:
+ raise libusb1.USBError(result)
+
+ def clearHalt(self, endpoint):
+ """
+ Clear a halt state on given endpoint number.
+ """
+ result = libusb1.libusb_clear_halt(self.__handle, endpoint)
+ if result:
+ raise libusb1.USBError(result)
+
+ def resetDevice(self):
+ """
+ Reinitialise current device.
+ Attempts to restore current configuration & alt settings.
+ If this fails, will result in a device diconnect & reconnect, so you
+ have to close current device and rediscover it (notified by a
+ LIBUSB_ERROR_NOT_FOUND error code).
+ """
+ result = libusb1.libusb_reset_device(self.__handle)
+ if result:
+ raise libusb1.USBError(result)
+
+ def kernelDriverActive(self, interface):
+ """
+ Tell whether a kernel driver is active on given interface number.
+ """
+ result = libusb1.libusb_kernel_driver_active(self.__handle, interface)
+ if result == 0:
+ is_active = False
+ elif result == 1:
+ is_active = True
+ else:
+ raise libusb1.USBError(result)
+ return is_active
+
+ def detachKernelDriver(self, interface):
+ """
+ Ask kernel driver to detach from given interface number.
+ """
+ result = libusb1.libusb_detach_kernel_driver(self.__handle, interface)
+ if result:
+ raise libusb1.USBError(result)
+
+ def attachKernelDriver(self, interface):
+ """
+ Ask kernel driver to re-attach to given interface number.
+ """
+ result = libusb1.libusb_attach_kernel_driver(self.__handle, interface)
+ if result:
+ raise libusb1.USBError(result)
+
+ def getSupportedLanguageList(self):
+ """
+ Return a list of USB language identifiers (as integers) supported by
+ current device for its string descriptors.
+ """
+ descriptor_string = create_binary_buffer(STRING_LENGTH)
+ result = libusb1.libusb_get_string_descriptor(self.__handle,
+ 0, 0, descriptor_string, sizeof(descriptor_string))
+ if result < 0:
+ if result == libusb1.LIBUSB_ERROR_PIPE:
+ # From libusb_control_transfer doc:
+ # control request not supported by the device
+ return []
+ raise libusb1.USBError(result)
+ length = cast(descriptor_string, POINTER(c_ubyte))[0]
+ langid_list = cast(descriptor_string, POINTER(c_uint16))
+ result = []
+ append = result.append
+ for offset in xrange(1, length / 2):
+ append(libusb1.libusb_le16_to_cpu(langid_list[offset]))
+ return result
+
+ def getStringDescriptor(self, descriptor, lang_id):
+ """
+ Fetch description string for given descriptor and in given language.
+ Use getSupportedLanguageList to know which languages are available.
+ Return value is an unicode string.
+ Return None if there is no such descriptor on device.
+ """
+ descriptor_string = create_unicode_buffer(
+ STRING_LENGTH / sizeof(c_wchar))
+ result = libusb1.libusb_get_string_descriptor(self.__handle,
+ descriptor, lang_id, descriptor_string, sizeof(descriptor_string))
+ if result == libusb1.LIBUSB_ERROR_NOT_FOUND:
+ return None
+ if result < 0:
+ raise libusb1.USBError(result)
+ return descriptor_string.value
+
+ def getASCIIStringDescriptor(self, descriptor):
+ """
+ Fetch description string for given descriptor in first available
+ language.
+ Return value is an ASCII string.
+ Return None if there is no such descriptor on device.
+ """
+ descriptor_string = create_binary_buffer(STRING_LENGTH)
+ result = libusb1.libusb_get_string_descriptor_ascii(self.__handle,
+ descriptor, descriptor_string, sizeof(descriptor_string))
+ if result == libusb1.LIBUSB_ERROR_NOT_FOUND:
+ return None
+ if result < 0:
+ raise libusb1.USBError(result)
+ return descriptor_string.value
+
+ # Sync I/O
+
+ def _controlTransfer(self, request_type, request, value, index, data,
+ length, timeout):
+ result = libusb1.libusb_control_transfer(self.__handle, request_type,
+ request, value, index, data, length, timeout)
+ if result < 0:
+ raise libusb1.USBError(result)
+ return result
+
+ def controlWrite(self, request_type, request, value, index, data,
+ timeout=0):
+ """
+ Synchronous control write.
+ request_type: request type bitmask (bmRequestType), see libusb1
+ constants LIBUSB_TYPE_* and LIBUSB_RECIPIENT_*.
+ request: request id (some values are standard).
+ value, index, data: meaning is request-dependent.
+ timeout: in milliseconds, how long to wait for device acknowledgement.
+ Set to 0 to disable.
+
+ Returns the number of bytes actually sent.
+ """
+ request_type = (request_type & ~libusb1.USB_ENDPOINT_DIR_MASK) | \
+ libusb1.LIBUSB_ENDPOINT_OUT
+ data = create_binary_buffer(data)
+ return self._controlTransfer(request_type, request, value, index, data,
+ sizeof(data), timeout)
+
+ def controlRead(self, request_type, request, value, index, length,
+ timeout=0):
+ """
+ Synchronous control read.
+ timeout: in milliseconds, how long to wait for data. Set to 0 to
+ disable.
+ See controlWrite for other parameters description.
+
+ Returns received data.
+ """
+ request_type = (request_type & ~libusb1.USB_ENDPOINT_DIR_MASK) | \
+ libusb1.LIBUSB_ENDPOINT_IN
+ data = create_binary_buffer(length)
+ transferred = self._controlTransfer(request_type, request, value,
+ index, data, length, timeout)
+ return data.raw[:transferred]
+
+ def _bulkTransfer(self, endpoint, data, length, timeout):
+ transferred = c_int()
+ result = libusb1.libusb_bulk_transfer(self.__handle, endpoint,
+ data, length, byref(transferred), timeout)
+ if result:
+ raise libusb1.USBError(result)
+ return transferred.value
+
+ def bulkWrite(self, endpoint, data, timeout=0):
+ """
+ Synchronous bulk write.
+ endpoint: endpoint to send data to.
+ data: data to send.
+ timeout: in milliseconds, how long to wait for device acknowledgement.
+ Set to 0 to disable.
+
+ Returns the number of bytes actually sent.
+ """
+ endpoint = (endpoint & ~libusb1.USB_ENDPOINT_DIR_MASK) | \
+ libusb1.LIBUSB_ENDPOINT_OUT
+ data = create_binary_buffer(data)
+ return self._bulkTransfer(endpoint, data, sizeof(data), timeout)
+
+ def bulkRead(self, endpoint, length, timeout=0):
+ """
+ Synchronous bulk read.
+ timeout: in milliseconds, how long to wait for data. Set to 0 to
+ disable.
+ See bulkWrite for other parameters description.
+
+ Returns received data.
+ """
+ endpoint = (endpoint & ~libusb1.USB_ENDPOINT_DIR_MASK) | \
+ libusb1.LIBUSB_ENDPOINT_IN
+ data = create_binary_buffer(length)
+ transferred = self._bulkTransfer(endpoint, data, length, timeout)
+ return data.raw[:transferred]
+
+ def _interruptTransfer(self, endpoint, data, length, timeout):
+ transferred = c_int()
+ result = libusb1.libusb_interrupt_transfer(self.__handle, endpoint,
+ data, length, byref(transferred), timeout)
+ if result:
+ raise libusb1.USBError(result)
+ return transferred.value
+
+ def interruptWrite(self, endpoint, data, timeout=0):
+ """
+ Synchronous interrupt write.
+ endpoint: endpoint to send data to.
+ data: data to send.
+ timeout: in milliseconds, how long to wait for device acknowledgement.
+ Set to 0 to disable.
+
+ Returns the number of bytes actually sent.
+ """
+ endpoint = (endpoint & ~libusb1.USB_ENDPOINT_DIR_MASK) | \
+ libusb1.LIBUSB_ENDPOINT_OUT
+ data = create_binary_buffer(data)
+ return self._interruptTransfer(endpoint, data, sizeof(data), timeout)
+
+ def interruptRead(self, endpoint, length, timeout=0):
+ """
+ Synchronous interrupt write.
+ timeout: in milliseconds, how long to wait for data. Set to 0 to
+ disable.
+ See interruptRead for other parameters description.
+
+ Returns received data.
+ """
+ endpoint = (endpoint & ~libusb1.USB_ENDPOINT_DIR_MASK) | \
+ libusb1.LIBUSB_ENDPOINT_IN
+ data = create_binary_buffer(length)
+ transferred = self._interruptTransfer(endpoint, data, length, timeout)
+ return data.raw[:transferred]
+
+ def getTransfer(self, iso_packets=0):
+ """
+ Get an empty transfer for asynchronous use.
+ iso_packets: the number of isochronous transfer descriptors to
+ allocate.
+ """
+ return USBTransfer(self.__handle, iso_packets)
+
+class USBConfiguration(object):
+ def __init__(self, config):
+ if not isinstance(config, libusb1.libusb_config_descriptor):
+ raise TypeError('Unexpected descriptor type.')
+ self.__config = config
+
+ def getNumInterfaces(self):
+ return self.__config.bNumInterfaces
+
+ def getConfigurationValue(self):
+ return self.__config.bConfigurationValue
+
+ def getDescriptor(self):
+ return self.__config.iConfiguration
+
+ def getAttributes(self):
+ return self.__config.bmAttributes
+
+ def getMaxPower(self):
+ return self.__config.MaxPower * 2
+
+ def getExtra(self):
+ return libusb1.get_extra(self.__config)
+
+ def iterInterfaces(self):
+ interface_list = self.__config.interface
+ for interface_num in xrange(self.getNumInterfaces()):
+ yield USBInterface(interface_list[interface_num])
+
+ def __getitem__(self, interface):
+ if not isinstance(interface, int):
+ raise TypeError('interface parameter must be an integer')
+ if not (0 <= interface < self.getNumInterfaces()):
+ raise IndexError('No such interface: %r' % (interface, ))
+ return USBInterface(self.__config.interface[interface])
+
+class USBInterface(object):
+ def __init__(self, interface):
+ if not isinstance(interface, libusb1.libusb_interface):
+ raise TypeError('Unexpected descriptor type.')
+ self.__interface = interface
+
+ def getNumSettings(self):
+ return self.__interface.num_altsetting
+
+ def iterSettings(self):
+ alt_setting_list = self.__interface.altsetting
+ for alt_setting_num in xrange(self.getNumSettings()):
+ yield USBInterfaceSetting(alt_setting_list[alt_setting_num])
+
+ def __getitem__(self, alt_setting):
+ if not isinstance(alt_setting, int):
+ raise TypeError('alt_setting parameter must be an integer')
+ if not (0 <= alt_setting < self.getNumSettings()):
+ raise IndexError('No such setting: %r' % (alt_setting, ))
+ return USBInterfaceSetting(self.__interface.altsetting[alt_setting])
+
+class USBInterfaceSetting(object):
+ def __init__(self, alt_setting):
+ if not isinstance(alt_setting, libusb1.libusb_interface_descriptor):
+ raise TypeError('Unexpected descriptor type.')
+ self.__alt_setting = alt_setting
+
+ def getNumber(self):
+ return self.__alt_setting.bInterfaceNumber
+
+ def getAlternateSetting(self):
+ return self.__alt_setting.bAlternateSetting
+
+ def getNumEndpoints(self):
+ return self.__alt_setting.bNumEndpoints
+
+ def getClass(self):
+ return self.__alt_setting.bInterfaceClass
+
+ def getSubClass(self):
+ return self.__alt_setting.bInterfaceSubClass
+
+ def getClassTupple(self):
+ """
+ For convenience: class and subclass are probably often matched
+ simultaneously.
+ """
+ alt_setting = self.__alt_setting
+ return (alt_setting.bInterfaceClass, alt_setting.bInterfaceSubClass)
+
+ def getProtocol(self):
+ return self.__alt_setting.bInterfaceProtocol
+
+ def getDescriptor(self):
+ return self.__alt_setting.iInterface
+
+ def getExtra(self):
+ return libusb1.get_extra(self.__alt_setting)
+
+ def iterEndpoints(self):
+ endpoint_list = self.__alt_setting.endpoint
+ for endpoint_num in xrange(self.getNumEndpoints()):
+ yield USBEndPoint(endpoint_list[endpoint_num])
+
+ def __getitem__(self, endpoint):
+ if not isinstance(endpoint, int):
+ raise TypeError('endpoint parameter must be an integer')
+ if not (0 <= endpoint < self.getNumEndpoints()):
+ raise ValueError('No such endpoint: %r' % (endpoint, ))
+ return USBEndPoint(self.__alt_setting.endpoint[endpoint])
+
+class USBEndPoint(object):
+ def __init__(self, endpoint):
+ if not isinstance(endpoint, libusb1.libusb_endpoint_descriptor):
+ raise TypeError('Unexpected descriptor type.')
+ self.__endpoint = endpoint
+
+ def getAddress(self):
+ return self.__endpoint.bEndpointAddress
+
+ def getAttributes(self):
+ return self.__endpoint.bmAttributes
+
+ def getMaxPacketSize(self):
+ return self.__endpoint.wMaxPacketSize
+
+ def getInterval(self):
+ return self.__endpoint.bInterval
+
+ def getRefresh(self):
+ return self.__endpoint.bRefresh
+
+ def getSyncAddress(self):
+ return self.__endpoint.bSynchAddress
+
+ def getExtra(self):
+ return libusb1.get_extra(self.__endpoint)
+
+class USBDevice(object):
+ """
+ Represents a USB device.
+ """
+
+ __configuration_descriptor_list = None
+ __libusb_unref_device = libusb1.libusb_unref_device
+ __libusb_free_config_descriptor = libusb1.libusb_free_config_descriptor
+ __byref = byref
+
+ def __init__(self, context, device_p):
+ """
+ You should not instanciate this class directly.
+ Call LibUSBContext methods to receive instances of this class.
+ """
+ # Important: device_p refcount must be incremented before being given
+ # to this constructor. This class will decrement refcount upon
+ # destruction.
+ self.__context = context
+ self.device_p = device_p
+ # Fetch device descriptor
+ device_descriptor = libusb1.libusb_device_descriptor()
+ result = libusb1.libusb_get_device_descriptor(device_p,
+ byref(device_descriptor))
+ if result:
+ raise libusb1.USBError(result)
+ self.device_descriptor = device_descriptor
+ # Fetch all configuration descriptors
+ self.__configuration_descriptor_list = []
+ append = self.__configuration_descriptor_list.append
+ for configuration_id in xrange(device_descriptor.bNumConfigurations):
+ config = libusb1.libusb_config_descriptor_p()
+ result = libusb1.libusb_get_config_descriptor(device_p,
+ configuration_id, byref(config))
+ if result == libusb1.LIBUSB_ERROR_NOT_FOUND:
+ # Some devices (ex windows' root hubs) tell they have one
+ # configuration, but they have no configuration descriptor.
+ continue
+ if result:
+ raise libusb1.USBError(result)
+ append(config.contents)
+
+ def __del__(self):
+ self.__libusb_unref_device(self.device_p)
+ if self.__configuration_descriptor_list is not None:
+ byref = self.__byref
+ for config in self.__configuration_descriptor_list:
+ self.__libusb_free_config_descriptor(byref(config))
+
+ def __str__(self):
+ return 'Bus %03i Device %03i: ID %04x:%04x' % (
+ self.getBusNumber(),
+ self.getDeviceAddress(),
+ self.getVendorID(),
+ self.getProductID(),
+ )
+
+ def reprConfigurations(self):
+ """
+ Get a string representation of device's configurations.
+ Note: opens the device temporarily.
+
+ Deprecated. This is useless. It doesn't even showcases API usage, as
+ it accesses privape properties.
+ """
+ out = StringIO()
+ for config in self.__configuration_descriptor_list:
+ print >> out, 'Configuration %i: %s' % (config.bConfigurationValue,
+ self._getASCIIStringDescriptor(config.iConfiguration))
+ print >> out, ' Max Power: %i mA' % (config.MaxPower * 2, )
+ # TODO: bmAttributes dump
+ for interface_num in xrange(config.bNumInterfaces):
+ interface = config.interface[interface_num]
+ print >> out, ' Interface %i' % (interface_num, )
+ for alt_setting_num in xrange(interface.num_altsetting):
+ altsetting = interface.altsetting[alt_setting_num]
+ print >> out, ' Alt Setting %i: %s' % (alt_setting_num,
+ self._getASCIIStringDescriptor(altsetting.iInterface))
+ print >> out, ' Class: %02x Subclass: %02x' % \
+ (altsetting.bInterfaceClass,
+ altsetting.bInterfaceSubClass)
+ print >> out, ' Protocol: %02x' % \
+ (altsetting.bInterfaceProtocol, )
+ for endpoint_num in xrange(altsetting.bNumEndpoints):
+ endpoint = altsetting.endpoint[endpoint_num]
+ print >> out, ' Endpoint %i' % (endpoint_num, )
+ print >> out, ' Address: %02x' % \
+ (endpoint.bEndpointAddress, )
+ attribute_list = []
+ transfer_type = endpoint.bmAttributes & \
+ libusb1.LIBUSB_TRANSFER_TYPE_MASK
+ attribute_list.append(libusb1.libusb_transfer_type(
+ transfer_type
+ ))
+ if transfer_type == \
+ libusb1.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ attribute_list.append(libusb1.libusb_iso_sync_type(
+ (endpoint.bmAttributes & \
+ libusb1.LIBUSB_ISO_SYNC_TYPE_MASK) >> 2
+ ))
+ attribute_list.append(libusb1.libusb_iso_usage_type(
+ (endpoint.bmAttributes & \
+ libusb1.LIBUSB_ISO_USAGE_TYPE_MASK) >> 4
+ ))
+ print >> out, ' Attributes: %s' % \
+ (', '.join(attribute_list), )
+ print >> out, ' Max Packet Size: %i' % \
+ (endpoint.wMaxPacketSize, )
+ print >> out, ' Interval: %i' % \
+ (endpoint.bInterval, )
+ print >> out, ' Refresh: %i' % \
+ (endpoint.bRefresh, )
+ print >> out, ' Sync Address: %02x' % \
+ (endpoint.bSynchAddress, )
+ return out.getvalue()
+
+ def iterConfiguations(self):
+ for config in self.__configuration_descriptor_list:
+ yield USBConfiguration(config)
+
+ def iterSettings(self):
+ for config in self.__configuration_descriptor_list:
+ for interface in USBConfiguration(config).iterInterfaces():
+ for setting in interface.iterSettings():
+ yield setting
+
+ def getBusNumber(self):
+ """
+ Get device's bus number.
+ """
+ return libusb1.libusb_get_bus_number(self.device_p)
+
+ def getDeviceAddress(self):
+ """
+ Get device's address on its bus.
+ """
+ return libusb1.libusb_get_device_address(self.device_p)
+
+ def getbcdUSB(self):
+ """
+ Get the USB spec version device complies to, in BCD format.
+ """
+ return self.device_descriptor.bcdUSB
+
+ def getDeviceClass(self):
+ """
+ Get device's class id.
+ """
+ return self.device_descriptor.bDeviceClass
+
+ def getDeviceSubClass(self):
+ """
+ Get device's subclass id.
+ """
+ return self.device_descriptor.bDeviceSubClass
+
+ def getDeviceProtocol(self):
+ """
+ Get device's protocol id.
+ """
+ return self.device_descriptor.bDeviceProtocol
+
+ def getMaxPacketSize0(self):
+ """
+ Get device's max packet size for endpoint 0 (control).
+ """
+ return self.device_descriptor.bMaxPacketSize0
+
+ def getMaxISOPacketSize(self, endpoint):
+ """
+ Get the maximum size for a single isochronous packet for given
+ endpoint.
+ """
+ result = libusb1.libusb_get_max_iso_packet_size(self.device_p, endpoint)
+ if result < 0:
+ raise libusb1.USBError(result)
+ return result
+
+ def getVendorID(self):
+ """
+ Get device's vendor id.
+ """
+ return self.device_descriptor.idVendor
+
+ def getProductID(self):
+ """
+ Get device's product id.
+ """
+ return self.device_descriptor.idProduct
+
+ def getbcdDevice(self):
+ """
+ Get device's release number.
+ """
+ return self.device_descriptor.bcdDevice
+
+ def getSupportedLanguageList(self):
+ """
+ Get the list of language ids device has string descriptors for.
+ """
+ temp_handle = self.open()
+ return temp_handle.getSupportedLanguageList()
+
+ def _getStringDescriptor(self, descriptor, lang_id):
+ if descriptor == 0:
+ result = None
+ else:
+ temp_handle = self.open()
+ result = temp_handle.getStringDescriptor(descriptor, lang_id)
+ return result
+
+ def _getASCIIStringDescriptor(self, descriptor):
+ if descriptor == 0:
+ result = None
+ else:
+ temp_handle = self.open()
+ result = temp_handle.getASCIIStringDescriptor(descriptor)
+ return result
+
+ def getManufacturer(self):
+ """
+ Get device's manufaturer name.
+ Note: opens the device temporarily.
+ """
+ return self._getASCIIStringDescriptor(
+ self.device_descriptor.iManufacturer)
+
+ def getProduct(self):
+ """
+ Get device's product name.
+ Note: opens the device temporarily.
+ """
+ return self._getASCIIStringDescriptor(self.device_descriptor.iProduct)
+
+ def getSerialNumber(self):
+ """
+ Get device's serial number.
+ Note: opens the device temporarily.
+ """
+ return self._getASCIIStringDescriptor(
+ self.device_descriptor.iSerialNumber)
+
+ def getNumConfigurations(self):
+ """
+ Get device's number of possible configurations.
+ """
+ return self.device_descriptor.bNumConfigurations
+
+ def open(self):
+ """
+ Open device.
+ Returns an USBDeviceHandle instance.
+ """
+ handle = libusb1.libusb_device_handle_p()
+ result = libusb1.libusb_open(self.device_p, byref(handle))
+ if result:
+ raise libusb1.USBError(result)
+ return USBDeviceHandle(self.__context, handle, self)
+
+class LibUSBContext(object):
+ """
+ libusb1 USB context.
+
+ Provides methods to enumerate & look up USB devices.
+ Also provides access to global (device-independent) libusb1 functions.
+ """
+ __libusb_exit = libusb1.libusb_exit
+ __context_p = None
+ __added_cb = None
+ __removed_cb = None
+ __libusb_set_pollfd_notifiers = libusb1.libusb_set_pollfd_notifiers
+
+ def __init__(self):
+ """
+ Create a new USB context.
+ """
+ context_p = libusb1.libusb_context_p()
+ result = libusb1.libusb_init(byref(context_p))
+ if result:
+ raise libusb1.USBError(result)
+ self.__context_p = context_p
+
+ def __del__(self):
+ self.exit()
+
+ def exit(self):
+ """
+ Close (destroy) this USB context.
+ """
+ context_p = self.__context_p
+ if context_p is not None:
+ self.__libusb_exit(context_p)
+ self.__context_p = None
+ self.__added_cb = None
+ self.__removed_cb = None
+
+ def getDeviceList(self):
+ """
+ Return a list of all USB devices currently plugged in, as USBDevice
+ instances.
+ """
+ device_p_p = libusb1.libusb_device_p_p()
+ libusb_device_p = libusb1.libusb_device_p
+ device_list_len = libusb1.libusb_get_device_list(self.__context_p,
+ byref(device_p_p))
+ # Instanciate our own libusb_device_p object so we can free
+ # libusb-provided device list. Is this a bug in ctypes that it doesn't
+ # copy pointer value (=pointed memory address) ? At least, it's not so
+ # convenient and forces using such weird code.
+ result = [USBDevice(self, libusb_device_p(x.contents))
+ for x in device_p_p[:device_list_len]]
+ libusb1.libusb_free_device_list(device_p_p, 0)
+ return result
+
+ def openByVendorIDAndProductID(self, vendor_id, product_id):
+ """
+ Get the first USB device matching given vendor and product ids.
+ Returns an USBDeviceHandle instance, or None if no present device
+ match.
+ """
+ for device in self.getDeviceList():
+ if device.getVendorID() == vendor_id and \
+ device.getProductID() == product_id:
+ result = device.open()
+ break
+ else:
+ result = None
+ return result
+
+ def getPollFDList(self):
+ """
+ Return file descriptors to be used to poll USB events.
+ You should not have to call this method, unless you are integrating
+ this class with a polling mechanism.
+ """
+ pollfd_p_p = libusb1.libusb_get_pollfds(self.__context_p)
+ if not pollfd_p_p:
+ errno = get_errno()
+ if errno:
+ raise OSError(errno)
+ else:
+ # Assume not implemented
+ raise NotImplementedError("Your libusb doesn't seem to "
+ "implement pollable FDs")
+ try:
+ result = []
+ append = result.append
+ fd_index = 0
+ while pollfd_p_p[fd_index]:
+ append((pollfd_p_p[fd_index].contents.fd,
+ pollfd_p_p[fd_index].contents.events))
+ fd_index += 1
+ finally:
+ _free(pollfd_p_p)
+ return result
+
+ def handleEvents(self):
+ """
+ Handle any pending event (blocking).
+ See libusb1 documentation for details (there is a timeout, so it's
+ not "really" blocking).
+ """
+ result = libusb1.libusb_handle_events(self.__context_p)
+ if result:
+ raise libusb1.USBError(result)
+
+ def handleEventsTimeout(self, tv=0):
+ """
+ Handle any pending event.
+ If tv is 0, will return immediately after handling already-pending
+ events.
+ Othewire, defines the maximum amount of time to wait for events, in
+ seconds.
+ """
+ if tv is None:
+ tv = 0
+ tv_s = int(tv)
+ tv = libusb1.timeval(tv_s, int((tv - tv_s) * 1000000))
+ result = libusb1.libusb_handle_events_timeout(self.__context_p,
+ byref(tv))
+ if result:
+ raise libusb1.USBError(result)
+
+ def setPollFDNotifiers(self, added_cb=None, removed_cb=None,
+ user_data=None):
+ """
+ Give libusb1 methods to call when it should add/remove file descriptor
+ for polling.
+ You should not have to call this method, unless you are integrating
+ this class with a polling mechanism.
+ """
+ if added_cb is None:
+ added_cb = POINTER(None)
+ else:
+ added_cb = libusb1.libusb_pollfd_added_cb_p(added_cb)
+ if removed_cb is None:
+ removed_cb = POINTER(None)
+ else:
+ removed_cb = libusb1.libusb_pollfd_removed_cb_p(removed_cb)
+ self.__added_cb = added_cb
+ self.__removed_cb = removed_cb
+ self.__libusb_set_pollfd_notifiers(self.__context_p, added_cb,
+ removed_cb, user_data)
+
+ def getNextTimeout(self):
+ """
+ Returns the next internal timeout that libusb needs to handle, in
+ seconds, or None if no timeout is needed.
+ You should not have to call this method, unless you are integrating
+ this class with a polling mechanism.
+ """
+ timeval = libusb1.timeval()
+ result = libusb1.libusb_get_next_timeout(self.__context_p,
+ byref(timeval))
+ if result == 0:
+ result = None
+ elif result == 1:
+ result = timeval.tv_sec + (timeval.tv_usec * 0.000001)
+ else:
+ raise libusb1.USBError(result)
+ return result
+
+ def setDebug(self, level):
+ """
+ Set debugging level.
+ Note: depending on libusb compilation settings, this might have no
+ effect.
+ """
+ libusb1.libusb_set_debug(self.__context_p, level)
+
diff --git a/project/df10ch_test/df10ch_test.sln b/project/df10ch_test/df10ch_test.sln
new file mode 100644
index 0000000..c2ad18a
--- /dev/null
+++ b/project/df10ch_test/df10ch_test.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "df10ch_test", "df10ch_test.vcxproj", "{A3FE763B-2505-450E-9F94-EDA674894EF8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A3FE763B-2505-450E-9F94-EDA674894EF8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A3FE763B-2505-450E-9F94-EDA674894EF8}.Debug|Win32.Build.0 = Debug|Win32
+ {A3FE763B-2505-450E-9F94-EDA674894EF8}.Release|Win32.ActiveCfg = Release|Win32
+ {A3FE763B-2505-450E-9F94-EDA674894EF8}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/project/df10ch_test/df10ch_test.vcxproj b/project/df10ch_test/df10ch_test.vcxproj
new file mode 100644
index 0000000..d0a7d41
--- /dev/null
+++ b/project/df10ch_test/df10ch_test.vcxproj
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{A3FE763B-2505-450E-9F94-EDA674894EF8}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>df10ch_test</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\libusb\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>..\..\..\libusb\Win32\Release\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libusb-1.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\..\libusb\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalLibraryDirectories>..\..\..\libusb\Win32\Release\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libusb-1.0.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\test_appl\df10ch_test.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\df10ch_usb_proto.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/project/df10ch_test/df10ch_test.vcxproj.filters b/project/df10ch_test/df10ch_test.vcxproj.filters
new file mode 100644
index 0000000..94eea01
--- /dev/null
+++ b/project/df10ch_test/df10ch_test.vcxproj.filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\test_appl\df10ch_test.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\df10ch_usb_proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/setup.py b/setup.py
index efb2c48..00c0c58 100644
--- a/setup.py
+++ b/setup.py
@@ -23,12 +23,12 @@
from distutils.core import setup
setup(name='df10ch_setup',
- version='3',
+ version='4',
description='DF10CH Setup program',
author='Andreas Auras',
- author_email='yak54@gmx.net',
+ author_email='yak54@inkennet.de',
url='http://www.vdr-wiki.de/wiki/index.php/VDR_Wiki:DF10CH_Atmolight_Kontroller',
- requires=[ 'usb', 'TKinter', 'Image', 'ImageTk', 'ImageDraw' ],
+ requires=[ 'TKinter', 'Image', 'ImageTk', 'ImageDraw' ],
scripts=[ 'df10ch_setup.py' ],
packages = [ 'df10ch_setup_pkg' ],
)
diff --git a/test_appl/df10ch_test.c b/test_appl/df10ch_test.c
index 2d69a5b..ee879a0 100644
--- a/test_appl/df10ch_test.c
+++ b/test_appl/df10ch_test.c
@@ -23,12 +23,21 @@
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
-#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <sys/time.h>
#include <libusb.h>
+#ifdef WIN32
+#include <windows.h>
+#define snprintf _snprintf
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#ifndef LIBUSB_CALL
+#define LIBUSB_CALL
+#endif
+#endif
+
#include "../df10ch_usb_proto.h"
#define DF10CH_USB_CFG_VENDOR_ID 0x16c0
@@ -63,8 +72,8 @@ struct df10ch_output_driver_s {
int transfer_err_cnt; // Number of transfer errors
};
-
-static const char *df10ch_usb_errmsg(int rc) {
+#ifndef WIN32
+static const char *libusb_strerror(int rc) {
switch (rc) {
case LIBUSB_SUCCESS:
return ("Success (no error)");
@@ -97,7 +106,7 @@ static const char *df10ch_usb_errmsg(int rc) {
}
return ("?");
}
-
+#endif
static const char * df10ch_usb_transfer_errmsg(int s) {
switch (s) {
@@ -146,10 +155,12 @@ static void df10ch_comm_errmsg(int stat, char *rc) {
static int df10ch_control_in_transfer(df10ch_ctrl_t *ctrl, uint8_t req, uint16_t val, uint16_t index, unsigned int timeout, uint8_t *buf, uint16_t buflen)
{
- // Use a return buffer always so that the controller is able to send a USB reply status
- // This is special for VUSB at controller side
+ int n = 0, retrys = 0;
unsigned char rcbuf[1];
int len = buflen;
+
+ // Use a return buffer always so that the controller is able to send a USB reply status
+ // This is special for VUSB at controller side
if (!len)
{
buf = rcbuf;
@@ -157,7 +168,6 @@ static int df10ch_control_in_transfer(df10ch_ctrl_t *ctrl, uint8_t req, uint16_t
}
// Because VUSB at controller sends ACK reply before CRC check of received data we have to retry sending request our self if data is corrupted
- int n = 0, retrys = 0;
while (retrys < 3)
{
n = libusb_control_transfer(ctrl->dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, req, val, index, buf, len, timeout);
@@ -174,7 +184,7 @@ static int df10ch_control_in_transfer(df10ch_ctrl_t *ctrl, uint8_t req, uint16_t
if (n < 0)
{
- printf( "%s: sending USB control transfer message %d failed: %s\n", ctrl->id, req, df10ch_usb_errmsg(n));
+ printf( "%s: sending USB control transfer message %d failed: %s\n", ctrl->id, req, libusb_strerror(n));
return -1;
}
@@ -191,11 +201,13 @@ static int df10ch_control_in_transfer(df10ch_ctrl_t *ctrl, uint8_t req, uint16_t
static void df10ch_dispose(df10ch_output_driver_t *this) {
df10ch_ctrl_t *ctrl = this->ctrls;
while (ctrl) {
+ df10ch_ctrl_t *next;
+
libusb_free_transfer(ctrl->transfer);
libusb_release_interface(ctrl->dev, 0);
libusb_close(ctrl->dev);
- df10ch_ctrl_t *next = ctrl->next;
+ next = ctrl->next;
free(ctrl->transfer_data);
free(ctrl);
ctrl = next;
@@ -231,16 +243,16 @@ static void df10ch_read_status(df10ch_output_driver_t *this, int always) {
static void df10ch_wait_for_replys(df10ch_output_driver_t *this) {
+ df10ch_ctrl_t *ctrl = this->ctrls;
// wait for end of all pending transfers
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = (DF10CH_USB_DEFAULT_TIMEOUT + 50) * 1000;
- df10ch_ctrl_t *ctrl = this->ctrls;
while (ctrl) {
if (ctrl->pending_submit) {
int rc = libusb_handle_events_timeout(this->ctx, &timeout);
if (rc && rc != LIBUSB_ERROR_INTERRUPTED) {
- printf( "handling USB events failed: %s\n", df10ch_usb_errmsg(rc));
+ printf( "handling USB events failed: %s\n", libusb_strerror(rc));
break;
}
}
@@ -251,7 +263,7 @@ static void df10ch_wait_for_replys(df10ch_output_driver_t *this) {
}
-static void df10ch_reply_cb(struct libusb_transfer *transfer) {
+static void LIBUSB_CALL df10ch_reply_cb(struct libusb_transfer *transfer) {
df10ch_ctrl_t *ctrl = (df10ch_ctrl_t *) transfer->user_data;
ctrl->pending_submit = 0;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED && transfer->status != LIBUSB_TRANSFER_CANCELLED) {
@@ -263,6 +275,11 @@ static void df10ch_reply_cb(struct libusb_transfer *transfer) {
static int df10ch_driver_open(df10ch_output_driver_t *this) {
+ libusb_device **list = NULL;
+ df10ch_ctrl_t *ctrl;
+ size_t cnt;
+ int rc;
+ size_t i;
this->max_transmit_latency = 0;
this->avg_transmit_latency = 0;
@@ -273,18 +290,15 @@ static int df10ch_driver_open(df10ch_output_driver_t *this) {
return -1;
}
- libusb_device **list = NULL;
- size_t cnt = libusb_get_device_list(this->ctx, &list);
+ cnt = libusb_get_device_list(this->ctx, &list);
if (cnt < 0) {
- printf("getting list of USB devices failed: %s\n", df10ch_usb_errmsg(cnt));
+ printf("getting list of USB devices failed: %s\n", libusb_strerror(cnt));
df10ch_dispose(this);
return -1;
}
// Note: Because controller uses obdev's free USB product/vendor ID's we have to do special lookup for finding
// the controllers. See file "USB-IDs-for-free.txt" of VUSB distribution.
- int rc;
- size_t i;
for (i = 0; i < cnt; i++) {
libusb_device *d = list[i];
struct libusb_device_descriptor desc;
@@ -294,31 +308,31 @@ static int df10ch_driver_open(df10ch_output_driver_t *this) {
rc = libusb_get_device_descriptor(d, &desc);
if (rc < 0)
- printf( "USB[%d,%d]: getting USB device descriptor failed: %s\n", busnum, devnum, df10ch_usb_errmsg(rc));
+ printf( "USB[%d,%d]: getting USB device descriptor failed: %s\n", busnum, devnum, libusb_strerror(rc));
else if (desc.idVendor == DF10CH_USB_CFG_VENDOR_ID && desc.idProduct == DF10CH_USB_CFG_PRODUCT_ID) {
libusb_device_handle *hdl = NULL;
rc = libusb_open(d, &hdl);
if (rc < 0)
- printf( "USB[%d,%d]: open of USB device failed: %s\n", busnum, devnum, df10ch_usb_errmsg(rc));
+ printf( "USB[%d,%d]: open of USB device failed: %s\n", busnum, devnum, libusb_strerror(rc));
else {
unsigned char buf[256];
rc = libusb_get_string_descriptor_ascii(hdl, desc.iManufacturer, buf, sizeof(buf));
if (rc < 0)
- printf( "USB[%d,%d]: getting USB manufacturer string failed: %s\n", busnum, devnum, df10ch_usb_errmsg(rc));
+ printf( "USB[%d,%d]: getting USB manufacturer string failed: %s\n", busnum, devnum, libusb_strerror(rc));
else if (rc == sizeof(DF10CH_USB_CFG_VENDOR_NAME) - 1 && !memcmp(buf, DF10CH_USB_CFG_VENDOR_NAME, rc)) {
rc = libusb_get_string_descriptor_ascii(hdl, desc.iProduct, buf, sizeof(buf));
if (rc < 0)
- printf( "USB[%d,%d]: getting USB product string failed: %s\n", busnum, devnum, df10ch_usb_errmsg(rc));
+ printf( "USB[%d,%d]: getting USB product string failed: %s\n", busnum, devnum, libusb_strerror(rc));
else if (rc == sizeof(DF10CH_USB_CFG_PRODUCT) - 1 && !memcmp(buf, DF10CH_USB_CFG_PRODUCT, rc)) {
char id[32];
snprintf(id, sizeof(id), "DF10CH[%d,%d]", busnum, devnum);
rc = libusb_set_configuration(hdl, 1);
if (rc < 0)
- printf( "%s: setting USB configuration failed: %s\n", id, df10ch_usb_errmsg(rc));
+ printf( "%s: setting USB configuration failed: %s\n", id, libusb_strerror(rc));
else {
rc = libusb_claim_interface(hdl, 0);
if (rc < 0)
- printf( "%s: claiming USB interface failed: %s\n", id, df10ch_usb_errmsg(rc));
+ printf( "%s: claiming USB interface failed: %s\n", id, libusb_strerror(rc));
else {
df10ch_ctrl_t *ctrl = (df10ch_ctrl_t *) calloc(1, sizeof(df10ch_ctrl_t));
ctrl->next = this->ctrls;
@@ -347,7 +361,7 @@ static int df10ch_driver_open(df10ch_output_driver_t *this) {
}
// Read controller configuration
- df10ch_ctrl_t *ctrl = this->ctrls;
+ ctrl = this->ctrls;
while (ctrl) {
uint8_t data[256];
@@ -398,22 +412,30 @@ static int df10ch_driver_close(df10ch_output_driver_t *this) {
static void df10ch_driver_output_colors(df10ch_output_driver_t *this, uint8_t *data, int len) {
- struct timeval tvnow, tvlast, tvdiff;
+ df10ch_ctrl_t *ctrl = this->ctrls;
+ int latency;
- gettimeofday(&tvlast, NULL);
+#ifdef WIN32
+ FILETIME act_time, start_time;
+ GetSystemTimeAsFileTime (&start_time);
+#else
+ struct timeval act_time, start_time, latency_time;
+ gettimeofday(&start_time, NULL);
+#endif
// Generate transfer messages and send it to controllers
- df10ch_ctrl_t *ctrl = this->ctrls;
while (ctrl) {
+ int rc;
+
// Generate payload data (brightness values)
uint8_t *payload = ctrl->transfer_data + LIBUSB_CONTROL_SETUP_SIZE;
memcpy(payload, data, len);
// initiate asynchron data transfer to controller
ctrl->transfer_error = 0;
- int rc = libusb_submit_transfer(ctrl->transfer);
+ rc = libusb_submit_transfer(ctrl->transfer);
if (rc)
- printf( "%s: submitting USB control transfer message failed: %s\n", ctrl->id, df10ch_usb_errmsg(rc));
+ printf( "%s: submitting USB control transfer message failed: %s\n", ctrl->id, libusb_strerror(rc));
else
ctrl->pending_submit = 1;
@@ -423,11 +445,18 @@ static void df10ch_driver_output_colors(df10ch_output_driver_t *this, uint8_t *d
// wait for end of all pending transfers
df10ch_wait_for_replys(this);
- gettimeofday(&tvnow, NULL);
- timersub(&tvnow, &tvlast, &tvdiff);
- this->avg_transmit_latency = (this->avg_transmit_latency + tvdiff.tv_usec) / 2;
- if (tvdiff.tv_usec > this->max_transmit_latency) {
- this->max_transmit_latency = tvdiff.tv_usec;
+#ifdef WIN32
+ GetSystemTimeAsFileTime (&act_time);
+ latency = (act_time.dwLowDateTime - start_time.dwLowDateTime) / 10;
+#else
+ gettimeofday(&act_time, NULL);
+ timersub(&act_time, &start_time, &latency_time);
+ latency = latency_time.tv_usec;
+#endif
+
+ this->avg_transmit_latency = (this->avg_transmit_latency + latency) / 2;
+ if (latency > this->max_transmit_latency) {
+ this->max_transmit_latency = latency;
printf( "max/avg transmit latency: %d/%d [us]\n", this->max_transmit_latency, this->avg_transmit_latency);
}
}
@@ -438,7 +467,7 @@ static uint16_t bright[DF10CH_MAX_CHANNELS];
int main(int argc, char **argv) {
int n, i, b;
- printf("DF10CH test application V1\n");
+ printf("DF10CH test application V2\n");
if (argc != 2) {
printf("usage: %s number-of-test-loops\n", argv[0]);
return 1;
diff --git a/windows/DF10CH.cat b/windows/DF10CH.cat
deleted file mode 100644
index 2ef39c5..0000000
--- a/windows/DF10CH.cat
+++ /dev/null
@@ -1,3 +0,0 @@
-This file will contain the digital signature of the files to be installed
-on the system.
-This file will be provided by Microsoft upon certification of your drivers.
diff --git a/windows/DF10CH.inf b/windows/DF10CH.inf
deleted file mode 100644
index 6cfe2d5..0000000
--- a/windows/DF10CH.inf
+++ /dev/null
@@ -1,132 +0,0 @@
-; DF10CH.inf
-; Copyright (c) 2010 libusb-win32 (GNU LGPL)
-[Version]
-Signature = "$Windows NT$"
-Class = "libusb-win32 devices"
-ClassGUID = {EB781AAF-9C70-4523-A5DF-642A87ECA567}
-Provider = "libusb-win32"
-CatalogFile = DF10CH.cat
-DriverVer = 05/19/2010, 1.1.14.0
-
-[ClassInstall32]
-AddReg=libusb_class_install_add_reg
-
-[libusb_class_install_add_reg]
-HKR,,,0,"libusb-win32 devices"
-HKR,,Icon,,-20
-
-[Manufacturer]
-"yak54@gmx.net"=LIBUSB_WIN32, NT, NTAMD64, NTIA64
-
-;--------------------------------------------------------------------------
-; libusb-win32 files
-;--------------------------------------------------------------------------
-
-[SourceDisksNames]
-1 = %LIBUSB_WIN32_DiskName%
-
-[SourceDisksFiles.x86]
-libusb0.sys = 1,x86
-libusb0.dll = 1,x86
-
-[SourceDisksFiles.amd64]
-libusb0.sys = 1,amd64
-libusb0.dll = 1,amd64
-x86\libusb0.dll = 1
-
-[SourceDisksFiles.ia64]
-libusb0.sys = 1,ia64
-libusb0.dll = 1,ia64
-x86\libusb0.dll = 1
-
-[DestinationDirs]
-libusb_files_sys = 10,system32\drivers
-libusb_files_dll = 10,system32
-libusb_files_dll_wow64 = 10,syswow64
-
-[libusb_files_sys]
-libusb0.sys
-
-[libusb_files_dll]
-libusb0.dll
-
-[libusb_files_dll_wow64]
-libusb0.dll,x86\libusb0.dll
-
-;--------------------------------------------------------------------------
-; libusb-win32 device driver
-;--------------------------------------------------------------------------
-
-[LIBUSB_WIN32_DEV.NT]
-CopyFiles = libusb_files_sys, libusb_files_dll
-
-[LIBUSB_WIN32_DEV.NTAMD64]
-CopyFiles = libusb_files_sys, libusb_files_dll, libusb_files_dll_wow64
-
-[LIBUSB_WIN32_DEV.NTIA64]
-CopyFiles = libusb_files_sys, libusb_files_dll, libusb_files_dll_wow64
-
-[LIBUSB_WIN32_DEV.NT.HW]
-DelReg = libusb_del_reg_hw
-AddReg = libusb_add_reg_hw
-
-[LIBUSB_WIN32_DEV.NTAMD64.HW]
-DelReg = libusb_del_reg_hw
-AddReg = libusb_add_reg_hw
-
-[LIBUSB_WIN32_DEV.NTIA64.HW]
-DelReg = libusb_del_reg_hw
-AddReg = libusb_add_reg_hw
-
-[LIBUSB_WIN32_DEV.NT.Services]
-AddService = libusb0, 0x00000002, libusb_add_service
-
-[LIBUSB_WIN32_DEV.NTAMD64.Services]
-AddService = libusb0, 0x00000002, libusb_add_service
-
-[LIBUSB_WIN32_DEV.NTIA64.Services]
-AddService = libusb0, 0x00000002, libusb_add_service
-
-; Older versions of this .inf file installed filter drivers. They are not
-; needed any more and must be removed
-[libusb_del_reg_hw]
-HKR,,LowerFilters
-HKR,,UpperFilters
-
-; libusb-win32 device properties
-[libusb_add_reg_hw]
-HKR,,SurpriseRemovalOK, 0x00010001, 1
-
-; (Optional) the usb configuration value to select when this device
-; is started. If this key does not exist the first config is selected.
-;HKR,,InitialConfigValue,0x00010001,<your config value>
-
-;--------------------------------------------------------------------------
-; libusb-win32 service
-;--------------------------------------------------------------------------
-
-[libusb_add_service]
-DisplayName = "LibUsb-Win32 - Kernel Driver 1.1.14.0, 05/19/2010"
-ServiceType = 1
-StartType = 3
-ErrorControl = 0
-ServiceBinary = %12%\libusb0.sys
-
-;--------------------------------------------------------------------------
-; LIBUSB_WIN32
-;--------------------------------------------------------------------------
-
-[LIBUSB_WIN32]
-"DF10CH"=LIBUSB_WIN32_DEV, USB\VID_16c0&PID_05dc
-
-[LIBUSB_WIN32.NT]
-"DF10CH"=LIBUSB_WIN32_DEV, USB\VID_16c0&PID_05dc
-
-[LIBUSB_WIN32.NTAMD64]
-"DF10CH"=LIBUSB_WIN32_DEV, USB\VID_16c0&PID_05dc
-
-[LIBUSB_WIN32.NTIA64]
-"DF10CH"=LIBUSB_WIN32_DEV, USB\VID_16c0&PID_05dc
-
-[Strings]
-LIBUSB_WIN32_DiskName="DF10CH Install Disk"
diff --git a/windows/df10ch_setup.bat b/windows/df10ch_setup.bat
new file mode 100644
index 0000000..1a44f3b
--- /dev/null
+++ b/windows/df10ch_setup.bat
@@ -0,0 +1,4 @@
+REM -- Start DF10CH Setup
+REM Expand PATH so that libusb-1.0.dll could be found
+set PATH=.;%PATH%
+.\df10ch_setup.exe %1 %2 %3
diff --git a/winsetup.py b/winsetup.py
new file mode 100644
index 0000000..f2fa0cb
--- /dev/null
+++ b/winsetup.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2011 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# Df10CH setup program installation script
+#
+
+from distutils.core import setup
+import py2exe
+
+setup(name='df10ch_setup',
+ version='4',
+ description='DF10CH Setup program',
+ author='Andreas Auras',
+ author_email='yak54@inkennet.de',
+ url='http://www.vdr-wiki.de/wiki/index.php/VDR_Wiki:DF10CH_Atmolight_Kontroller',
+ requires=[ 'TKinter', 'Image', 'ImageTk', 'ImageDraw' ],
+ console=[ 'df10ch_setup.py' ],
+ packages = [ 'df10ch_setup_pkg' ],
+ data_files = [ ( '', [ 'project/df10ch_test/Release/df10ch_test.exe',
+ '../libusb/Win32/Release/dll/libusb-1.0.dll',
+ '../zadig.exe',
+ 'windows/df10ch_setup.bat',
+ 'HISTORY',
+ 'COPYING',
+ 'README' ] ),
+ ( 'firmware', [ 'usb_appl/df10ch_usb_appl.dff',
+ 'usb_appl/df10ch_usb_appl.hex',
+ 'usb_boot/df10ch_usb_boot.hex',
+ 'pwm_appl/df10ch_pwm_appl.dff',
+ 'pwm_appl/df10ch_pwm_appl.hex',
+ 'pwm_boot/df10ch_pwm_boot.hex' ] ) ],
+ )
+