Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/plugins/wedo_plugin/usb
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/wedo_plugin/usb')
-rw-r--r--plugins/wedo_plugin/usb/ACKNOWLEDGEMENTS51
-rw-r--r--plugins/wedo_plugin/usb/LICENSE27
-rw-r--r--plugins/wedo_plugin/usb/README.rst83
-rw-r--r--plugins/wedo_plugin/usb/ReleaseNotes.rst102
-rw-r--r--plugins/wedo_plugin/usb/TODO36
-rw-r--r--plugins/wedo_plugin/usb/__init__.py17
-rw-r--r--plugins/wedo_plugin/usb/_debug.py2
-rw-r--r--plugins/wedo_plugin/usb/_interop.py10
-rw-r--r--plugins/wedo_plugin/usb/backend/__init__.py2
-rw-r--r--plugins/wedo_plugin/usb/backend/libusb0.py590
-rw-r--r--plugins/wedo_plugin/usb/backend/libusb1.py901
-rw-r--r--plugins/wedo_plugin/usb/backend/openusb.py66
-rw-r--r--plugins/wedo_plugin/usb/control.py2
-rw-r--r--plugins/wedo_plugin/usb/core.py90
-rw-r--r--plugins/wedo_plugin/usb/legacy.py30
-rw-r--r--plugins/wedo_plugin/usb/util.py8
16 files changed, 1929 insertions, 88 deletions
diff --git a/plugins/wedo_plugin/usb/ACKNOWLEDGEMENTS b/plugins/wedo_plugin/usb/ACKNOWLEDGEMENTS
new file mode 100644
index 0000000..b7fdb22
--- /dev/null
+++ b/plugins/wedo_plugin/usb/ACKNOWLEDGEMENTS
@@ -0,0 +1,51 @@
+This is a list of people who has contributed to PyUSB 1.0 development.
+If I forgot you, please email me.
+
+PyUSB 1.0.0 (beta 1)
+---------------------
+
+- Stefano Di Martino: the port number patch.
+- Simon Norberg: several bug fixes.
+- iThompson: fixed tab errors in Python 3.3.
+- Harry Bock: workaround for Python 3.3 bug.
+- ponty: tox support.
+- Chris Clark: version information patch.
+- themperek: improve read speed.
+- David Halter: for the isochronous writing implementation for the libusb10
+ backend.
+
+PyUSB 1.0.0 (alpha 3)
+---------------------
+
+- Robert von Burg: for the bug reports about Python versions compatibility and
+ kernel driver functions.
+- James Rowe: for patches to the tutorial file.
+- Braiden Kindt: for the patch fixing bug when less than o number of requested
+ bytes are read.
+- Tormod Volden: for his several patches for legacy module.
+
+PyUSB 1.0.0 (alpha 2)
+---------------------
+
+- Chris Clark: for the bug report in the log subsystem.
+- Emmanuel Blot: for the patch which improves performance when debug is disabled.
+- Peter Bigot: for the patch that fixes get_active_configuration seg fault,
+ the patch to add error code to USBError and the patch to fix
+ parameter order in the USBError.
+- Travis Robinson and Xiaofan Chen: for let me use their benchmark firmware.
+- Poul-Henning Kamp: for the suggestion of ``bus`` and ``address`` attributes.
+
+PyUSB 1.0.0 (alpha 1)
+---------------------
+
+- Xiaofan Chen: for support in mailing list.
+- Poul-Henning Kam: for the documentation patches.
+
+PyUSB 1.0.0 (alpha 0)
+---------------------
+
+- Thomas Reitmayr: thanks for your patches to get PyUSB running with libusb 1.0.
+- Carl Ritson: thanks for your patch to get minimal working of legacy layer.
+- Romain Aviolat: thanks for pointing out a mistake in the tutorial and to report a bug in ctrl_transfer.
+- Xiaofan Chen: thanks for your effort testing PyUSB with libusb 1.0 Windows backend and on FreeBSD.
+
diff --git a/plugins/wedo_plugin/usb/LICENSE b/plugins/wedo_plugin/usb/LICENSE
new file mode 100644
index 0000000..1c88b5a
--- /dev/null
+++ b/plugins/wedo_plugin/usb/LICENSE
@@ -0,0 +1,27 @@
+Copyright (C) 2009-2011 Wander Lairson Costa. All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
diff --git a/plugins/wedo_plugin/usb/README.rst b/plugins/wedo_plugin/usb/README.rst
new file mode 100644
index 0000000..741c4df
--- /dev/null
+++ b/plugins/wedo_plugin/usb/README.rst
@@ -0,0 +1,83 @@
+=======================================
+PyUSB 1.0 - Easy USB access from Python
+=======================================
+
+Introduction
+============
+
+The PyUSB module provides for Python easy access to the host
+machine's Universal Serial Bus (USB) system.
+
+Until 0.4 version, PyUSB used to be a thin wrapper over libusb.
+With 1.0 version, things changed considerably. Now PyUSB is an
+API rich, backend neutral Python USB module easy to use.
+
+As with most Python modules, PyUSB's documentation is based on Python
+doc strings and can therefore be manipulated by tools such as pydoc.
+
+You can also find a tutorial at: http://pyusb.sourceforge.net/docs/1.0/tutorial.html.
+
+PyUSB is being developed and tested in Linux and Windows, but it should work
+fine in any platform running Python >= 2.4, ctypes and at least one of the
+builtin backends.
+
+PyUSB supports libusb 0.1, libusb 1.0 and OpenUSB, but the user does not need
+to worry about that, unless in some corner cases.
+
+If you have any question about PyUSB, you can use the PyUSB mailing list
+hosted in the SourceForge. In the PyUSB website (http://pyusb.sourceforge.net)
+you can find instructions on how to subscribe to the mailing list.
+
+Installing PyUSB on GNU/Linux Systems
+=====================================
+
+These instructions are for Debian-based systems. Instructions for
+other flavors of GNU/Linux should be similar.
+
+You will first need to install the following packages:
+
+1) python (PyUSB is useless without it), version >= 2.4
+2) At least one of the supported libraries (libusb 1.0, libusb 0.1 or OpenUSB)
+3) If your Python version is < 2.5, you have to install ctypes as a separate package,
+ because these versions of Python does not ship it.
+
+For example, the command::
+
+ $ sudo apt-get install python libusb
+
+should install all these packages on most Debian-based systems with
+access to the proper package repositories.
+
+Once the above packages are installed, you can install PyUSB
+with the command::
+
+ $ sudo python setup.py install
+
+Run it as root from within the same directory as this README file.
+
+Installing PyUSB on Windows
+===========================
+
+Now that PyUSB is 100% written in Python, you install it on Windows
+in the same way you do on Linux::
+
+ python setup.py install
+
+If you get some kind of "command not found" error, make sure to add
+the Python install directory to your PATH environment variable or
+give the complete path to the Python interpreter.
+
+Remember that you need libusb (1.0 or 0.1) or OpenUSB running on your
+system. For Windows users, libusb 1.0 is still experimental, so it is
+recommended libusb-win32 package. Check the libusb website for updates
+(http://www.libusb.org).
+
+Reporting bugs/Submitting patches
+=================================
+
+Some people have been sending patches and reporting bugs directly
+at my email. Please, do it through
+`github <https://github.com/walac/pyusb>`_, I had a hardtime tracking
+their names to put them in the acknowledgments file. ;-)
+
+PS: this README file was based on the great Josh Lifton's one... ^_^
diff --git a/plugins/wedo_plugin/usb/ReleaseNotes.rst b/plugins/wedo_plugin/usb/ReleaseNotes.rst
new file mode 100644
index 0000000..53c7d96
--- /dev/null
+++ b/plugins/wedo_plugin/usb/ReleaseNotes.rst
@@ -0,0 +1,102 @@
+==========
+PyUSB News
+==========
+
+What's new in PyUSB 1.0.0 (beta 1)?
+===================================
+
+- Isochronous transfer for libusb 1.0 (by David Halter).
+- Experimental OpenUSB support.
+- Documentation update.
+- ``PYUSB_DEBUG_LEVEL`` environment variable is now called ``PYUSB_DEBUG``.
+- Legacy module nwo groups according to their *bus*.
+- Version information available for apps (by Chris Clark).
+- Faster read operation (by themperek).
+- Tox support (by ponty).
+- Support for port number info (by Stefano Di Martino).
+- Several bug fixes (please, check the Changelog file).
+
+Known issues
+============
+
+- OpenUSB backend hangs on some control transfers.
+
+TODO
+====
+
+- More tests with legacy module.
+- Isochronous transfers for libusb-win32.
+
+What's new in PyUSB 1.0.0 (alpha 3)?
+====================================
+
+**WARNING**: this release renames the libusb 1.0 and libusb 0.1 backends. If
+your code makes direct access to this backends, you will have to change it.
+
+- Fixed several legacy module bugs (by Tormod Volden).
+- Fixed libusb0 backend for BSDs and Mac OSX.
+- Fixed data loss when less the requested number of bytes were read (by
+ Braiden Kindt).
+- Documentation fixes.
+
+What's new in PyUSB 1.0.0 (alpha 2)?
+====================================
+
+- Test firmware now lives in its own respository (https://github.com/walac/bmfw).
+- ``USBError`` now has the property ``backend_error_code`` that tells the
+ backend specific error.
+- ``errno`` value in ``USBError`` is translated according to the backend error.
+- Now ``Device`` class has the ``bus`` and ``address`` attributes to
+ differentiate identical devices.
+- Optimization when log is disabled (by Emmanuel Blot).
+- Several other minor fixes and improvaments (check ChangeLog file).
+
+Features not implemented
+------------------------
+
+- OpenUSB support.
+- Isochronous transfer.
+
+What's new in PyUSB 1.0.0 (alpha 1)?
+====================================
+
+This release implements more PyUSB 1.0 features towards beta stage. The new
+features implemented include:
+
+- Standard control requests through usb.control module.
+- Request current configuration from device when you do not call
+ set_configuration.
+- get_string function in the usb.util module to get string descriptors.
+- Full 0.4 API emulation.
+- Device is not reset anymore in test cases to avoid problems in systems
+ where it does not work.
+
+Features not implemented
+------------------------
+
+- OpenUSB support.
+- Isochronous transfer.
+
+What's new in PyUSB 1.0.0 (alpha 0)?
+====================================
+
+This is the first PyUSB 1.0 series public release. This is an alpha release, which
+means that most of the features described in the README file and on the website are
+not yet stable or even implemented.
+
+Features not implemented
+------------------------
+
+- Full support for legacy 0.4 legacy code (although partial support is provided).
+- OpenUSB backend.
+- libusb 1.0 windows backend stability (although it is reasonable usable).
+- Support for several standard control requests (including GET_STRING).
+- Python < 2.6 and Python 3 not yet fully tested.
+
+Known issues
+------------
+
+- ``reset`` method fails under FreeUSB (libusb 1.0 backend).
+- ``reset`` method hangs under Windows (libusb 1.0 backend).
+- Sometimes occurs `read` timeout on Windows (libusb 1.0 backend).
+- Test cases fail to run under cygwin.
diff --git a/plugins/wedo_plugin/usb/TODO b/plugins/wedo_plugin/usb/TODO
new file mode 100644
index 0000000..d7eeb70
--- /dev/null
+++ b/plugins/wedo_plugin/usb/TODO
@@ -0,0 +1,36 @@
+1.0.0-a3:
+ * Finish implementation and test OpenUSB backend.
+ * Samples.
+ * Improve documentation.
+ * Implement isochronous transfers.
+ * Test, test and test.
+
+1.0.0-a2:
+ * Validate it on platforms other than Windows and Linux.
+ * Finish implementation and test OpenUSB backend.
+ * Samples.
+ * Improve documentation.
+ * Implement isochronous transfers.
+ * Test, test and test.
+
+1.0.0-a1:
+ * Validate it on platforms other than Windows and Linux.
+ * Finish implementation and test OpenUSB backend.
+ * Samples.
+ * Improve documentation.
+ * Implement isochronous transfers.
+ * Test, test and test.
+
+1.0.0-a0:
+ * Implement standard control requests API.
+ * Finish implementation of legacy compatibility layer.
+ * Determine automatically current configuration when user hasn't set it.
+ * Validate it on platforms other than Windows and Linux.
+ * Finish implementation and test of OpenUSB backend.
+ * Validate it on Python 2.3 and Python 3.x.
+ * Samples.
+ * Improve documentation.
+ * Implement isochronous transfers.
+ * Upgrade PIC test firmware to use 2.6a version Microchip USB stack.
+ * Test, test and test.
+
diff --git a/plugins/wedo_plugin/usb/__init__.py b/plugins/wedo_plugin/usb/__init__.py
index 8909cf2..178ed14 100644
--- a/plugins/wedo_plugin/usb/__init__.py
+++ b/plugins/wedo_plugin/usb/__init__.py
@@ -1,8 +1,8 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
-#
+# Copyright (C) 2009-2013 Wander Lairson Costa
+#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
-#
+#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
@@ -12,13 +12,13 @@
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
-#
+#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
+#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
@@ -43,13 +43,18 @@ import os
__author__ = 'Wander Lairson Costa'
+# Use Semantic Versioning, http://semver.org/
+version_info = (1, 0, 0, 'b1')
+__version__ = '%d.%d.%d%s' % version_info
+
+
__all__ = ['legacy', 'core', 'backend', 'util']
def _setup_log():
from usb import _debug
logger = logging.getLogger('usb')
- debug_level = os.getenv('PYUSB_DEBUG_LEVEL')
+ debug_level = os.getenv('PYUSB_DEBUG')
if debug_level is not None:
_debug.enable_tracing(True)
diff --git a/plugins/wedo_plugin/usb/_debug.py b/plugins/wedo_plugin/usb/_debug.py
index 13b0ced..8b1f910 100644
--- a/plugins/wedo_plugin/usb/_debug.py
+++ b/plugins/wedo_plugin/usb/_debug.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
+# Copyright (C) 2009-2013 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
diff --git a/plugins/wedo_plugin/usb/_interop.py b/plugins/wedo_plugin/usb/_interop.py
index 6069d5e..93b8f04 100644
--- a/plugins/wedo_plugin/usb/_interop.py
+++ b/plugins/wedo_plugin/usb/_interop.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
+# Copyright (C) 2009-2013 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
@@ -129,7 +129,9 @@ def as_array(data=None):
try:
return array.array('B', data)
except TypeError:
- # When you pass a unicode string, you got a TypeError
- # if first parameter is not 'u'
- return array.array('u', data)
+ # When you pass a unicode string or a character sequence,
+ # you get a TypeError if first parameter does not match
+ a = array.array('B')
+ a.fromstring(data)
+ return a
diff --git a/plugins/wedo_plugin/usb/backend/__init__.py b/plugins/wedo_plugin/usb/backend/__init__.py
index 67ee00f..e08d7bc 100644
--- a/plugins/wedo_plugin/usb/backend/__init__.py
+++ b/plugins/wedo_plugin/usb/backend/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
+# Copyright (C) 2009-2013 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
diff --git a/plugins/wedo_plugin/usb/backend/libusb0.py b/plugins/wedo_plugin/usb/backend/libusb0.py
new file mode 100644
index 0000000..8738335
--- /dev/null
+++ b/plugins/wedo_plugin/usb/backend/libusb0.py
@@ -0,0 +1,590 @@
+# Copyright (C) 2009-2013 Wander Lairson Costa
+#
+# The following terms apply to all files associated
+# with the software unless explicitly disclaimed in individual files.
+#
+# The authors hereby grant permission to use, copy, modify, distribute,
+# and license this software and its documentation for any purpose, provided
+# that existing copyright notices are retained in all copies and that this
+# notice is included verbatim in any distributions. No written agreement,
+# license, or royalty fee is required for any of the authorized uses.
+# Modifications to this software may be copyrighted by their authors
+# and need not follow the licensing terms described here, provided that
+# the new terms are clearly indicated on the first page of each file where
+# they apply.
+#
+# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+# MODIFICATIONS.
+
+from ctypes import *
+import ctypes.util
+import os
+import usb.backend
+import usb.util
+import sys
+from usb.core import USBError
+from usb._debug import methodtrace
+import usb._interop as _interop
+import logging
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = ['get_backend']
+
+_logger = logging.getLogger('usb.backend.libusb0')
+
+# usb.h
+
+_PC_PATH_MAX = 4
+
+if sys.platform.find('bsd') != -1 or sys.platform.find('mac') != -1 or \
+ sys.platform.find('darwin') != -1:
+ _PATH_MAX = 1024
+elif sys.platform == 'win32' or sys.platform == 'cygwin':
+ _PATH_MAX = 511
+else:
+ _PATH_MAX = os.pathconf('.', _PC_PATH_MAX)
+
+# libusb-win32 makes all structures packed, while
+# default libusb only does for some structures
+# _PackPolicy defines the structure packing according
+# to the platform.
+class _PackPolicy(object):
+ pass
+
+if sys.platform == 'win32' or sys.platform == 'cygwin':
+ _PackPolicy._pack_ = 1
+
+# Data structures
+
+class _usb_descriptor_header(Structure):
+ _pack_ = 1
+ _fields_ = [('blength', c_uint8),
+ ('bDescriptorType', c_uint8)]
+
+class _usb_string_descriptor(Structure):
+ _pack_ = 1
+ _fields_ = [('bLength', c_uint8),
+ ('bDescriptorType', c_uint8),
+ ('wData', c_uint16)]
+
+class _usb_endpoint_descriptor(Structure, _PackPolicy):
+ _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', POINTER(c_uint8)),
+ ('extralen', c_int)]
+
+class _usb_interface_descriptor(Structure, _PackPolicy):
+ _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', POINTER(_usb_endpoint_descriptor)),
+ ('extra', POINTER(c_uint8)),
+ ('extralen', c_int)]
+
+class _usb_interface(Structure, _PackPolicy):
+ _fields_ = [('altsetting', POINTER(_usb_interface_descriptor)),
+ ('num_altsetting', c_int)]
+
+class _usb_config_descriptor(Structure, _PackPolicy):
+ _fields_ = [('bLength', c_uint8),
+ ('bDescriptorType', c_uint8),
+ ('wTotalLength', c_uint16),
+ ('bNumInterfaces', c_uint8),
+ ('bConfigurationValue', c_uint8),
+ ('iConfiguration', c_uint8),
+ ('bmAttributes', c_uint8),
+ ('bMaxPower', c_uint8),
+ ('interface', POINTER(_usb_interface)),
+ ('extra', POINTER(c_uint8)),
+ ('extralen', c_int)]
+
+class _usb_device_descriptor(Structure, _PackPolicy):
+ _pack_ = 1
+ _fields_ = [('bLength', c_uint8),
+ ('bDescriptorType', c_uint8),
+ ('bcdUSB', c_uint16),
+ ('bDeviceClass', c_uint8),
+ ('bDeviceSubClass', c_uint8),
+ ('bDeviceProtocol', c_uint8),
+ ('bMaxPacketSize0', c_uint8),
+ ('idVendor', c_uint16),
+ ('idProduct', c_uint16),
+ ('bcdDevice', c_uint16),
+ ('iManufacturer', c_uint8),
+ ('iProduct', c_uint8),
+ ('iSerialNumber', c_uint8),
+ ('bNumConfigurations', c_uint8)]
+
+class _usb_device(Structure, _PackPolicy):
+ pass
+
+class _usb_bus(Structure, _PackPolicy):
+ pass
+
+_usb_device._fields_ = [('next', POINTER(_usb_device)),
+ ('prev', POINTER(_usb_device)),
+ ('filename', c_int8 * (_PATH_MAX + 1)),
+ ('bus', POINTER(_usb_bus)),
+ ('descriptor', _usb_device_descriptor),
+ ('config', POINTER(_usb_config_descriptor)),
+ ('dev', c_void_p),
+ ('devnum', c_uint8),
+ ('num_children', c_ubyte),
+ ('children', POINTER(POINTER(_usb_device)))]
+
+_usb_bus._fields_ = [('next', POINTER(_usb_bus)),
+ ('prev', POINTER(_usb_bus)),
+ ('dirname', c_char * (_PATH_MAX + 1)),
+ ('devices', POINTER(_usb_device)),
+ ('location', c_uint32),
+ ('root_dev', POINTER(_usb_device))]
+
+_usb_dev_handle = c_void_p
+
+class _DeviceDescriptor:
+ def __init__(self, dev):
+ desc = dev.descriptor
+ self.bLength = desc.bLength
+ self.bDescriptorType = desc.bDescriptorType
+ self.bcdUSB = desc.bcdUSB
+ self.bDeviceClass = desc.bDeviceClass
+ self.bDeviceSubClass = desc.bDeviceSubClass
+ self.bDeviceProtocol = desc.bDeviceProtocol
+ self.bMaxPacketSize0 = desc.bMaxPacketSize0
+ self.idVendor = desc.idVendor
+ self.idProduct = desc.idProduct
+ self.bcdDevice = desc.bcdDevice
+ self.iManufacturer = desc.iManufacturer
+ self.iProduct = desc.iProduct
+ self.iSerialNumber = desc.iSerialNumber
+ self.bNumConfigurations = desc.bNumConfigurations
+ self.address = dev.devnum
+ self.bus = dev.bus[0].location
+
+ self.port_number = None
+_lib = None
+
+def _load_library():
+ if sys.platform != 'cygwin':
+ candidates = ('usb-0.1', 'usb', 'libusb0')
+ for candidate in candidates:
+ # Workaround for CPython 3.3 issue#16283 / pyusb #14
+ if sys.platform == 'win32':
+ candidate = candidate + '.dll'
+
+ libname = ctypes.util.find_library(candidate)
+ if libname is not None: break
+ else:
+ # corner cases
+ # cygwin predefines library names with 'cyg' instead of 'lib'
+ try:
+ return CDLL('cygusb0.dll')
+ except:
+ _logger.error('Libusb 0 could not be loaded in cygwin', exc_info=True)
+
+ raise OSError('USB library could not be found')
+ return CDLL(libname)
+
+def _setup_prototypes(lib):
+ # usb_dev_handle *usb_open(struct usb_device *dev);
+ lib.usb_open.argtypes = [POINTER(_usb_device)]
+ lib.usb_open.restype = _usb_dev_handle
+
+ # int usb_close(usb_dev_handle *dev);
+ lib.usb_close.argtypes = [_usb_dev_handle]
+
+ # int usb_get_string(usb_dev_handle *dev,
+ # int index,
+ # int langid,
+ # char *buf,
+ # size_t buflen);
+ lib.usb_get_string.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_int,
+ c_char_p,
+ c_size_t
+ ]
+
+ # int usb_get_string_simple(usb_dev_handle *dev,
+ # int index,
+ # char *buf,
+ # size_t buflen);
+ lib.usb_get_string_simple.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_char_p,
+ c_size_t
+ ]
+
+ # int usb_get_descriptor_by_endpoint(usb_dev_handle *udev,
+ # int ep,
+ # unsigned char type,
+ # unsigned char index,
+ # void *buf,
+ # int size);
+ lib.usb_get_descriptor_by_endpoint.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_ubyte,
+ c_ubyte,
+ c_void_p,
+ c_int
+ ]
+
+ # int usb_get_descriptor(usb_dev_handle *udev,
+ # unsigned char type,
+ # unsigned char index,
+ # void *buf,
+ # int size);
+ lib.usb_get_descriptor.argtypes = [
+ _usb_dev_handle,
+ c_ubyte,
+ c_ubyte,
+ c_void_p,
+ c_int
+ ]
+
+ # int usb_bulk_write(usb_dev_handle *dev,
+ # int ep,
+ # const char *bytes,
+ # int size,
+ # int timeout);
+ lib.usb_bulk_write.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_char_p,
+ c_int,
+ c_int
+ ]
+
+ # int usb_bulk_read(usb_dev_handle *dev,
+ # int ep,
+ # char *bytes,
+ # int size,
+ # int timeout);
+ lib.usb_bulk_read.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_char_p,
+ c_int,
+ c_int
+ ]
+
+ # int usb_interrupt_write(usb_dev_handle *dev,
+ # int ep,
+ # const char *bytes,
+ # int size,
+ # int timeout);
+ lib.usb_interrupt_write.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_char_p,
+ c_int,
+ c_int
+ ]
+
+ # int usb_interrupt_read(usb_dev_handle *dev,
+ # int ep,
+ # char *bytes,
+ # int size,
+ # int timeout);
+ lib.usb_interrupt_read.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_char_p,
+ c_int,
+ c_int
+ ]
+
+ # int usb_control_msg(usb_dev_handle *dev,
+ # int requesttype,
+ # int request,
+ # int value,
+ # int index,
+ # char *bytes,
+ # int size,
+ # int timeout);
+ lib.usb_control_msg.argtypes = [
+ _usb_dev_handle,
+ c_int,
+ c_int,
+ c_int,
+ c_int,
+ c_char_p,
+ c_int,
+ c_int
+ ]
+
+ # int usb_set_configuration(usb_dev_handle *dev, int configuration);
+ lib.usb_set_configuration.argtypes = [_usb_dev_handle, c_int]
+
+ # int usb_claim_interface(usb_dev_handle *dev, int interface);
+ lib.usb_claim_interface.argtypes = [_usb_dev_handle, c_int]
+
+ # int usb_release_interface(usb_dev_handle *dev, int interface);
+ lib.usb_release_interface.argtypes = [_usb_dev_handle, c_int]
+
+ # int usb_set_altinterface(usb_dev_handle *dev, int alternate);
+ lib.usb_set_altinterface.argtypes = [_usb_dev_handle, c_int]
+
+ # int usb_resetep(usb_dev_handle *dev, unsigned int ep);
+ lib.usb_resetep.argtypes = [_usb_dev_handle, c_int]
+
+ # int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
+ lib.usb_clear_halt.argtypes = [_usb_dev_handle, c_int]
+
+ # int usb_reset(usb_dev_handle *dev);
+ lib.usb_reset.argtypes = [_usb_dev_handle]
+
+ # char *usb_strerror(void);
+ lib.usb_strerror.argtypes = []
+ lib.usb_strerror.restype = c_char_p
+
+ # void usb_set_debug(int level);
+ lib.usb_set_debug.argtypes = [c_int]
+
+ # struct usb_device *usb_device(usb_dev_handle *dev);
+ lib.usb_device.argtypes = [_usb_dev_handle]
+ lib.usb_device.restype = POINTER(_usb_device)
+
+ # struct usb_bus *usb_get_busses(void);
+ lib.usb_get_busses.restype = POINTER(_usb_bus)
+
+def _check(retval):
+ if retval is None:
+ errmsg = _lib.usb_strerror()
+ else:
+ ret = int(retval)
+ if ret < 0:
+ errmsg = _lib.usb_strerror()
+ # No error means that we need to get the error
+ # message from the return code
+ # Thanks to Nicholas Wheeler to point out the problem...
+ # Also see issue #2860940
+ if errmsg.lower() == 'no error':
+ errmsg = os.strerror(-ret)
+ else:
+ return ret
+ raise USBError(errmsg, ret)
+
+# implementation of libusb 0.1.x backend
+class _LibUSB(usb.backend.IBackend):
+ @methodtrace(_logger)
+ def enumerate_devices(self):
+ _check(_lib.usb_find_busses())
+ _check(_lib.usb_find_devices())
+ bus = _lib.usb_get_busses()
+ while bool(bus):
+ dev = bus[0].devices
+ while bool(dev):
+ yield dev[0]
+ dev = dev[0].next
+ bus = bus[0].next
+
+ @methodtrace(_logger)
+ def get_device_descriptor(self, dev):
+ return _DeviceDescriptor(dev)
+
+ @methodtrace(_logger)
+ def get_configuration_descriptor(self, dev, config):
+ if config >= dev.descriptor.bNumConfigurations:
+ raise IndexError('Invalid configuration index ' + str(config))
+ return dev.config[config]
+
+ @methodtrace(_logger)
+ def get_interface_descriptor(self, dev, intf, alt, config):
+ cfgdesc = self.get_configuration_descriptor(dev, config)
+ if intf >= cfgdesc.bNumInterfaces:
+ raise IndexError('Invalid interface index ' + str(interface))
+ interface = cfgdesc.interface[intf]
+ if alt >= interface.num_altsetting:
+ raise IndexError('Invalid alternate setting index ' + str(alt))
+ return interface.altsetting[alt]
+
+ @methodtrace(_logger)
+ def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
+ interface = self.get_interface_descriptor(dev, intf, alt, config)
+ if ep >= interface.bNumEndpoints:
+ raise IndexError('Invalid endpoint index ' + str(ep))
+ return interface.endpoint[ep]
+
+ @methodtrace(_logger)
+ def open_device(self, dev):
+ return _check(_lib.usb_open(dev))
+
+ @methodtrace(_logger)
+ def close_device(self, dev_handle):
+ _check(_lib.usb_close(dev_handle))
+
+ @methodtrace(_logger)
+ def set_configuration(self, dev_handle, config_value):
+ _check(_lib.usb_set_configuration(dev_handle, config_value))
+
+ @methodtrace(_logger)
+ def set_interface_altsetting(self, dev_handle, intf, altsetting):
+ _check(_lib.usb_set_altinterface(dev_handle, altsetting))
+
+ @methodtrace(_logger)
+ def get_configuration(self, dev_handle):
+ bmRequestType = usb.util.build_request_type(
+ usb.util.CTRL_IN,
+ usb.util.CTRL_TYPE_STANDARD,
+ usb.util.CTRL_RECIPIENT_DEVICE
+ )
+ return self.ctrl_transfer(dev_handle,
+ bmRequestType,
+ 0x08,
+ 0,
+ 0,
+ 1,
+ 100
+ )[0]
+
+
+ @methodtrace(_logger)
+ def claim_interface(self, dev_handle, intf):
+ _check(_lib.usb_claim_interface(dev_handle, intf))
+
+ @methodtrace(_logger)
+ def release_interface(self, dev_handle, intf):
+ _check(_lib.usb_release_interface(dev_handle, intf))
+
+ @methodtrace(_logger)
+ def bulk_write(self, dev_handle, ep, intf, data, timeout):
+ return self.__write(_lib.usb_bulk_write,
+ dev_handle,
+ ep,
+ intf,
+ data, timeout)
+
+ @methodtrace(_logger)
+ def bulk_read(self, dev_handle, ep, intf, size, timeout):
+ return self.__read(_lib.usb_bulk_read,
+ dev_handle,
+ ep,
+ intf,
+ size,
+ timeout)
+
+ @methodtrace(_logger)
+ def intr_write(self, dev_handle, ep, intf, data, timeout):
+ return self.__write(_lib.usb_interrupt_write,
+ dev_handle,
+ ep,
+ intf,
+ data,
+ timeout)
+
+ @methodtrace(_logger)
+ def intr_read(self, dev_handle, ep, intf, size, timeout):
+ return self.__read(_lib.usb_interrupt_read,
+ dev_handle,
+ ep,
+ intf,
+ size,
+ timeout)
+
+ @methodtrace(_logger)
+ def ctrl_transfer(self,
+ dev_handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ data_or_wLength,
+ timeout):
+ if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT:
+ address, length = data_or_wLength.buffer_info()
+ length *= data_or_wLength.itemsize
+ return _check(_lib.usb_control_msg(
+ dev_handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ cast(address, c_char_p),
+ length,
+ timeout
+ ))
+ else:
+ data = _interop.as_array((0,) * data_or_wLength)
+ read = int(_check(_lib.usb_control_msg(
+ dev_handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ cast(data.buffer_info()[0],
+ c_char_p),
+ data_or_wLength,
+ timeout
+ )))
+ return data[:read]
+
+ @methodtrace(_logger)
+ def reset_device(self, dev_handle):
+ _check(_lib.usb_reset(dev_handle))
+
+ @methodtrace(_logger)
+ def detach_kernel_driver(self, dev_handle, intf):
+ _check(_lib.usb_detach_kernel_driver_np(dev_handle, intf))
+
+ def __write(self, fn, dev_handle, ep, intf, data, timeout):
+ address, length = data.buffer_info()
+ length *= data.itemsize
+ return int(_check(fn(
+ dev_handle,
+ ep,
+ cast(address, c_char_p),
+ length,
+ timeout
+ )))
+
+ def __read(self, fn, dev_handle, ep, intf, size, timeout):
+ data = _interop.as_array('\x00' * size)
+ address, length = data.buffer_info()
+ length *= data.itemsize
+ ret = int(_check(fn(
+ dev_handle,
+ ep,
+ cast(address, c_char_p),
+ length,
+ timeout
+ )))
+ return data[:ret]
+
+def get_backend():
+ global _lib
+ try:
+ if _lib is None:
+ _lib = _load_library()
+ _setup_prototypes(_lib)
+ _lib.usb_init()
+ return _LibUSB()
+ except Exception:
+ _logger.error('Error loading libusb 0.1 backend', exc_info=True)
+ return None
diff --git a/plugins/wedo_plugin/usb/backend/libusb1.py b/plugins/wedo_plugin/usb/backend/libusb1.py
new file mode 100644
index 0000000..5396092
--- /dev/null
+++ b/plugins/wedo_plugin/usb/backend/libusb1.py
@@ -0,0 +1,901 @@
+# Copyright (C) 2009-2013 Wander Lairson Costa
+#
+# The following terms apply to all files associated
+# with the software unless explicitly disclaimed in individual files.
+#
+# The authors hereby grant permission to use, copy, modify, distribute,
+# and license this software and its documentation for any purpose, provided
+# that existing copyright notices are retained in all copies and that this
+# notice is included verbatim in any distributions. No written agreement,
+# license, or royalty fee is required for any of the authorized uses.
+# Modifications to this software may be copyrighted by their authors
+# and need not follow the licensing terms described here, provided that
+# the new terms are clearly indicated on the first page of each file where
+# they apply.
+#
+# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+# MODIFICATIONS.
+
+from ctypes import *
+import ctypes.util
+import usb.util
+import sys
+import logging
+from usb._debug import methodtrace
+import usb._interop as _interop
+import errno
+import math
+from usb.core import USBError
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = [
+ 'get_backend',
+ 'LIBUSB_SUCESS',
+ 'LIBUSB_ERROR_IO',
+ 'LIBUSB_ERROR_INVALID_PARAM',
+ 'LIBUSB_ERROR_ACCESS',
+ 'LIBUSB_ERROR_NO_DEVICE',
+ 'LIBUSB_ERROR_NOT_FOUND',
+ 'LIBUSB_ERROR_BUSY',
+ 'LIBUSB_ERROR_TIMEOUT',
+ 'LIBUSB_ERROR_OVERFLOW',
+ 'LIBUSB_ERROR_PIPE',
+ 'LIBUSB_ERROR_INTERRUPTED',
+ 'LIBUSB_ERROR_NO_MEM',
+ 'LIBUSB_ERROR_NOT_SUPPORTED',
+ 'LIBUSB_ERROR_OTHER'
+ 'LIBUSB_TRANSFER_COMPLETED',
+ 'LIBUSB_TRANSFER_ERROR',
+ 'LIBUSB_TRANSFER_TIMED_OUT',
+ 'LIBUSB_TRANSFER_CANCELLED',
+ 'LIBUSB_TRANSFER_STALL',
+ 'LIBUSB_TRANSFER_NO_DEVICE',
+ 'LIBUSB_TRANSFER_OVERFLOW'
+ ]
+
+_logger = logging.getLogger('usb.backend.libusb1')
+
+# libusb.h
+
+# transfer_type codes
+# 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
+
+# return codes
+
+LIBUSB_SUCCESS = 0
+LIBUSB_ERROR_IO = -1
+LIBUSB_ERROR_INVALID_PARAM = -2
+LIBUSB_ERROR_ACCESS = -3
+LIBUSB_ERROR_NO_DEVICE = -4
+LIBUSB_ERROR_NOT_FOUND = -5
+LIBUSB_ERROR_BUSY = -6
+LIBUSB_ERROR_TIMEOUT = -7
+LIBUSB_ERROR_OVERFLOW = -8
+LIBUSB_ERROR_PIPE = -9
+LIBUSB_ERROR_INTERRUPTED = -10
+LIBUSB_ERROR_NO_MEM = -11
+LIBUSB_ERROR_NOT_SUPPORTED = -12
+LIBUSB_ERROR_OTHER = -99
+
+# map return codes to strings
+_str_error = {
+ LIBUSB_SUCCESS:'Success (no error)',
+ LIBUSB_ERROR_IO:'Input/output error',
+ LIBUSB_ERROR_INVALID_PARAM:'Invalid parameter',
+ LIBUSB_ERROR_ACCESS:'Access denied (insufficient permissions)',
+ LIBUSB_ERROR_NO_DEVICE:'No such device (it may have been disconnected)',
+ LIBUSB_ERROR_NOT_FOUND:'Entity not found',
+ LIBUSB_ERROR_BUSY:'Resource busy',
+ LIBUSB_ERROR_TIMEOUT:'Operation timed out',
+ LIBUSB_ERROR_OVERFLOW:'Overflow',
+ LIBUSB_ERROR_PIPE:'Pipe error',
+ LIBUSB_ERROR_INTERRUPTED:'System call interrupted (perhaps due to signal)',
+ LIBUSB_ERROR_NO_MEM:'Insufficient memory',
+ LIBUSB_ERROR_NOT_SUPPORTED:'Operation not supported or unimplemented on this platform',
+ LIBUSB_ERROR_OTHER:'Unknown error'
+}
+
+# map return code to errno values
+_libusb_errno = {
+ 0:None,
+ LIBUSB_ERROR_IO:errno.__dict__.get('EIO', None),
+ LIBUSB_ERROR_INVALID_PARAM:errno.__dict__.get('EINVAL', None),
+ LIBUSB_ERROR_ACCESS:errno.__dict__.get('EACCES', None),
+ LIBUSB_ERROR_NO_DEVICE:errno.__dict__.get('ENODEV', None),
+ LIBUSB_ERROR_NOT_FOUND:errno.__dict__.get('ENOENT', None),
+ LIBUSB_ERROR_BUSY:errno.__dict__.get('EBUSY', None),
+ LIBUSB_ERROR_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),
+ LIBUSB_ERROR_OVERFLOW:errno.__dict__.get('EOVERFLOW', None),
+ LIBUSB_ERROR_PIPE:errno.__dict__.get('EPIPE', None),
+ LIBUSB_ERROR_INTERRUPTED:errno.__dict__.get('EINTR', None),
+ LIBUSB_ERROR_NO_MEM:errno.__dict__.get('ENOMEM', None),
+ LIBUSB_ERROR_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),
+ LIBUSB_ERROR_OTHER:None
+}
+
+# Transfer status codes:
+# Note that this does not indicate
+# that the entire amount of requested data was transferred.
+LIBUSB_TRANSFER_COMPLETED = 0
+LIBUSB_TRANSFER_ERROR = 1
+LIBUSB_TRANSFER_TIMED_OUT = 2
+LIBUSB_TRANSFER_CANCELLED = 3
+LIBUSB_TRANSFER_STALL = 4
+LIBUSB_TRANSFER_NO_DEVICE = 5
+LIBUSB_TRANSFER_OVERFLOW = 6
+
+# map return codes to strings
+_str_transfer_error = {
+ LIBUSB_TRANSFER_COMPLETED:'Success (no error)',
+ LIBUSB_TRANSFER_ERROR:'Transfer failed',
+ LIBUSB_TRANSFER_TIMED_OUT:'Transfer timed out',
+ LIBUSB_TRANSFER_CANCELLED:'Transfer was cancelled',
+ LIBUSB_TRANSFER_STALL:'For bulk/interrupt endpoints: halt condition '\
+ 'detected (endpoint stalled). For control '\
+ 'endpoints: control request not supported.',
+ LIBUSB_TRANSFER_NO_DEVICE:'Device was disconnected',
+ LIBUSB_TRANSFER_OVERFLOW:'Device sent more data than requested'
+}
+
+# map transfer codes to errno codes
+_transfer_errno = {
+ LIBUSB_TRANSFER_COMPLETED:0,
+ LIBUSB_TRANSFER_ERROR:errno.__dict__.get('EIO', None),
+ LIBUSB_TRANSFER_TIMED_OUT:errno.__dict__.get('ETIMEDOUT', None),
+ LIBUSB_TRANSFER_CANCELLED:errno.__dict__.get('EAGAIN', None),
+ LIBUSB_TRANSFER_STALL:errno.__dict__.get('EIO', None),
+ LIBUSB_TRANSFER_NO_DEVICE:errno.__dict__.get('ENODEV', None),
+ LIBUSB_TRANSFER_OVERFLOW:errno.__dict__.get('EOVERFLOW', None)
+}
+
+# Data structures
+
+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', POINTER(c_ubyte)),
+ ('extra_length', c_int)]
+
+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', POINTER(_libusb_endpoint_descriptor)),
+ ('extra', POINTER(c_ubyte)),
+ ('extra_length', c_int)]
+
+class _libusb_interface(Structure):
+ _fields_ = [('altsetting', POINTER(_libusb_interface_descriptor)),
+ ('num_altsetting', c_int)]
+
+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),
+ ('bMaxPower', c_uint8),
+ ('interface', POINTER(_libusb_interface)),
+ ('extra', POINTER(c_ubyte)),
+ ('extra_length', c_int)]
+
+class _libusb_device_descriptor(Structure):
+ _fields_ = [('bLength', c_uint8),
+ ('bDescriptorType', c_uint8),
+ ('bcdUSB', c_uint16),
+ ('bDeviceClass', c_uint8),
+ ('bDeviceSubClass', c_uint8),
+ ('bDeviceProtocol', c_uint8),
+ ('bMaxPacketSize0', c_uint8),
+ ('idVendor', c_uint16),
+ ('idProduct', c_uint16),
+ ('bcdDevice', c_uint16),
+ ('iManufacturer', c_uint8),
+ ('iProduct', c_uint8),
+ ('iSerialNumber', c_uint8),
+ ('bNumConfigurations', c_uint8)]
+
+
+# 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_device_handle = c_void_p
+
+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),
+ ('flags', c_uint8),
+ ('endpoint', c_uint8),
+ ('type', c_uint8),
+ ('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)
+]
+
+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))
+
+_lib = None
+
+def _load_library():
+ if sys.platform != 'cygwin':
+ candidates = ('usb-1.0', 'libusb-1.0', 'usb')
+ for candidate in candidates:
+ if sys.platform == 'win32':
+ candidate = candidate + '.dll'
+
+ libname = ctypes.util.find_library(candidate)
+ if libname is not None: break
+ else:
+ # corner cases
+ # cygwin predefines library names with 'cyg' instead of 'lib'
+ try:
+ return CDLL('cygusb-1.0.dll')
+ except Exception:
+ _logger.error('Libusb 1.0 could not be loaded in cygwin', exc_info=True)
+
+ raise OSError('USB library could not be found')
+ # Windows backend uses stdcall calling convention
+ if sys.platform == 'win32':
+ l = WinDLL(libname)
+ else:
+ l = CDLL(libname)
+ # On FreeBSD 8/9, libusb 1.0 and libusb 0.1 are in the same shared
+ # object libusb.so, so if we found libusb library name, we must assure
+ # it is 1.0 version. We just try to get some symbol from 1.0 version
+ if not hasattr(l, 'libusb_init'):
+ raise OSError('USB library could not be found')
+ return l
+
+def _setup_prototypes(lib):
+ # void libusb_set_debug (libusb_context *ctx, int level)
+ lib.libusb_set_debug.argtypes = [c_void_p, c_int]
+
+ # int libusb_init (libusb_context **context)
+ lib.libusb_init.argtypes = [POINTER(c_void_p)]
+
+ # void libusb_exit (struct libusb_context *ctx)
+ lib.libusb_exit.argtypes = [c_void_p]
+
+ # ssize_t libusb_get_device_list (libusb_context *ctx,
+ # libusb_device ***list)
+ lib.libusb_get_device_list.argtypes = [
+ c_void_p,
+ POINTER(POINTER(c_void_p))
+ ]
+
+ # void libusb_free_device_list (libusb_device **list,
+ # int unref_devices)
+ lib.libusb_free_device_list.argtypes = [
+ POINTER(c_void_p),
+ c_int
+ ]
+
+ # libusb_device *libusb_ref_device (libusb_device *dev)
+ lib.libusb_ref_device.argtypes = [c_void_p]
+ lib.libusb_ref_device.restype = c_void_p
+
+ # void libusb_unref_device(libusb_device *dev)
+ lib.libusb_unref_device.argtypes = [c_void_p]
+
+ # int libusb_open(libusb_device *dev, libusb_device_handle **handle)
+ lib.libusb_open.argtypes = [c_void_p, POINTER(_libusb_device_handle)]
+
+ # void libusb_close(libusb_device_handle *dev_handle)
+ lib.libusb_close.argtypes = [_libusb_device_handle]
+
+ # int libusb_set_configuration(libusb_device_handle *dev,
+ # int configuration)
+ lib.libusb_set_configuration.argtypes = [_libusb_device_handle, c_int]
+
+ # int libusb_get_configuration(libusb_device_handle *dev,
+ # int *config)
+ lib.libusb_get_configuration.argtypes = [_libusb_device_handle, POINTER(c_int)]
+
+ # int libusb_claim_interface(libusb_device_handle *dev,
+ # int interface_number)
+ lib.libusb_claim_interface.argtypes = [_libusb_device_handle, c_int]
+
+ # int libusb_release_interface(libusb_device_handle *dev,
+ # int interface_number)
+ lib.libusb_release_interface.argtypes = [_libusb_device_handle, c_int]
+
+ # int libusb_set_interface_alt_setting(libusb_device_handle *dev,
+ # int interface_number,
+ # int alternate_setting)
+ lib.libusb_set_interface_alt_setting.argtypes = [
+ _libusb_device_handle,
+ c_int,
+ c_int
+ ]
+
+ # int libusb_reset_device (libusb_device_handle *dev)
+ lib.libusb_reset_device.argtypes = [_libusb_device_handle]
+
+ # int libusb_kernel_driver_active(libusb_device_handle *dev,
+ # int interface)
+ lib.libusb_kernel_driver_active.argtypes = [
+ _libusb_device_handle,
+ c_int
+ ]
+
+ # int libusb_detach_kernel_driver(libusb_device_handle *dev,
+ # int interface)
+ lib.libusb_detach_kernel_driver.argtypes = [
+ _libusb_device_handle,
+ c_int
+ ]
+
+ # int libusb_attach_kernel_driver(libusb_device_handle *dev,
+ # int interface)
+ lib.libusb_attach_kernel_driver.argtypes = [
+ _libusb_device_handle,
+ c_int
+ ]
+
+ # int libusb_get_device_descriptor(
+ # libusb_device *dev,
+ # struct libusb_device_descriptor *desc
+ # )
+ lib.libusb_get_device_descriptor.argtypes = [
+ c_void_p,
+ POINTER(_libusb_device_descriptor)
+ ]
+
+ # int libusb_get_config_descriptor(
+ # libusb_device *dev,
+ # uint8_t config_index,
+ # struct libusb_config_descriptor **config
+ # )
+ lib.libusb_get_config_descriptor.argtypes = [
+ c_void_p,
+ c_uint8,
+ POINTER(POINTER(_libusb_config_descriptor))
+ ]
+
+ # void libusb_free_config_descriptor(
+ # struct libusb_config_descriptor *config
+ # )
+ lib.libusb_free_config_descriptor.argtypes = [
+ POINTER(_libusb_config_descriptor)
+ ]
+
+ # int libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
+ # uint8_t desc_index,
+ # unsigned char *data,
+ # int length)
+ lib.libusb_get_string_descriptor_ascii.argtypes = [
+ _libusb_device_handle,
+ c_uint8,
+ POINTER(c_ubyte),
+ c_int
+ ]
+
+ # int libusb_control_transfer(libusb_device_handle *dev_handle,
+ # uint8_t bmRequestType,
+ # uint8_t bRequest,
+ # uint16_t wValue,
+ # uint16_t wIndex,
+ # unsigned char *data,
+ # uint16_t wLength,
+ # unsigned int timeout)
+ lib.libusb_control_transfer.argtypes = [
+ _libusb_device_handle,
+ c_uint8,
+ c_uint8,
+ c_uint16,
+ c_uint16,
+ POINTER(c_ubyte),
+ c_uint16,
+ c_uint
+ ]
+
+ #int libusb_bulk_transfer(
+ # struct libusb_device_handle *dev_handle,
+ # unsigned char endpoint,
+ # unsigned char *data,
+ # int length,
+ # int *transferred,
+ # unsigned int timeout
+ # )
+ lib.libusb_bulk_transfer.argtypes = [
+ _libusb_device_handle,
+ c_ubyte,
+ POINTER(c_ubyte),
+ c_int,
+ POINTER(c_int),
+ 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
+ # );
+ lib.libusb_interrupt_transfer.argtypes = [
+ _libusb_device_handle,
+ c_ubyte,
+ POINTER(c_ubyte),
+ c_int,
+ POINTER(c_int),
+ c_uint
+ ]
+
+ # libusb_transfer* libusb_alloc_transfer(int iso_packets);
+ lib.libusb_alloc_transfer.argtypes = [c_int]
+ lib.libusb_alloc_transfer.restype = POINTER(_libusb_transfer)
+
+ # void libusb_free_transfer(struct libusb_transfer *transfer)
+ lib.libusb_free_transfer.argtypes = [POINTER(_libusb_transfer)]
+
+ # int libusb_submit_transfer(struct libusb_transfer *transfer);
+ lib.libusb_submit_transfer.argtypes = [POINTER(_libusb_transfer)]
+
+ # void libusb_set_iso_packet_lengths(
+ # libusb_transfer* transfer,
+ # unsigned int length
+ # );
+ def libusb_set_iso_packet_lengths(transfer_p, length):
+ r"""This function is inline in the libusb.h file, so we must implement
+ it.
+
+ lib.libusb_set_iso_packet_lengths.argtypes = [
+ POINTER(_libusb_transfer),
+ c_int
+ ]
+ """
+ transfer = transfer_p.contents
+ for iso_packet_desc in _get_iso_packet_list(transfer):
+ iso_packet_desc.length = length
+ lib.libusb_set_iso_packet_lengths = libusb_set_iso_packet_lengths
+
+ #int libusb_get_max_iso_packet_size(libusb_device* dev,
+ # unsigned char endpoint);
+ lib.libusb_get_max_iso_packet_size.argtypes = [c_void_p,
+ c_ubyte]
+
+ # void libusb_fill_iso_transfer(
+ # struct libusb_transfer* transfer,
+ # libusb_device_handle* dev_handle,
+ # unsigned char endpoint,
+ # unsigned char* buffer,
+ # int length,
+ # int num_iso_packets,
+ # libusb_transfer_cb_fn callback,
+ # void * user_data,
+ # unsigned int timeout
+ # );
+ def libusb_fill_iso_transfer(_libusb_transfer_p, dev_handle, endpoint, buffer, length,
+ num_iso_packets, callback, user_data, timeout):
+ r"""This function is inline in the libusb.h file, so we must implement
+ it.
+
+ lib.libusb_fill_iso_transfer.argtypes = [
+ _libusb_transfer,
+ _libusb_device_handle,
+ c_ubyte,
+ POINTER(c_ubyte),
+ c_int,
+ c_int,
+ _libusb_transfer_cb_fn_p,
+ c_void_p,
+ c_uint
+ ]
+ """
+ transfer = _libusb_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
+ lib.libusb_fill_iso_transfer = libusb_fill_iso_transfer
+
+ # uint8_t libusb_get_bus_number(libusb_device *dev)
+ lib.libusb_get_bus_number.argtypes = [c_void_p]
+ lib.libusb_get_bus_number.restype = c_uint8
+
+ # uint8_t libusb_get_device_address(libusb_device *dev)
+ lib.libusb_get_device_address.argtypes = [c_void_p]
+ lib.libusb_get_device_address.restype = c_uint8
+
+ try:
+ # uint8_t libusb_get_port_number(libusb_device *dev)
+ lib.libusb_get_port_number.argtypes = [c_void_p]
+ lib.libusb_get_port_number.restype = c_uint8
+ except AttributeError:
+ pass
+
+ #int libusb_handle_events(libusb_context *ctx);
+ lib.libusb_handle_events.argtypes = [c_void_p]
+
+# check a libusb function call
+def _check(retval):
+ if isinstance(retval, int):
+ retval = c_int(retval)
+ if isinstance(retval, c_int):
+ if retval.value < 0:
+ ret = retval.value
+ raise USBError(_str_error[ret], ret, _libusb_errno[ret])
+ return retval
+
+# wrap a device
+class _Device(object):
+ def __init__(self, devid):
+ self.devid = _lib.libusb_ref_device(devid)
+ def __del__(self):
+ _lib.libusb_unref_device(self.devid)
+
+# wrap a descriptor and keep a reference to another object
+# Thanks to Thomas Reitmayr.
+class _WrapDescriptor(object):
+ def __init__(self, desc, obj = None):
+ self.obj = obj
+ self.desc = desc
+ def __getattr__(self, name):
+ return getattr(self.desc, name)
+
+# wrap a configuration descriptor
+class _ConfigDescriptor(object):
+ def __init__(self, desc):
+ self.desc = desc
+ def __del__(self):
+ _lib.libusb_free_config_descriptor(self.desc)
+ def __getattr__(self, name):
+ return getattr(self.desc.contents, name)
+
+
+# iterator for libusb devices
+class _DevIterator(object):
+ def __init__(self, ctx):
+ self.dev_list = POINTER(c_void_p)()
+ self.num_devs = _check(_lib.libusb_get_device_list(
+ ctx,
+ byref(self.dev_list))
+ ).value
+ def __iter__(self):
+ for i in range(self.num_devs):
+ yield _Device(self.dev_list[i])
+ def __del__(self):
+ _lib.libusb_free_device_list(self.dev_list, 1)
+
+class _DeviceHandle(object):
+ def __init__(self, dev):
+ self.handle = _libusb_device_handle()
+ self.devid = dev.devid
+ _check(_lib.libusb_open(self.devid, byref(self.handle)))
+
+class _IsoTransferHandler(object):
+ def __init__(self, dev_handle, ep, buff, timeout):
+ address, length = buff.buffer_info()
+
+ packet_length = _lib.libusb_get_max_iso_packet_size(dev_handle.devid, ep)
+ packet_count = int(math.ceil(float(length) / packet_length))
+
+ self.transfer = _lib.libusb_alloc_transfer(packet_count)
+
+ _lib.libusb_fill_iso_transfer(self.transfer,
+ dev_handle.handle,
+ ep,
+ cast(address, POINTER(c_ubyte)),
+ length,
+ packet_count,
+ _libusb_transfer_cb_fn_p(self.__callback),
+ None,
+ timeout)
+
+ self.__set_packets_length(length, packet_length)
+
+ def __del__(self):
+ _lib.libusb_free_transfer(self.transfer)
+
+ def submit(self, ctx = None):
+ self.__callback_done = 0
+ _check(_lib.libusb_submit_transfer(self.transfer))
+
+ while not self.__callback_done:
+ _check(_lib.libusb_handle_events(ctx))
+
+ return self.__compute_size_transf_data()
+
+ def __compute_size_transf_data(self):
+ return sum([t.actual_length for t in
+ _get_iso_packet_list(self.transfer.contents)])
+
+ def __set_packets_length(self, n, packet_length):
+ _lib.libusb_set_iso_packet_lengths(self.transfer, packet_length)
+ r = n % packet_length
+ if r:
+ iso_packets = _get_iso_packet_list(self.transfer.contents)
+ iso_packets[-1].length = r
+
+ def __callback(self, transfer):
+ if transfer.contents.status == LIBUSB_TRANSFER_COMPLETED:
+ self.__callback_done = 1
+ else:
+ status = int(transfer.contents.status)
+ raise usb.USBError(_str_transfer_error[status],
+ status,
+ _transfer_errno[status])
+
+# implementation of libusb 1.0 backend
+class _LibUSB(usb.backend.IBackend):
+ @methodtrace(_logger)
+ def __init__(self, lib):
+ usb.backend.IBackend.__init__(self)
+ self.lib = lib
+ self.ctx = c_void_p()
+ _check(self.lib.libusb_init(byref(self.ctx)))
+
+ @methodtrace(_logger)
+ def __del__(self):
+ self.lib.libusb_exit(self.ctx)
+
+
+ @methodtrace(_logger)
+ def enumerate_devices(self):
+ return _DevIterator(self.ctx)
+
+ @methodtrace(_logger)
+ def get_device_descriptor(self, dev):
+ dev_desc = _libusb_device_descriptor()
+ _check(self.lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc)))
+ dev_desc.bus = self.lib.libusb_get_bus_number(dev.devid)
+ dev_desc.address = self.lib.libusb_get_device_address(dev.devid)
+
+ #Only available i newer versions of libusb
+ try:
+ dev_desc.port_number = self.lib.libusb_get_port_number(dev.devid)
+ except AttributeError:
+ dev_desc.port_number = None
+
+ return dev_desc
+
+ @methodtrace(_logger)
+ def get_configuration_descriptor(self, dev, config):
+ cfg = POINTER(_libusb_config_descriptor)()
+ _check(self.lib.libusb_get_config_descriptor(
+ dev.devid,
+ config, byref(cfg)))
+ return _ConfigDescriptor(cfg)
+
+ @methodtrace(_logger)
+ def get_interface_descriptor(self, dev, intf, alt, config):
+ cfg = self.get_configuration_descriptor(dev, config)
+ if intf >= cfg.bNumInterfaces:
+ raise IndexError('Invalid interface index ' + str(intf))
+ i = cfg.interface[intf]
+ if alt >= i.num_altsetting:
+ raise IndexError('Invalid alternate setting index ' + str(alt))
+ return _WrapDescriptor(i.altsetting[alt], cfg)
+
+ @methodtrace(_logger)
+ def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
+ i = self.get_interface_descriptor(dev, intf, alt, config)
+ if ep > i.bNumEndpoints:
+ raise IndexError('Invalid endpoint index ' + str(ep))
+ return _WrapDescriptor(i.endpoint[ep], i)
+
+ @methodtrace(_logger)
+ def open_device(self, dev):
+ return _DeviceHandle(dev)
+
+ @methodtrace(_logger)
+ def close_device(self, dev_handle):
+ self.lib.libusb_close(dev_handle.handle)
+
+ @methodtrace(_logger)
+ def set_configuration(self, dev_handle, config_value):
+ _check(self.lib.libusb_set_configuration(dev_handle.handle, config_value))
+
+ @methodtrace(_logger)
+ def get_configuration(self, dev_handle):
+ config = c_int()
+ _check(self.lib.libusb_get_configuration(dev_handle.handle, byref(config)))
+ return config.value
+
+ @methodtrace(_logger)
+ def set_interface_altsetting(self, dev_handle, intf, altsetting):
+ _check(self.lib.libusb_set_interface_alt_setting(
+ dev_handle.handle,
+ intf,
+ altsetting))
+
+ @methodtrace(_logger)
+ def claim_interface(self, dev_handle, intf):
+ _check(self.lib.libusb_claim_interface(dev_handle.handle, intf))
+
+ @methodtrace(_logger)
+ def release_interface(self, dev_handle, intf):
+ _check(self.lib.libusb_release_interface(dev_handle.handle, intf))
+
+ @methodtrace(_logger)
+ def bulk_write(self, dev_handle, ep, intf, data, timeout):
+ return self.__write(self.lib.libusb_bulk_transfer,
+ dev_handle,
+ ep,
+ intf,
+ data,
+ timeout)
+
+ @methodtrace(_logger)
+ def bulk_read(self, dev_handle, ep, intf, size, timeout):
+ return self.__read(self.lib.libusb_bulk_transfer,
+ dev_handle,
+ ep,
+ intf,
+ size,
+ timeout)
+
+ @methodtrace(_logger)
+ def intr_write(self, dev_handle, ep, intf, data, timeout):
+ return self.__write(self.lib.libusb_interrupt_transfer,
+ dev_handle,
+ ep,
+ intf,
+ data,
+ timeout)
+
+ @methodtrace(_logger)
+ def intr_read(self, dev_handle, ep, intf, size, timeout):
+ return self.__read(self.lib.libusb_interrupt_transfer,
+ dev_handle,
+ ep,
+ intf,
+ size,
+ timeout)
+
+ @methodtrace(_logger)
+ def iso_write(self, dev_handle, ep, intf, data, timeout):
+ handler = _IsoTransferHandler(dev_handle, ep, data, timeout)
+ return handler.submit(self.ctx)
+
+ @methodtrace(_logger)
+ def iso_read(self, dev_handle, ep, intf, size, timeout):
+ data = _interop.as_array('\x00' * size)
+ handler = _IsoTransferHandler(dev_handle, ep, data, timeout)
+ return data[:handler.submit(self.ctx)]
+
+ @methodtrace(_logger)
+ def ctrl_transfer(self,
+ dev_handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ data_or_wLength,
+ timeout):
+ if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT:
+ buff = data_or_wLength
+ else:
+ buff = _interop.as_array((0,) * data_or_wLength)
+
+ addr, length = buff.buffer_info()
+ length *= buff.itemsize
+
+ ret = _check(self.lib.libusb_control_transfer(
+ dev_handle.handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ cast(addr, POINTER(c_ubyte)),
+ length,
+ timeout))
+
+ if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT:
+ return ret.value
+ else:
+ return buff[:ret.value]
+
+ @methodtrace(_logger)
+ def reset_device(self, dev_handle):
+ _check(self.lib.libusb_reset_device(dev_handle.handle))
+
+ @methodtrace(_logger)
+ def is_kernel_driver_active(self, dev_handle, intf):
+ return bool(_check(self.lib.libusb_kernel_driver_active(dev_handle.handle,
+ intf)))
+
+ @methodtrace(_logger)
+ def detach_kernel_driver(self, dev_handle, intf):
+ _check(self.lib.libusb_detach_kernel_driver(dev_handle.handle, intf))
+
+ @methodtrace(_logger)
+ def attach_kernel_driver(self, dev_handle, intf):
+ _check(self.lib.libusb_attach_kernel_driver(dev_handle.handle, intf))
+
+ def __write(self, fn, dev_handle, ep, intf, data, timeout):
+ address, length = data.buffer_info()
+ length *= data.itemsize
+ transferred = c_int()
+ retval = fn(dev_handle.handle,
+ ep,
+ cast(address, POINTER(c_ubyte)),
+ length,
+ byref(transferred),
+ timeout)
+ # do not assume LIBUSB_ERROR_TIMEOUT means no I/O.
+ if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT):
+ _check(retval)
+
+ return transferred.value
+
+ def __read(self, fn, dev_handle, ep, intf, size, timeout):
+ data = _interop.as_array('\x00' * size)
+ address, length = data.buffer_info()
+ length *= data.itemsize
+ transferred = c_int()
+ retval = fn(dev_handle.handle,
+ ep,
+ cast(address, POINTER(c_ubyte)),
+ length,
+ byref(transferred),
+ timeout)
+ # do not assume LIBUSB_ERROR_TIMEOUT means no I/O.
+ if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT):
+ _check(retval)
+ return data[:transferred.value]
+
+def get_backend():
+ global _lib
+ try:
+ if _lib is None:
+ _lib = _load_library()
+ _setup_prototypes(_lib)
+ return _LibUSB(_lib)
+ except Exception:
+ _logger.error('Error loading libusb 1.0 backend', exc_info=True)
+ return None
diff --git a/plugins/wedo_plugin/usb/backend/openusb.py b/plugins/wedo_plugin/usb/backend/openusb.py
index 23e4d45..3398c4a 100644
--- a/plugins/wedo_plugin/usb/backend/openusb.py
+++ b/plugins/wedo_plugin/usb/backend/openusb.py
@@ -1,8 +1,8 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
-#
+# Copyright (C) 2009-2013 Wander Lairson Costa
+#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
-#
+#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
@@ -12,13 +12,13 @@
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
-#
+#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
+#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
@@ -32,6 +32,8 @@ import usb.util
from usb._debug import methodtrace
import logging
import errno
+import sys
+import usb._interop as _interop
__author__ = 'Wander Lairson Costa'
@@ -187,7 +189,7 @@ class _usb_device_desc(Structure):
class _openusb_request_result(Structure):
_fields_ = [('status', c_int32),
- ('transfered_bytes', c_uint32)]
+ ('transferred_bytes', c_uint32)]
class _openusb_ctrl_request(Structure):
class _openusb_ctrl_setup(Structure):
@@ -195,7 +197,8 @@ class _openusb_ctrl_request(Structure):
('bRequest', c_uint8),
('wValue', c_uint16),
('wIndex', c_uint16)]
- _fields_ = [('payload', POINTER(c_uint8)),
+ _fields_ = [('setup', _openusb_ctrl_setup),
+ ('payload', POINTER(c_uint8)),
('length', c_uint32),
('timeout', c_uint32),
('flags', c_uint32),
@@ -243,7 +246,12 @@ _lib = None
_ctx = None
def _load_library():
- libname = ctypes.util.find_library('openusb')
+ candidate = 'openusb'
+ # Workaround for CPython 3.3 issue#16283 / pyusb #14
+ if sys.platform == 'win32':
+ candidate = candidate + '.dll'
+
+ libname = ctypes.util.find_library(candidate)
if libname is None:
raise OSError('USB library could not be found')
return CDLL(libname)
@@ -396,7 +404,7 @@ def _setup_prototypes(lib):
]
lib.openusb_parse_interface_desc.restype = c_int32
-
+
# int32_t openusb_parse_endpoint_desc(openusb_handle_t handle,
# openusb_devid_t devid,
# uint8_t *buffer,
@@ -477,7 +485,10 @@ def _setup_prototypes(lib):
lib.openusb_isoc_xfer.restype = c_int32
def _check(retval):
- ret = retval.value
+ if isinstance(retval, c_int):
+ ret = retval.value
+ else:
+ ret = retval
if ret != 0:
from usb.core import USBError
raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret])
@@ -492,7 +503,7 @@ class _Context(object):
class _BusIterator(object):
def __init__(self):
- self.buslist = POINTER(openusb_busid)()
+ self.buslist = POINTER(_openusb_busid)()
num_busids = c_uint32()
_check(_lib.openusb_get_busid_list(_ctx.handle,
byref(self.buslist),
@@ -536,6 +547,7 @@ class _OpenUSB(usb.backend.IBackend):
byref(desc)))
desc.bus = None
desc.address = None
+ desc.port_number = None
return desc
@methodtrace(_logger)
@@ -598,7 +610,7 @@ class _OpenUSB(usb.backend.IBackend):
@methodtrace(_logger)
def set_interface_altsetting(self, dev_handle, intf, altsetting):
- _check(_lib.set_altsetting(dev_handle, intf, altsetting))
+ _check(_lib.openusb_set_altsetting(dev_handle, intf, altsetting))
@methodtrace(_logger)
def claim_interface(self, dev_handle, intf):
@@ -612,20 +624,22 @@ class _OpenUSB(usb.backend.IBackend):
def bulk_write(self, dev_handle, ep, intf, data, timeout):
request = _openusb_bulk_request()
memset(byref(request), 0, sizeof(request))
- request.payload, request.length = data.buffer_info()
+ payload, request.length = data.buffer_info()
+ request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
- return request.transfered_bytes.value
+ return request.result.transferred_bytes
@methodtrace(_logger)
def bulk_read(self, dev_handle, ep, intf, size, timeout):
request = _openusb_bulk_request()
- buffer = array.array('B', '\x00' * size)
+ buffer = _interop.as_array('\x00' * size)
memset(byref(request), 0, sizeof(request))
- request.payload, request.length = buffer.buffer_info()
+ payload, request.length = buffer.buffer_info()
+ request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
- return buffer[:request.transfered_bytes.value]
+ return buffer[:request.result.transferred_bytes]
@methodtrace(_logger)
def intr_write(self, dev_handle, ep, intf, data, timeout):
@@ -635,18 +649,18 @@ class _OpenUSB(usb.backend.IBackend):
request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
- return request.transfered_bytes.value
+ return request.result.transferred_bytes
@methodtrace(_logger)
def intr_read(self, dev_handle, ep, intf, size, timeout):
request = _openusb_intr_request()
- buffer = array.array('B', '\x00' * size)
+ buffer = _interop.as_array('B', '\x00' * size)
memset(byref(request), 0, sizeof(request))
payload, request.length = buffer.buffer_info()
request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
- return buffer[:request.transfered_bytes.value]
+ return buffer[:request.result.transferred_bytes]
# TODO: implement isochronous
# @methodtrace(_logger)
@@ -675,20 +689,20 @@ class _OpenUSB(usb.backend.IBackend):
direction = usb.util.ctrl_direction(bmRequestType)
- if direction == ENDPOINT_OUT:
+ if direction == usb.util.CTRL_OUT:
buffer = data_or_wLength
else:
- buffer = array.array('B', '\x00' * data_or_wLength)
+ buffer = _interop.as_array('\x00' * data_or_wLength)
payload, request.length = buffer.buffer_info()
request.payload = cast(payload, POINTER(c_uint8))
- ret = _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request)))
+ _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request)))
- if direction == ENDPOINT_OUT:
- ret
+ if direction == usb.util.CTRL_OUT:
+ return request.result.transferred_bytes
else:
- buffer[:ret]
+ return buffer[:request.result.transferred_bytes]
@methodtrace(_logger)
def reset_device(self, dev_handle):
diff --git a/plugins/wedo_plugin/usb/control.py b/plugins/wedo_plugin/usb/control.py
index 8647c14..c7726da 100644
--- a/plugins/wedo_plugin/usb/control.py
+++ b/plugins/wedo_plugin/usb/control.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
+# Copyright (C) 2009-2013 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
diff --git a/plugins/wedo_plugin/usb/core.py b/plugins/wedo_plugin/usb/core.py
index c90d011..e2509b8 100644
--- a/plugins/wedo_plugin/usb/core.py
+++ b/plugins/wedo_plugin/usb/core.py
@@ -1,8 +1,8 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
-#
+# Copyright (C) 2009-2013 Wander Lairson Costa
+#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
-#
+#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
@@ -12,13 +12,13 @@
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
-#
+#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
+#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
@@ -53,7 +53,7 @@ _DEFAULT_TIMEOUT = 1000
def _set_attr(input, output, fields):
for f in fields:
- setattr(output, f, int(getattr(input, f)))
+ setattr(output, f, getattr(input, f))
class _ResourceManager(object):
def __init__(self, dev, backend):
@@ -125,12 +125,12 @@ class _ResourceManager(object):
self._claimed_intf.remove(i)
def managed_set_interface(self, device, intf, alt):
- if intf is None:
- i = self.get_interface(device, intf)
- elif isinstance(intf, Interface):
+ if isinstance(intf, Interface):
i = intf
else:
cfg = self.get_active_configuration(device)
+ if intf is None:
+ intf = cfg[(0,0)].bInterfaceNumber
if alt is not None:
i = util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=alt)
else:
@@ -144,13 +144,12 @@ class _ResourceManager(object):
def get_interface(self, device, intf):
# TODO: check the viability of issuing a GET_INTERFACE
# request when we don't have a alternate setting cached
- if intf is None:
- cfg = self.get_active_configuration(device)
- return cfg[(0,0)]
- elif isinstance(intf, Interface):
+ if isinstance(intf, Interface):
return intf
else:
cfg = self.get_active_configuration(device)
+ if intf is None:
+ intf = cfg[(0,0)].bInterfaceNumber
if intf in self._alt_set:
return util.find_descriptor(cfg,
bInterfaceNumber=intf,
@@ -197,7 +196,7 @@ class _ResourceManager(object):
class USBError(IOError):
r"""Exception class for USB errors.
-
+
Backends must raise this exception when USB related errors occur.
The backend specific error code is available through the
'backend_error_code' member variable.
@@ -276,7 +275,7 @@ class Endpoint(object):
def write(self, data, timeout = None):
r"""Write data to the endpoint.
-
+
The parameter data contains the data to be sent to the endpoint and
timeout is the time limit of the operation. The transfer type and
endpoint address are automatically inferred.
@@ -289,7 +288,7 @@ class Endpoint(object):
def read(self, size, timeout = None):
r"""Read data from the endpoint.
-
+
The parameter size is the number of bytes to read and timeout is the
time limit of the operation.The transfer type and endpoint address
are automatically inferred.
@@ -388,7 +387,7 @@ class Interface(object):
class Configuration(object):
r"""Represent a configuration object.
-
+
This class contains all fields of the Configuration Descriptor
according to the USB Specification. You may access them as class
properties. For example, to access the field bConfigurationValue
@@ -461,7 +460,7 @@ class Configuration(object):
class Device(object):
r"""Device object.
-
+
This class contains all fields of the Device Descriptor according
to the USB Specification. You may access them as class properties.
For example, to access the field bDescriptorType of the device
@@ -528,16 +527,29 @@ class Device(object):
'iSerialNumber',
'bNumConfigurations',
'address',
- 'bus'
+ 'bus',
+ 'port_number'
)
)
- self.bus = int(desc.bus) if desc.bus is not None else None
- self.address = int(desc.address) if desc.address is not None else None
+ if desc.bus is not None:
+ self.bus = int(desc.bus)
+ else:
+ self.bus = None
+
+ if desc.address is not None:
+ self.address = int(desc.address)
+ else:
+ self.address = None
+
+ if desc.port_number is not None:
+ self.port_number = int(desc.port_number)
+ else:
+ self.port_number = None
def set_configuration(self, configuration = None):
r"""Set the active configuration.
-
+
The configuration parameter is the bConfigurationValue field of the
configuration you want to set as active. If you call this method
without parameter, it will use the first configuration found.
@@ -552,7 +564,7 @@ class Device(object):
def set_interface_altsetting(self, interface = None, alternate_setting = None):
r"""Set the alternate setting for an interface.
-
+
When you want to use an interface and it has more than one alternate setting,
you should call this method to select the alternate setting you would like
to use. If you call the method without one or the two parameters, it will
@@ -578,6 +590,7 @@ class Device(object):
def reset(self):
r"""Reset the device."""
+ self._ctx.managed_open()
self._ctx.dispose(self, False)
self._ctx.backend.reset_device(self._ctx.handle)
self._ctx.dispose(self, True)
@@ -590,7 +603,8 @@ class Device(object):
communicate with. The interface parameter is the bInterfaceNumber field
of the interface descriptor which contains the endpoint. If you do not
provide one, the first one found will be used, as explained in the
- set_interface_altsetting() method.
+ set_interface_altsetting() method. The bInterfaceNumber parameter is
+ not used for most backends, and often can be ignored.
The data parameter should be a sequence like type convertible to
array type (see array module).
@@ -627,8 +641,10 @@ class Device(object):
communicate with. The interface parameter is the bInterfaceNumber field
of the interface descriptor which contains the endpoint. If you do not
provide one, the first one found will be used, as explained in the
- set_interface_altsetting() method. The size parameters tells how many
- bytes you want to read.
+ set_interface_altsetting() method. The bInterfaceNumber parameter is
+ not used for most backends, and often can be ignored.
+
+ The size parameter tells how many bytes you want to read.
The timeout is specified in miliseconds.
@@ -701,7 +717,8 @@ class Device(object):
If a kernel driver is active, and the object will be unable to perform I/O.
"""
self._ctx.managed_open()
- return self._ctx.backend.is_kernel_driver_active(self._ctx.handle, interface)
+ return self._ctx.backend.is_kernel_driver_active(self._ctx.handle,
+ self._ctx.get_interface(self, interface).bInterfaceNumber)
def detach_kernel_driver(self, interface):
r"""Detach a kernel driver.
@@ -709,13 +726,15 @@ class Device(object):
If successful, you will then be able to perform I/O.
"""
self._ctx.managed_open()
- self._ctx.backend.detach_kernel_driver(self._ctx.handle, interface)
+ self._ctx.backend.detach_kernel_driver(self._ctx.handle,
+ self._ctx.get_interface(self, interface).bInterfaceNumber)
def attach_kernel_driver(self, interface):
r"""Re-attach an interface's kernel driver, which was previously
detached using detach_kernel_driver()."""
self._ctx.managed_open()
- self._ctx.backend.attach_kernel_driver(self._ctx.handle, interface)
+ self._ctx.backend.attach_kernel_driver(self._ctx.handle,
+ self._ctx.get_interface(self, interface).bInterfaceNumber)
def __iter__(self):
r"""Iterate over all configurations of the device."""
@@ -820,8 +839,7 @@ def find(find_all=False, backend = None, custom_match = None, **args):
def device_iter(k, v):
for dev in backend.enumerate_devices():
d = Device(dev, backend)
- if (custom_match is None or custom_match(d)) and \
- _interop._reduce(
+ if _interop._reduce(
lambda a, b: a and b,
map(
operator.eq,
@@ -829,15 +847,15 @@ def find(find_all=False, backend = None, custom_match = None, **args):
map(lambda i: getattr(d, i), k)
),
True
- ):
+ ) and (custom_match is None or custom_match(d)):
yield d
if backend is None:
- import usb.backend.libusb10 as libusb10
- import usb.backend.libusb01 as libusb01
+ import usb.backend.libusb1 as libusb1
+ import usb.backend.libusb0 as libusb0
import usb.backend.openusb as openusb
- for m in (libusb10, openusb, libusb01):
+ for m in (libusb1, openusb, libusb0):
backend = m.get_backend()
if backend is not None:
_logger.info('find(): using backend "%s"', m.__name__)
@@ -846,7 +864,7 @@ def find(find_all=False, backend = None, custom_match = None, **args):
raise ValueError('No backend available')
k, v = args.keys(), args.values()
-
+
if find_all:
return [d for d in device_iter(k, v)]
else:
diff --git a/plugins/wedo_plugin/usb/legacy.py b/plugins/wedo_plugin/usb/legacy.py
index 0c9c52c..ebe9f4d 100644
--- a/plugins/wedo_plugin/usb/legacy.py
+++ b/plugins/wedo_plugin/usb/legacy.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
+# Copyright (C) 2009-2013 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
@@ -222,8 +222,10 @@ class DeviceHandle(object):
Arguments:
interface: interface number or an Interface object.
"""
- if_num = interface.interfaceNumber \
- if isinstance(interface, Interface) else interface
+ if isinstance(interface, Interface):
+ if_num = interface.interfaceNumber
+ else:
+ if_num = interface
util.claim_interface(self.dev, if_num)
self.__claimed_interface = if_num
@@ -301,7 +303,11 @@ class Device(object):
self.deviceClass = dev.bDeviceClass
self.deviceSubClass = dev.bDeviceSubClass
self.deviceProtocol = dev.bDeviceProtocol
- self.deviceVersion = dev.bcdDevice
+ self.deviceVersion = str((dev.bcdDevice >> 12) & 0xf) + \
+ str((dev.bcdDevice >> 8) & 0xf) + \
+ '.' + \
+ str((dev.bcdDevice >> 4) & 0xf) + \
+ str(dev.bcdDevice & 0xf)
self.devnum = None
self.filename = ''
self.iManufacturer = dev.iManufacturer
@@ -310,7 +316,11 @@ class Device(object):
self.idProduct = dev.idProduct
self.idVendor = dev.idVendor
self.maxPacketSize = dev.bMaxPacketSize0
- self.usbVersion = dev.bcdUSB
+ self.usbVersion = str((dev.bcdUSB >> 12) & 0xf) + \
+ str((dev.bcdUSB >> 8) & 0xf) + \
+ '.' + \
+ str((dev.bcdUSB >> 4) & 0xf) + \
+ str(dev.bcdUSB & 0xf)
self.configurations = [Configuration(c) for c in dev]
self.dev = dev
@@ -323,12 +333,14 @@ class Device(object):
class Bus(object):
r"""Bus object."""
- def __init__(self):
+ def __init__(self, devices):
self.dirname = ''
- self.localtion = 0
- self.devices = [Device(d) for d in core.find(find_all=True)]
+ self.location = 0
+ self.devices = [Device(d) for d in devices]
def busses():
r"""Return a tuple with the usb busses."""
- return (Bus(),)
+ return (Bus(g) for k, g in _interop._groupby(
+ _interop._sorted(core.find(find_all=True), key=lambda d: d.bus),
+ lambda d: d.bus))
diff --git a/plugins/wedo_plugin/usb/util.py b/plugins/wedo_plugin/usb/util.py
index 1f8cee3..53bcae3 100644
--- a/plugins/wedo_plugin/usb/util.py
+++ b/plugins/wedo_plugin/usb/util.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Wander Lairson Costa
+# Copyright (C) 2009-2013 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
@@ -224,7 +224,7 @@ def get_string(dev, length, index, langid = None):
dev is the Device object to which the request will be
sent to.
- length is the length of string in number of characters.
+ length is the maximum length of the string in number of characters.
index is the string descriptor index and langid is the Language
ID of the descriptor. If langid is omitted, the string descriptor
@@ -243,7 +243,7 @@ def get_string(dev, length, index, langid = None):
# Note from libusb 1.0 sources (descriptor.c)
buf = get_descriptor(
dev,
- 1024,
+ 254,
DESC_TYPE_STRING,
0
)
@@ -257,4 +257,4 @@ def get_string(dev, length, index, langid = None):
index,
langid
)
- return buf[2:].tostring().decode('utf-16-le')
+ return buf[2:buf[0]].tostring().decode('utf-16-le')