diff options
author | Andreas Auras <yak54@inkennet.de> | 2011-09-23 22:16:43 +0200 |
---|---|---|
committer | Andreas Auras <yak54@inkennet.de> | 2011-09-23 22:16:43 +0200 |
commit | e13185dcc397297442e815cb4372537c86e89afa (patch) | |
tree | 282e25b9d62d263280236993b655c0502d80c1b7 | |
parent | a9fd3ff0b95b45ea419c701448270a061b28c570 (diff) | |
download | df10ch-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-- | .project | 4 | ||||
-rw-r--r-- | .pydevproject | 4 | ||||
-rw-r--r-- | HISTORY | 10 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README | 64 | ||||
-rw-r--r-- | df10ch_setup.py | 2 | ||||
-rw-r--r-- | df10ch_setup_pkg/device_dlg.py | 9 | ||||
-rw-r--r-- | df10ch_setup_pkg/device_drv.py | 137 | ||||
-rw-r--r-- | df10ch_setup_pkg/firmware.py | 3 | ||||
-rw-r--r-- | df10ch_setup_pkg/libusb1.py | 917 | ||||
-rw-r--r-- | df10ch_setup_pkg/usb1.py | 1507 | ||||
-rw-r--r-- | project/df10ch_test/df10ch_test.sln | 20 | ||||
-rw-r--r-- | project/df10ch_test/df10ch_test.vcxproj | 91 | ||||
-rw-r--r-- | project/df10ch_test/df10ch_test.vcxproj.filters | 27 | ||||
-rw-r--r-- | setup.py | 6 | ||||
-rw-r--r-- | test_appl/df10ch_test.c | 101 | ||||
-rw-r--r-- | windows/DF10CH.cat | 3 | ||||
-rw-r--r-- | windows/DF10CH.inf | 132 | ||||
-rw-r--r-- | windows/df10ch_setup.bat | 4 | ||||
-rw-r--r-- | winsetup.py | 50 |
20 files changed, 2832 insertions, 269 deletions
@@ -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> @@ -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. @@ -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 @@ -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 @@ -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' ] ) ], + ) + |