Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/wedo_plugin/WeDoMore.py154
-rw-r--r--plugins/wedo_plugin/__init__.py0
-rw-r--r--plugins/wedo_plugin/icons/WeDooff.svg71
-rw-r--r--plugins/wedo_plugin/icons/WeDoon.svg71
-rw-r--r--plugins/wedo_plugin/usb/__init__.py92
-rw-r--r--plugins/wedo_plugin/usb/_debug.py77
-rw-r--r--plugins/wedo_plugin/usb/_interop.py135
-rw-r--r--plugins/wedo_plugin/usb/backend/__init__.py368
-rw-r--r--plugins/wedo_plugin/usb/backend/libusb01.py582
-rw-r--r--plugins/wedo_plugin/usb/backend/libusb10.py654
-rw-r--r--plugins/wedo_plugin/usb/backend/openusb.py707
-rw-r--r--plugins/wedo_plugin/usb/control.py252
-rw-r--r--plugins/wedo_plugin/usb/core.py856
-rw-r--r--plugins/wedo_plugin/usb/legacy.py334
-rw-r--r--plugins/wedo_plugin/usb/util.py260
-rw-r--r--plugins/wedo_plugin/wedo_plugin.py126
16 files changed, 4739 insertions, 0 deletions
diff --git a/plugins/wedo_plugin/WeDoMore.py b/plugins/wedo_plugin/WeDoMore.py
new file mode 100644
index 0000000..cbc84e2
--- /dev/null
+++ b/plugins/wedo_plugin/WeDoMore.py
@@ -0,0 +1,154 @@
+#Copyright (c) 2011, 2012, Ian Daniher
+#Copyright (c) 2012, Tony Forster, Walter Bender
+#
+# This program 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.
+#
+# This program 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import os
+sys.path.append(os.path.dirname(__file__))
+import usb.core
+import logging
+
+TILT_FORWARD = 0
+TILT_LEFT = 1
+TILT_RIGHT = 2
+TILT_BACK = 3
+NO_TILT = -1
+
+
+class WeDo:
+ def __init__(self):
+ """Find a USB device with the VID and PID of the Lego
+ WeDo. If the HID kernel driver is active, detatch
+ it."""
+ self.dev = usb.core.find(idVendor=0x0694, idProduct=0x0003)
+ if self.dev is None:
+ logging.debug("No Lego WeDo found")
+ else:
+ if self.dev.is_kernel_driver_active(0):
+ try:
+ self.dev.detach_kernel_driver(0)
+ except usb.core.USBError as e:
+ sys.exit("Could not detatch kernel driver: %s" % str(e))
+ self.valMotorA = 0
+ self.valMotorB = 0
+
+ def getRawData(self):
+ """Read 64 bytes from the WeDo's endpoint, but only
+ return the last eight."""
+ self.endpoint = self.dev[0][(0,0)][0]
+ data = list(self.endpoint.read(64)[-8:])
+ return data
+
+ def processMotorValues(self, value):
+ """Check to make sure motor values are sane."""
+ retValue = int(value)
+ if 0 < value < 101:
+ retValue += 27
+ elif -101 < value < 0:
+ retValue -= 27
+ elif value == 0:
+ retValue = 0
+ return retValue
+
+ def setMotors(self, valMotorA, valMotorB):
+ """Arguments should be in form of a number between 0
+ and 100, positive or negative. Magic numbers used for
+ the ctrl_transfer derived from sniffing USB coms."""
+ if self.dev is None:
+ return
+ self.valMotorA = self.processMotorValues(valMotorA)
+ self.valMotorB = self.processMotorValues(valMotorB)
+ data = [64, self.valMotorA&0xFF,
+ self.valMotorB&0xFF, 0x00, 0x00, 0x00, 0x00, 0x00]
+ self.dev.ctrl_transfer(bmRequestType = 0x21, bRequest = 0x09,
+ wValue = 0x0200, wIndex = 0,
+ data_or_wLength = data)
+
+ def getData(self):
+ """Sensor data is contained in the 2nd and 4th byte,
+ with sensor IDs being contained in the 3rd and 5th
+ byte respectively."""
+ rawData = self.getRawData()
+ sensorData = {rawData[3]: rawData[2], rawData[5]: rawData[4]}
+ return sensorData
+
+ def processTilt(self, v):
+ """Use a series of elif/value-checks to process the
+ tilt sensor data."""
+ if v in [24, 25, 26, 27]:
+ return TILT_BACK
+ elif v in [73, 74, 75, 76]:
+ return TILT_RIGHT
+ elif v in [175, 176, 177, 178, 179, 180]:
+ return TILT_FORWARD
+ elif v in [229, 230]:
+ return TILT_LEFT
+ else:
+ return NO_TILT
+
+ def interpretData(self):
+ """This function contains all the magic-number
+ sensor/actuator IDs. It returns a list containing one
+ or two tuples of the form (name, value)."""
+ data = self.getData()
+ response = []
+ for num in data.keys():
+ if num in [0, 1, 2]:
+ response.append(('motor', 1))
+ elif num in [176, 177, 178, 179]:
+ response.append(('distance', data[num]-69))
+ elif num in [38, 39]:
+ response.append(('tilt', self.processTilt(
+ data[num])))
+ elif num in [238, 239]:
+ response.append(('motor', 0))
+ elif num in [228, 230]:
+ response.append(('normal', 1))
+ return response
+
+ def getTilt(self):
+ if self.dev is None:
+ return NO_TILT
+ data = self.getData()
+ for num in data.keys():
+ if num in [38, 39]:
+ return self.processTilt(data[num])
+ return NO_TILT
+
+ def getDistance(self):
+ if self.dev is None:
+ return 0
+ data = self.getData()
+ for num in data.keys():
+ if num in [176, 177, 178, 179]:
+ return data[num] - 69
+ return 0
+
+ def setMotorA(self, valMotorA):
+ self.setMotors(valMotorA, self.valMotorB)
+
+ def setMotorB(self, valMotorB):
+ self.setMotors(self.valMotorA, valMotorB)
+
+ def getMotorA(self):
+ if self.dev is None:
+ return 0
+ return self.valMotorA
+
+ def getMotorB(self):
+ if self.dev is None:
+ return 0
+ return self.valMotorB
diff --git a/plugins/wedo_plugin/__init__.py b/plugins/wedo_plugin/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/wedo_plugin/__init__.py
diff --git a/plugins/wedo_plugin/icons/WeDooff.svg b/plugins/wedo_plugin/icons/WeDooff.svg
new file mode 100644
index 0000000..cc43d44
--- /dev/null
+++ b/plugins/wedo_plugin/icons/WeDooff.svg
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="55"
+ height="55"
+ viewBox="0 0 55 55"
+ id="svg2"
+ xml:space="preserve"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="WeDooff.svg"><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="640"
+ inkscape:window-height="504"
+ id="namedview10"
+ showgrid="false"
+ inkscape:zoom="4.2909091"
+ inkscape:cx="27.5"
+ inkscape:cy="27.5"
+ inkscape:window-x="0"
+ inkscape:window-y="24"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg2" /><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 27.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="55 : 27.5 : 1"
+ inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+ id="perspective12" />
+
+
+
+
+ </defs><rect
+ width="55"
+ height="55"
+ x="0"
+ y="0"
+ id="rect3269"
+ style="fill:#282828;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
+ d="m 11.421095,15.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z"
+ id="path7"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ style="fill:#ffffff;fill-opacity:1"
+ id="path2823"
+ d="m 35.421095,15.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z" /><path
+ d="m 35.421095,39.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z"
+ id="path2825"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ style="fill:#ffffff;fill-opacity:1"
+ id="path2827"
+ d="m 11.421095,39.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z" /></svg>
diff --git a/plugins/wedo_plugin/icons/WeDoon.svg b/plugins/wedo_plugin/icons/WeDoon.svg
new file mode 100644
index 0000000..16d54d2
--- /dev/null
+++ b/plugins/wedo_plugin/icons/WeDoon.svg
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="55"
+ height="55"
+ viewBox="0 0 55 55"
+ id="svg2"
+ xml:space="preserve"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="WeDoon.svg"><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="640"
+ inkscape:window-height="504"
+ id="namedview10"
+ showgrid="false"
+ inkscape:zoom="4.2909091"
+ inkscape:cx="27.5"
+ inkscape:cy="27.5"
+ inkscape:window-x="0"
+ inkscape:window-y="24"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg2" /><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 27.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="55 : 27.5 : 1"
+ inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+ id="perspective12" />
+
+
+
+
+ </defs><rect
+ width="55"
+ height="55"
+ x="0"
+ y="0"
+ id="rect3269"
+ style="fill:#ffd200;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
+ d="m 11.421095,15.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z"
+ id="path7"
+ style="fill:#ff0000;fill-opacity:1" /><path
+ style="fill:#ff0000;fill-opacity:1"
+ id="path2823"
+ d="m 35.421095,15.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z" /><path
+ d="m 35.421095,39.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z"
+ id="path2825"
+ style="fill:#ff0000;fill-opacity:1" /><path
+ style="fill:#ff0000;fill-opacity:1"
+ id="path2827"
+ d="m 11.421095,39.380686 c 0,2.0569 1.66964,3.72654 3.72654,3.72654 2.05489,0 3.72453,-1.66964 3.72453,-3.72654 0,-2.05489 -1.66897,-3.72788 -3.72453,-3.72788 -2.0569,0 -3.72654,1.67299 -3.72654,3.72788 z" /></svg> \ No newline at end of file
diff --git a/plugins/wedo_plugin/usb/__init__.py b/plugins/wedo_plugin/usb/__init__.py
new file mode 100644
index 0000000..8909cf2
--- /dev/null
+++ b/plugins/wedo_plugin/usb/__init__.py
@@ -0,0 +1,92 @@
+# Copyright (C) 2009-2011 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.
+
+r"""PyUSB - Easy USB access in Python
+
+This package exports the following modules and subpackages:
+
+ core - the main USB implementation
+ legacy - the compatibility layer with 0.x version
+ backend - the support for backend implementations.
+
+Since version 1.0, main PyUSB implementation lives in the 'usb.core'
+module. New applications are encouraged to use it.
+"""
+
+import logging
+import os
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = ['legacy', 'core', 'backend', 'util']
+
+
+def _setup_log():
+ from usb import _debug
+ logger = logging.getLogger('usb')
+ debug_level = os.getenv('PYUSB_DEBUG_LEVEL')
+
+ if debug_level is not None:
+ _debug.enable_tracing(True)
+ filename = os.getenv('PYUSB_LOG_FILENAME')
+
+ LEVELS = {'debug': logging.DEBUG,
+ 'info': logging.INFO,
+ 'warning': logging.WARNING,
+ 'error': logging.ERROR,
+ 'critical': logging.CRITICAL}
+
+ level = LEVELS.get(debug_level, logging.CRITICAL + 10)
+ logger.setLevel(level = level)
+
+ try:
+ handler = logging.FileHandler(filename)
+ except:
+ handler = logging.StreamHandler()
+
+ fmt = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s')
+ handler.setFormatter(fmt)
+ logger.addHandler(handler)
+ else:
+ class NullHandler(logging.Handler):
+ def emit(self, record):
+ pass
+
+ # We set the log level to avoid delegation to the
+ # parent log handler (if there is one).
+ # Thanks to Chris Clark to pointing this out.
+ logger.setLevel(logging.CRITICAL + 10)
+
+ logger.addHandler(NullHandler())
+
+
+_setup_log()
+
+# We import all 'legacy' module symbols to provide compatility
+# with applications that use 0.x versions.
+from usb.legacy import *
diff --git a/plugins/wedo_plugin/usb/_debug.py b/plugins/wedo_plugin/usb/_debug.py
new file mode 100644
index 0000000..13b0ced
--- /dev/null
+++ b/plugins/wedo_plugin/usb/_debug.py
@@ -0,0 +1,77 @@
+# Copyright (C) 2009-2011 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.
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = ['methodtrace', 'functiontrace']
+
+import logging
+import usb._interop as _interop
+
+_enable_tracing = False
+
+def enable_tracing(enable):
+ global _enable_tracing
+ _enable_tracing = enable
+
+def _trace_function_call(logger, fname, *args, **named_args):
+ logger.debug(
+ # TODO: check if 'f' is a method or a free function
+ fname + '(' + \
+ ', '.join((str(val) for val in args)) + \
+ ', '.join((name + '=' + str(val) for name, val in named_args.items())) + ')'
+ )
+
+# decorator for methods calls tracing
+def methodtrace(logger):
+ def decorator_logging(f):
+ if not _enable_tracing:
+ return f
+ def do_trace(*args, **named_args):
+ # this if is just a optimization to avoid unecessary string formatting
+ if logging.DEBUG >= logger.getEffectiveLevel():
+ fn = type(args[0]).__name__ + '.' + f.__name__
+ _trace_function_call(logger, fn, *args[1:], **named_args)
+ return f(*args, **named_args)
+ _interop._update_wrapper(do_trace, f)
+ return do_trace
+ return decorator_logging
+
+# decorator for methods calls tracing
+def functiontrace(logger):
+ def decorator_logging(f):
+ if not _enable_tracing:
+ return f
+ def do_trace(*args, **named_args):
+ # this if is just a optimization to avoid unecessary string formatting
+ if logging.DEBUG >= logger.getEffectiveLevel():
+ _trace_function_call(logger, f.__name__, *args, **named_args)
+ return f(*args, **named_args)
+ _interop._update_wrapper(do_trace, f)
+ return do_trace
+ return decorator_logging
diff --git a/plugins/wedo_plugin/usb/_interop.py b/plugins/wedo_plugin/usb/_interop.py
new file mode 100644
index 0000000..6069d5e
--- /dev/null
+++ b/plugins/wedo_plugin/usb/_interop.py
@@ -0,0 +1,135 @@
+# Copyright (C) 2009-2011 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.
+
+# All the hacks necessary to assure compatibility across all
+# supported versions come here.
+# Please, note that there is one version check for each
+# hack we need to do, this makes maintenance easier... ^^
+
+import sys
+import array
+
+__all__ = ['_reduce', '_set', '_next', '_groupby', '_sorted', '_update_wrapper']
+
+# we support Python >= 2.3
+assert sys.hexversion >= 0x020300f0
+
+# On Python 3, reduce became a functools module function
+try:
+ import functools
+ _reduce = functools.reduce
+except (ImportError, AttributeError):
+ _reduce = reduce
+
+# we only have the builtin set type since 2.5 version
+try:
+ _set = set
+except NameError:
+ import sets
+ _set = sets.Set
+
+# On Python >= 2.6, we have the builtin next() function
+# On Python 2.5 and before, we have to call the iterator method next()
+def _next(iter):
+ try:
+ return next(iter)
+ except NameError:
+ return iter.next()
+
+# groupby is available only since 2.4 version
+try:
+ import itertools
+ _groupby = itertools.groupby
+except (ImportError, AttributeError):
+ # stolen from Python docs
+ class _groupby(object):
+ # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
+ # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
+ def __init__(self, iterable, key=None):
+ if key is None:
+ key = lambda x: x
+ self.keyfunc = key
+ self.it = iter(iterable)
+ self.tgtkey = self.currkey = self.currvalue = object()
+ def __iter__(self):
+ return self
+ def next(self):
+ while self.currkey == self.tgtkey:
+ self.currvalue = _next(self.it) # Exit on StopIteration
+ self.currkey = self.keyfunc(self.currvalue)
+ self.tgtkey = self.currkey
+ return (self.currkey, self._grouper(self.tgtkey))
+ def _grouper(self, tgtkey):
+ while self.currkey == tgtkey:
+ yield self.currvalue
+ self.currvalue = _next(self.it) # Exit on StopIteration
+ self.currkey = self.keyfunc(self.currvalue)
+
+# builtin sorted function is only availale since 2.4 version
+try:
+ _sorted = sorted
+except NameError:
+ def _sorted(l, key=None, reverse=False):
+ # sort function on Python 2.3 does not
+ # support 'key' parameter
+ class KeyToCmp(object):
+ def __init__(self, K):
+ self.key = K
+ def __call__(self, x, y):
+ kx = self.key(x)
+ ky = self.key(y)
+ if kx < ky:
+ return reverse and 1 or -1
+ elif kx > ky:
+ return reverse and -1 or 1
+ else:
+ return 0
+ tmp = list(l)
+ tmp.sort(KeyToCmp(key))
+ return tmp
+
+try:
+ import functools
+ _update_wrapper = functools.update_wrapper
+except (ImportError, AttributeError):
+ def _update_wrapper(wrapper, wrapped):
+ wrapper.__name__ = wrapped.__name__
+ wrapper.__module__ = wrapped.__module__
+ wrapper.__doc__ = wrapped.__doc__
+ wrapper.__dict__ = wrapped.__dict__
+
+def as_array(data=None):
+ if data is None:
+ return array.array('B')
+ 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)
+
diff --git a/plugins/wedo_plugin/usb/backend/__init__.py b/plugins/wedo_plugin/usb/backend/__init__.py
new file mode 100644
index 0000000..67ee00f
--- /dev/null
+++ b/plugins/wedo_plugin/usb/backend/__init__.py
@@ -0,0 +1,368 @@
+# Copyright (C) 2009-2011 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.
+
+r"""usb.backend - Backend interface.
+
+This module exports:
+
+IBackend - backend interface.
+
+Backends are Python objects which implement the IBackend interface.
+The easiest way to do so is inherinting from IBackend.
+
+PyUSB already provides backends for libusb versions 0.1 and 1.0,
+and OpenUSB library. Backends modules included with PyUSB are required to
+export the get_backend() function, which returns an instance of a backend
+object. You can provide your own customized backend if you
+want to. Bellow you find a skeleton of a backend implementation module:
+
+import usb.backend
+
+class MyBackend(usb.backend.IBackend):
+ pass
+
+def get_backend():
+ return MyBackend()
+
+You can use your customized backend by passing it as the backend parameter of the
+usb.core.find() function. For example:
+
+import custom_backend
+import usb.core
+
+myidVendor = 0xfffe
+myidProduct = 0x0001
+
+mybackend = custom_backend.get_backend()
+
+dev = usb.core.find(backend = mybackend, idProduct=myidProduct,
+ idVendor=myidVendor)
+
+For custom backends, you are not required to supply the get_backend() function,
+since the application code will instantiate the backend.
+
+If you do not provide a backend to the find() function, it will use one of the
+defaults backend according to its internal rules. For details, consult the
+find() function documentation.
+"""
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = ['IBackend', 'libusb01', 'libusb10', 'openusb']
+
+def _not_implemented(func):
+ raise NotImplementedError(func.__name__)
+
+class IBackend(object):
+ r"""Backend interface.
+
+ IBackend is the basic interface for backend implementations. By default,
+ the methods of the interface raise a NotImplementedError exception. A
+ backend implementation should replace the methods to provide the funcionality
+ necessary.
+
+ As Python is a dynamic typed language, you are not obligated to inherit from
+ IBackend: everything that bahaves like an IBackend is an IBackend. But you
+ are strongly recommended to do so, inheriting from IBackend provides consistent
+ default behavior.
+ """
+ def enumerate_devices(self):
+ r"""This function is required to return an iterable object which
+ yields an implementation defined device identification for each
+ USB device found in the system.
+
+ The device identification object is used as argument to other methods
+ of the interface.
+ """
+ _not_implemented(self.enumerate_devices)
+
+ def get_device_descriptor(self, dev):
+ r"""Return the device descriptor of the given device.
+
+ The object returned is required to have all the Device Descriptor
+ fields accessible as member variables. They must be convertible (but
+ not required to be equal) to the int type.
+
+ dev is an object yielded by the iterator returned by the enumerate_devices()
+ method.
+ """
+ _not_implemented(self.get_device_descriptor)
+
+ def get_configuration_descriptor(self, dev, config):
+ r"""Return a configuration descriptor of the given device.
+
+ The object returned is required to have all the Configuration Descriptor
+ fields acessible as member variables. They must be convertible (but
+ not required to be equal) to the int type.
+
+ The dev parameter is the already described device identification object.
+ config is the logical index of the configuration (not the bConfigurationValue
+ field). By "logical index" we mean the relative order of the configurations
+ returned by the peripheral as a result of GET_DESCRIPTOR request.
+ """
+ _not_implemented(self.get_configuration_descriptor)
+
+ def get_interface_descriptor(self, dev, intf, alt, config):
+ r"""Return an interface descriptor of the given device.
+
+ The object returned is required to have all the Interface Descriptor
+ fields accessible as member variables. They must be convertible (but
+ not required to be equal) to the int type.
+
+ The dev parameter is the already described device identification object.
+ The intf parameter is the interface logical index (not the bInterfaceNumber field)
+ and alt is the alternate setting logical index (not the bAlternateSetting value).
+ Not every interface has more than one alternate setting. In this case, the alt
+ parameter should be zero. config is the configuration logical index (not the
+ bConfigurationValue field).
+ """
+ _not_implemented(self.get_interface_descriptor)
+
+ def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
+ r"""Return an endpoint descriptor of the given device.
+
+ The object returned is required to have all the Endpoint Descriptor
+ fields acessible as member variables. They must be convertible (but
+ not required to be equal) to the int type.
+
+ The ep parameter is the endpoint logical index (not the bEndpointAddress
+ field) of the endpoint descriptor desired. intf, alt and config are the same
+ values already described in the get_interface_descriptor() method.
+ """
+ _not_implemented(self.get_endpoint_descriptor)
+
+ def open_device(self, dev):
+ r"""Open the device for data exchange.
+
+ This method opens the device identified by the dev parameter for communication.
+ This method must be called before calling any communication related method, such
+ as transfer methods.
+
+ It returns a handle identifying the communication instance. This handle must be
+ passed to the communication methods.
+ """
+ _not_implemented(self.open_device)
+
+ def close_device(self, dev_handle):
+ r"""Close the device handle.
+
+ This method closes the device communication channel and releases any
+ system resources related to it.
+ """
+ _not_implemented(self.close_device)
+
+ def set_configuration(self, dev_handle, config_value):
+ r"""Set the active device configuration.
+
+ This method should be called to set the active configuration
+ of the device. The dev_handle parameter is the value returned
+ by the open_device() method and the config_value parameter is the
+ bConfigurationValue field of the related configuration descriptor.
+ """
+ _not_implemented(self.set_configuration)
+
+ def get_configuration(self, dev_handle):
+ r"""Get the current active device configuration.
+
+ This method returns the bConfigurationValue of the currently
+ active configuration. Depending on the backend and the OS,
+ either a cached value may be returned or a control request may
+ be issued. The dev_handle parameter is the value returned by
+ the open_device method.
+ """
+ _not_implemented(self.get_configuration)
+
+ def set_interface_altsetting(self, dev_handle, intf, altsetting):
+ r"""Set the interface alternate setting.
+
+ This method should only be called when the interface has more than
+ one alternate setting. The dev_handle is the value returned by the
+ open_device() method. intf and altsetting are respectivelly the
+ bInterfaceNumber and bAlternateSetting fields of the related interface.
+ """
+ _not_implemented(self.set_interface_altsetting)
+
+ def claim_interface(self, dev_handle, intf):
+ r"""Claim the given interface.
+
+ Interface claiming is not related to USB spec itself, but it is
+ generally an necessary call of the USB libraries. It requests exclusive
+ access to the interface on the system. This method must be called
+ before using one of the transfer methods.
+
+ dev_handle is the value returned by the open_device() method and
+ intf is the bInterfaceNumber field of the desired interface.
+ """
+ _not_implemented(self.claim_interface)
+
+ def release_interface(self, dev_handle, intf):
+ r"""Release the claimed interface.
+
+ dev_handle and intf are the same parameters of the claim_interface
+ method.
+ """
+ _not_implemented(self.release_interface)
+
+ def bulk_write(self, dev_handle, ep, intf, data, timeout):
+ r"""Perform a bulk write.
+
+ dev_handle is the value returned by the open_device() method.
+ The ep parameter is the bEndpointAddress field whose endpoint
+ the data will be sent to. intf is the bInterfaceNumber field
+ of the interface containing the endpoint. The data parameter
+ is the data to be sent. It must be an instance of the array.array
+ class. The timeout parameter specifies a time limit to the operation
+ in miliseconds.
+
+ The method returns the number of bytes written.
+ """
+ _not_implemented(self.bulk_write)
+
+ def bulk_read(self, dev_handle, ep, intf, size, timeout):
+ r"""Perform a bulk read.
+
+ dev_handle is the value returned by the open_device() method.
+ The ep parameter is the bEndpointAddress field whose endpoint
+ the data will be received from. intf is the bInterfaceNumber field
+ of the interface containing the endpoint. The size parameter
+ is the number of bytes to be read. The timeout parameter specifies
+ a time limit to the operation in miliseconds.
+
+ The method returns an array.array object containing the data read.
+ """
+ _not_implemented(self.bulk_read)
+
+ def intr_write(self, dev_handle, ep, intf, data, timeout):
+ r"""Perform an interrupt write.
+
+ dev_handle is the value returned by the open_device() method.
+ The ep parameter is the bEndpointAddress field whose endpoint
+ the data will be sent to. intf is the bInterfaceNumber field
+ of the interface containing the endpoint. The data parameter
+ is the data to be sent. It must be an instance of the array.array
+ class. The timeout parameter specifies a time limit to the operation
+ in miliseconds.
+
+ The method returns the number of bytes written.
+ """
+ _not_implemented(self.intr_write)
+
+ def intr_read(self, dev_handle, ep, intf, size, timeout):
+ r"""Perform an interrut read.
+
+ dev_handle is the value returned by the open_device() method.
+ The ep parameter is the bEndpointAddress field whose endpoint
+ the data will be received from. intf is the bInterfaceNumber field
+ of the interface containing the endpoint. The size parameter
+ is the number of bytes to be read. The timeout parameter specifies
+ a time limit to the operation in miliseconds.
+
+ The method returns an array.array object containing the data read.
+ """
+ _not_implemented(self.intr_read)
+
+ def iso_write(self, dev_handle, ep, intf, data, timeout):
+ r"""Perform an isochronous write.
+
+ dev_handle is the value returned by the open_device() method.
+ The ep parameter is the bEndpointAddress field whose endpoint
+ the data will be sent to. intf is the bInterfaceNumber field
+ of the interface containing the endpoint. The data parameter
+ is the data to be sent.It must be an instance of the array.array
+ class. The timeout parameter specifies a time limit to the operation
+ in miliseconds.
+
+ The method returns the number of bytes written.
+ """
+ _not_implemented(self.iso_write)
+
+ def iso_read(self, dev_handle, ep, intf, size, timeout):
+ r"""Perform an isochronous read.
+
+ dev_handle is the value returned by the open_device() method.
+ The ep parameter is the bEndpointAddress field whose endpoint
+ the data will be received from. intf is the bInterfaceNumber field
+ of the interface containing the endpoint. The size parameter
+ is the number of bytes to be read. The timeout parameter specifies
+ a time limit to the operation in miliseconds.
+
+ The method returns an array.array object containing the data read.
+ """
+ _not_implemented(self.iso_read)
+
+ def ctrl_transfer(self,
+ dev_handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ data_or_wLength,
+ timeout):
+ r"""Perform a control transfer on the endpoint 0.
+
+ The direction of the transfer is inferred from the bmRequestType
+ field of the setup packet.
+
+ dev_handle is the value returned by the open_device() method.
+ bmRequestType, bRequest, wValue and wIndex are the same fields
+ of the setup packet. data_or_wLength is either the payload to be sent
+ to the device, if any, as an array.array object (None there is no
+ payload) for OUT requests in the data stage or the wLength field
+ specifying the number of bytes to read for IN requests in the data
+ stage. The timeout parameter specifies a time limit to the operation
+ in miliseconds.
+
+ Return the number of bytes written (for OUT transfers) or the data
+ read (for IN transfers), as an array.array object.
+ """
+ _not_implemented(self.ctrl_transfer)
+
+ def reset_device(self, dev_handle):
+ r"""Reset the device."""
+ _not_implemented(self.reset_device)
+
+ def is_kernel_driver_active(self, dev_handle, intf):
+ r"""Determine if a kernel driver is active on an interface.
+
+ If a kernel driver is active, you cannot claim the interface,
+ and the backend will be unable to perform I/O.
+ """
+ _not_implemented(self.is_kernel_driver_active)
+
+ def detach_kernel_driver(self, dev_handle, intf):
+ r"""Detach a kernel driver from an interface.
+
+ If successful, you will then be able to claim the interface
+ and perform I/O.
+ """
+ _not_implemented(self.detach_kernel_driver)
+
+ def attach_kernel_driver(self, dev_handle, intf):
+ r"""Re-attach an interface's kernel driver, which was previously
+ detached using detach_kernel_driver()."""
+ _not_implemented(self.attach_kernel_driver)
diff --git a/plugins/wedo_plugin/usb/backend/libusb01.py b/plugins/wedo_plugin/usb/backend/libusb01.py
new file mode 100644
index 0000000..cf344c0
--- /dev/null
+++ b/plugins/wedo_plugin/usb/backend/libusb01.py
@@ -0,0 +1,582 @@
+# Copyright (C) 2009-2011 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.libusb01')
+
+# usb.h
+
+_PC_PATH_MAX = 4
+
+if sys.platform != 'win32' and sys.platform != 'cygwin':
+ _PATH_MAX = os.pathconf('.', _PC_PATH_MAX)
+else:
+ _PATH_MAX = 511
+
+# 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
+
+_lib = None
+
+def _load_library():
+ if sys.platform != 'cygwin':
+ candidates = ('usb-0.1', 'usb', 'libusb0')
+ for candidate in candidates:
+ 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((0,) * 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/libusb10.py b/plugins/wedo_plugin/usb/backend/libusb10.py
new file mode 100644
index 0000000..cb2a566
--- /dev/null
+++ b/plugins/wedo_plugin/usb/backend/libusb10.py
@@ -0,0 +1,654 @@
+# Copyright (C) 2009-2011 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
+
+__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'
+ ]
+
+_logger = logging.getLogger('usb.backend.libusb10')
+
+# libusb.h
+
+# 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 = {
+ LIBUSB_SUCCESS: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
+}
+
+# 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)]
+
+_lib = None
+_init = None
+
+_libusb_device_handle = c_void_p
+
+def _load_library():
+ if sys.platform != 'cygwin':
+ candidates = ('usb-1.0', 'libusb-1.0', 'usb')
+ for candidate in candidates:
+ 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
+ ]
+
+ # 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
+
+
+
+# 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:
+ from usb.core import USBError
+ 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)
+
+# initialize and finalize the library
+class _Initializer(object):
+ def __init__(self):
+ _check(_lib.libusb_init(None))
+ def __del__(self):
+ _lib.libusb_exit(None)
+
+
+# iterator for libusb devices
+class _DevIterator(object):
+ def __init__(self):
+ self.dev_list = POINTER(c_void_p)()
+ self.num_devs = _check(_lib.libusb_get_device_list(
+ None,
+ 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)
+
+# implementation of libusb 1.0 backend
+class _LibUSB(usb.backend.IBackend):
+ @methodtrace(_logger)
+ def enumerate_devices(self):
+ return _DevIterator()
+
+ @methodtrace(_logger)
+ def get_device_descriptor(self, dev):
+ dev_desc = _libusb_device_descriptor()
+ _check(_lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc)))
+ dev_desc.bus = _lib.libusb_get_bus_number(dev.devid)
+ dev_desc.address = _lib.libusb_get_device_address(dev.devid)
+ return dev_desc
+
+ @methodtrace(_logger)
+ def get_configuration_descriptor(self, dev, config):
+ cfg = POINTER(_libusb_config_descriptor)()
+ _check(_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):
+ handle = _libusb_device_handle()
+ _check(_lib.libusb_open(dev.devid, byref(handle)))
+ return handle
+
+ @methodtrace(_logger)
+ def close_device(self, dev_handle):
+ _lib.libusb_close(dev_handle)
+
+ @methodtrace(_logger)
+ def set_configuration(self, dev_handle, config_value):
+ _check(_lib.libusb_set_configuration(dev_handle, config_value))
+
+ @methodtrace(_logger)
+ def get_configuration(self, dev_handle):
+ config = c_int()
+ _check(_lib.libusb_get_configuration(dev_handle, byref(config)))
+ return config.value
+
+ @methodtrace(_logger)
+ def set_interface_altsetting(self, dev_handle, intf, altsetting):
+ _check(_lib.libusb_set_interface_alt_setting(dev_handle,
+ intf,
+ altsetting))
+
+ @methodtrace(_logger)
+ def claim_interface(self, dev_handle, intf):
+ _check(_lib.libusb_claim_interface(dev_handle, intf))
+
+ @methodtrace(_logger)
+ def release_interface(self, dev_handle, intf):
+ _check(_lib.libusb_release_interface(dev_handle, intf))
+
+ @methodtrace(_logger)
+ def bulk_write(self, dev_handle, ep, intf, data, timeout):
+ return self.__write(_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(_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(_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(_lib.libusb_interrupt_transfer,
+ dev_handle,
+ ep,
+ intf,
+ size,
+ timeout)
+
+# TODO: implement isochronous
+# @methodtrace(_logger)
+# def iso_write(self, dev_handle, ep, intf, data, timeout):
+# pass
+
+
+# @methodtrace(_logger)
+# def iso_read(self, dev_handle, ep, intf, size, timeout):
+# pass
+
+ @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(_lib.libusb_control_transfer(dev_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(_lib.libusb_reset_device(dev_handle))
+
+ @methodtrace(_logger)
+ def is_kernel_driver_active(self, dev_handle, intf):
+ return bool(_check(_lib.libusb_kernel_driver_active(dev_handle, intf)))
+
+ @methodtrace(_logger)
+ def detach_kernel_driver(self, dev_handle, intf):
+ _check(_lib.libusb_detach_kernel_driver(dev_handle, intf))
+
+ @methodtrace(_logger)
+ def attach_kernel_driver(self, dev_handle, intf):
+ _check(_lib.libusb_attach_kernel_driver(dev_handle, intf))
+
+ def __write(self, fn, dev_handle, ep, intf, data, timeout):
+ address, length = data.buffer_info()
+ length *= data.itemsize
+ transferred = c_int()
+ _check(fn(dev_handle,
+ ep,
+ cast(address, POINTER(c_ubyte)),
+ length,
+ byref(transferred),
+ timeout))
+ return transferred.value
+
+ def __read(self, fn, dev_handle, ep, intf, size, timeout):
+ data = _interop.as_array((0,) * size)
+ address, length = data.buffer_info()
+ length *= data.itemsize
+ transferred = c_int()
+ _check(fn(dev_handle,
+ ep,
+ cast(address, POINTER(c_ubyte)),
+ length,
+ byref(transferred),
+ timeout))
+ return data[:transferred.value]
+
+def get_backend():
+ global _lib, _init
+ try:
+ if _lib is None:
+ _lib = _load_library()
+ _setup_prototypes(_lib)
+ _init = _Initializer()
+ return _LibUSB()
+ 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
new file mode 100644
index 0000000..23e4d45
--- /dev/null
+++ b/plugins/wedo_plugin/usb/backend/openusb.py
@@ -0,0 +1,707 @@
+# Copyright (C) 2009-2011 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
+from usb._debug import methodtrace
+import logging
+import errno
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = [
+ 'get_backend'
+ 'OPENUSB_SUCCESS'
+ 'OPENUSB_PLATFORM_FAILURE'
+ 'OPENUSB_NO_RESOURCES'
+ 'OPENUSB_NO_BANDWIDTH'
+ 'OPENUSB_NOT_SUPPORTED'
+ 'OPENUSB_HC_HARDWARE_ERROR'
+ 'OPENUSB_INVALID_PERM'
+ 'OPENUSB_BUSY'
+ 'OPENUSB_BADARG'
+ 'OPENUSB_NOACCESS'
+ 'OPENUSB_PARSE_ERROR'
+ 'OPENUSB_UNKNOWN_DEVICE'
+ 'OPENUSB_INVALID_HANDLE'
+ 'OPENUSB_SYS_FUNC_FAILURE'
+ 'OPENUSB_NULL_LIST'
+ 'OPENUSB_CB_CONTINUE'
+ 'OPENUSB_CB_TERMINATE'
+ 'OPENUSB_IO_STALL'
+ 'OPENUSB_IO_CRC_ERROR'
+ 'OPENUSB_IO_DEVICE_HUNG'
+ 'OPENUSB_IO_REQ_TOO_BIG'
+ 'OPENUSB_IO_BIT_STUFFING'
+ 'OPENUSB_IO_UNEXPECTED_PID'
+ 'OPENUSB_IO_DATA_OVERRUN'
+ 'OPENUSB_IO_DATA_UNDERRUN'
+ 'OPENUSB_IO_BUFFER_OVERRUN'
+ 'OPENUSB_IO_BUFFER_UNDERRUN'
+ 'OPENUSB_IO_PID_CHECK_FAILURE'
+ 'OPENUSB_IO_DATA_TOGGLE_MISMATCH'
+ 'OPENUSB_IO_TIMEOUT'
+ 'OPENUSB_IO_CANCELED'
+ ]
+
+_logger = logging.getLogger('usb.backend.openusb')
+
+OPENUSB_SUCCESS = 0
+OPENUSB_PLATFORM_FAILURE = -1
+OPENUSB_NO_RESOURCES = -2
+OPENUSB_NO_BANDWIDTH = -3
+OPENUSB_NOT_SUPPORTED = -4
+OPENUSB_HC_HARDWARE_ERROR = -5
+OPENUSB_INVALID_PERM = -6
+OPENUSB_BUSY = -7
+OPENUSB_BADARG = -8
+OPENUSB_NOACCESS = -9
+OPENUSB_PARSE_ERROR = -10
+OPENUSB_UNKNOWN_DEVICE = -11
+OPENUSB_INVALID_HANDLE = -12
+OPENUSB_SYS_FUNC_FAILURE = -13
+OPENUSB_NULL_LIST = -14
+OPENUSB_CB_CONTINUE = -20
+OPENUSB_CB_TERMINATE = -21
+OPENUSB_IO_STALL = -50
+OPENUSB_IO_CRC_ERROR = -51
+OPENUSB_IO_DEVICE_HUNG = -52
+OPENUSB_IO_REQ_TOO_BIG = -53
+OPENUSB_IO_BIT_STUFFING = -54
+OPENUSB_IO_UNEXPECTED_PID = -55
+OPENUSB_IO_DATA_OVERRUN = -56
+OPENUSB_IO_DATA_UNDERRUN = -57
+OPENUSB_IO_BUFFER_OVERRUN = -58
+OPENUSB_IO_BUFFER_UNDERRUN = -59
+OPENUSB_IO_PID_CHECK_FAILURE = -60
+OPENUSB_IO_DATA_TOGGLE_MISMATCH = -61
+OPENUSB_IO_TIMEOUT = -62
+OPENUSB_IO_CANCELED = -63
+
+_openusb_errno = {
+ OPENUSB_SUCCESS:None,
+ OPENUSB_PLATFORM_FAILURE:None,
+ OPENUSB_NO_RESOURCES:errno.__dict__.get('ENOMEM', None),
+ OPENUSB_NO_BANDWIDTH:None,
+ OPENUSB_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),
+ OPENUSB_HC_HARDWARE_ERROR:errno.__dict__.get('EIO', None),
+ OPENUSB_INVALID_PERM:errno.__dict__.get('EBADF', None),
+ OPENUSB_BUSY:errno.__dict__.get('EBUSY', None),
+ OPENUSB_BADARG:errno.__dict__.get('EINVAL', None),
+ OPENUSB_NOACCESS:errno.__dict__.get('EACCES', None),
+ OPENUSB_PARSE_ERROR:None,
+ OPENUSB_UNKNOWN_DEVICE:errno.__dict__.get('ENODEV', None),
+ OPENUSB_INVALID_HANDLE:errno.__dict__.get('EINVAL', None),
+ OPENUSB_SYS_FUNC_FAILURE:None,
+ OPENUSB_NULL_LIST:None,
+ OPENUSB_CB_CONTINUE:None,
+ OPENUSB_CB_TERMINATE:None,
+ OPENUSB_IO_STALL:errno.__dict__.get('EIO', None),
+ OPENUSB_IO_CRC_ERROR:errno.__dict__.get('EIO', None),
+ OPENUSB_IO_DEVICE_HUNG:errno.__dict__.get('EIO', None),
+ OPENUSB_IO_REQ_TOO_BIG:errno.__dict__.get('E2BIG', None),
+ OPENUSB_IO_BIT_STUFFING:None,
+ OPENUSB_IO_UNEXPECTED_PID:errno.__dict__.get('ESRCH', None),
+ OPENUSB_IO_DATA_OVERRUN:errno.__dict__.get('EOVERFLOW', None),
+ OPENUSB_IO_DATA_UNDERRUN:None,
+ OPENUSB_IO_BUFFER_OVERRUN:errno.__dict__.get('EOVERFLOW', None),
+ OPENUSB_IO_BUFFER_UNDERRUN:None,
+ OPENUSB_IO_PID_CHECK_FAILURE:None,
+ OPENUSB_IO_DATA_TOGGLE_MISMATCH:None,
+ OPENUSB_IO_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),
+ OPENUSB_IO_CANCELED:errno.__dict__.get('EINTR', None)
+}
+
+class _usb_endpoint_desc(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)]
+
+class _usb_interface_desc(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)]
+
+class _usb_config_desc(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)]
+
+class _usb_device_desc(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)]
+
+class _openusb_request_result(Structure):
+ _fields_ = [('status', c_int32),
+ ('transfered_bytes', c_uint32)]
+
+class _openusb_ctrl_request(Structure):
+ class _openusb_ctrl_setup(Structure):
+ _fields_ = [('bmRequestType', c_uint8),
+ ('bRequest', c_uint8),
+ ('wValue', c_uint16),
+ ('wIndex', c_uint16)]
+ _fields_ = [('payload', POINTER(c_uint8)),
+ ('length', c_uint32),
+ ('timeout', c_uint32),
+ ('flags', c_uint32),
+ ('result', _openusb_request_result),
+ ('next', c_void_p)]
+
+class _openusb_intr_request(Structure):
+ _fields_ = [('interval', c_uint16),
+ ('payload', POINTER(c_uint8)),
+ ('length', c_uint32),
+ ('timeout', c_uint32),
+ ('flags', c_uint32),
+ ('result', _openusb_request_result),
+ ('next', c_void_p)]
+
+class _openusb_bulk_request(Structure):
+ _fields_ = [('payload', POINTER(c_uint8)),
+ ('length', c_uint32),
+ ('timeout', c_uint32),
+ ('flags', c_uint32),
+ ('result', _openusb_request_result),
+ ('next', c_void_p)]
+
+class _openusb_isoc_pkts(Structure):
+ class _openusb_isoc_packet(Structure):
+ _fields_ = [('payload', POINTER(c_uint8)),
+ ('length', c_uint32)]
+ _fields_ = [('num_packets', c_uint32),
+ ('packets', POINTER(_openusb_isoc_packet))]
+
+class _openusb_isoc_request(Structure):
+ _fields_ = [('start_frame', c_uint32),
+ ('flags', c_uint32),
+ ('pkts', _openusb_isoc_pkts),
+ ('isoc_results', POINTER(_openusb_request_result)),
+ ('isoc_status', c_int32),
+ ('next', c_void_p)]
+
+_openusb_devid = c_uint64
+_openusb_busid = c_uint64
+_openusb_handle = c_uint64
+_openusb_dev_handle = c_uint64
+
+_lib = None
+_ctx = None
+
+def _load_library():
+ libname = ctypes.util.find_library('openusb')
+ if libname is None:
+ raise OSError('USB library could not be found')
+ return CDLL(libname)
+
+def _setup_prototypes(lib):
+ # int32_t openusb_init(uint32_t flags , openusb_handle_t *handle);
+ lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)]
+ lib.openusb_init.restype = c_int32
+
+ # void openusb_fini(openusb_handle_t handle );
+ lib.openusb_fini.argtypes = [_openusb_handle]
+
+ # uint32_t openusb_get_busid_list(openusb_handle_t handle,
+ # openusb_busid_t **busids,
+ # uint32_t *num_busids);
+ lib.openusb_get_busid_list.argtypes = [
+ _openusb_handle,
+ POINTER(POINTER(_openusb_busid)),
+ POINTER(c_uint32)
+ ]
+
+ # void openusb_free_busid_list(openusb_busid_t * busids);
+ lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)]
+
+ # uint32_t openusb_get_devids_by_bus(openusb_handle_t handle,
+ # openusb_busid_t busid,
+ # openusb_devid_t **devids,
+ # uint32_t *num_devids);
+ lib.openusb_get_devids_by_bus.argtypes = [
+ _openusb_handle,
+ _openusb_busid,
+ POINTER(POINTER(_openusb_devid)),
+ POINTER(c_uint32)
+ ]
+
+ lib.openusb_get_devids_by_bus.restype = c_int32
+
+ # void openusb_free_devid_list(openusb_devid_t * devids);
+ lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)]
+
+ # int32_t openusb_open_device(openusb_handle_t handle,
+ # openusb_devid_t devid ,
+ # uint32_t flags,
+ # openusb_dev_handle_t *dev);
+ lib.openusb_open_device.argtypes = [
+ _openusb_handle,
+ _openusb_devid,
+ c_uint32,
+ POINTER(_openusb_dev_handle)
+ ]
+
+ lib.openusb_open_device.restype = c_int32
+
+ # int32_t openusb_close_device(openusb_dev_handle_t dev);
+ lib.openusb_close_device.argtypes = [_openusb_dev_handle]
+ lib.openusb_close_device.restype = c_int32
+
+ # int32_t openusb_set_configuration(openusb_dev_handle_t dev,
+ # uint8_t cfg);
+ lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8]
+ lib.openusb_set_configuration.restype = c_int32
+
+ # int32_t openusb_get_configuration(openusb_dev_handle_t dev,
+ # uint8_t *cfg);
+ lib.openusb_get_configuration.argtypes = [_openusb_dev_handle, POINTER(c_uint8)]
+ lib.openusb_get_configuration.restype = c_int32
+
+ # int32_t openusb_claim_interface(openusb_dev_handle_t dev,
+ # uint8_t ifc,
+ # openusb_init_flag_t flags);
+ lib.openusb_claim_interface.argtypes = [
+ _openusb_dev_handle,
+ c_uint8,
+ c_int
+ ]
+
+ lib.openusb_claim_interface.restype = c_int32
+
+ # int32_t openusb_release_interface(openusb_dev_handle_t dev,
+ # uint8_t ifc);
+ lib.openusb_release_interface.argtypes = [
+ _openusb_dev_handle,
+ c_uint8
+ ]
+
+ lib.openusb_release_interface.restype = c_int32
+
+ # int32_topenusb_set_altsetting(openusb_dev_handle_t dev,
+ # uint8_t ifc,
+ # uint8_t alt);
+ lib.openusb_set_altsetting.argtypes = [
+ _openusb_dev_handle,
+ c_uint8,
+ c_uint8
+ ]
+ lib.openusb_set_altsetting.restype = c_int32
+
+ # int32_t openusb_reset(openusb_dev_handle_t dev);
+ lib.openusb_reset.argtypes = [_openusb_dev_handle]
+ lib.openusb_reset.restype = c_int32
+
+ # int32_t openusb_parse_device_desc(openusb_handle_t handle,
+ # openusb_devid_t devid,
+ # uint8_t *buffer,
+ # uint16_t buflen,
+ # usb_device_desc_t *devdesc);
+ lib.openusb_parse_device_desc.argtypes = [
+ _openusb_handle,
+ _openusb_devid,
+ POINTER(c_uint8),
+ c_uint16,
+ POINTER(_usb_device_desc)
+ ]
+
+ lib.openusb_parse_device_desc.restype = c_int32
+
+ # int32_t openusb_parse_config_desc(openusb_handle_t handle,
+ # openusb_devid_t devid,
+ # uint8_t *buffer,
+ # uint16_t buflen,
+ # uint8_t cfgidx,
+ # usb_config_desc_t *cfgdesc);
+ lib.openusb_parse_config_desc.argtypes = [
+ _openusb_handle,
+ _openusb_devid,
+ POINTER(c_uint8),
+ c_uint16,
+ c_uint8,
+ POINTER(_usb_config_desc)
+ ]
+ lib.openusb_parse_config_desc.restype = c_int32
+
+ # int32_t openusb_parse_interface_desc(openusb_handle_t handle,
+ # openusb_devid_t devid,
+ # uint8_t *buffer,
+ # uint16_t buflen,
+ # uint8_t cfgidx,
+ # uint8_t ifcidx,
+ # uint8_t alt,
+ # usb_interface_desc_t *ifcdesc);
+ lib.openusb_parse_interface_desc.argtypes = [
+ _openusb_handle,
+ _openusb_devid,
+ POINTER(c_uint8),
+ c_uint16,
+ c_uint8,
+ c_uint8,
+ c_uint8,
+ POINTER(_usb_interface_desc)
+ ]
+
+ 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,
+ # uint16_t buflen,
+ # uint8_t cfgidx,
+ # uint8_t ifcidx,
+ # uint8_t alt,
+ # uint8_t eptidx,
+ # usb_endpoint_desc_t *eptdesc);
+ lib.openusb_parse_endpoint_desc.argtypes = [
+ _openusb_handle,
+ _openusb_devid,
+ POINTER(c_uint8),
+ c_uint16,
+ c_uint8,
+ c_uint8,
+ c_uint8,
+ c_uint8,
+ POINTER(_usb_endpoint_desc)
+ ]
+
+ lib.openusb_parse_interface_desc.restype = c_int32
+
+ # const char *openusb_strerror(int32_t error );
+ lib.openusb_strerror.argtypes = [c_int32]
+ lib.openusb_strerror.restype = c_char_p
+
+ # int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev,
+ # uint8_t ifc,
+ # uint8_t ept,
+ # openusb_ctrl_request_t *ctrl);
+ lib.openusb_ctrl_xfer.argtypes = [
+ _openusb_dev_handle,
+ c_uint8,
+ c_uint8,
+ POINTER(_openusb_ctrl_request)
+ ]
+
+ lib.openusb_ctrl_xfer.restype = c_int32
+
+ # int32_t openusb_intr_xfer(openusb_dev_handle_t dev,
+ # uint8_t ifc,
+ # uint8_t ept,
+ # openusb_intr_request_t *intr);
+ lib.openusb_intr_xfer.argtypes = [
+ _openusb_dev_handle,
+ c_uint8,
+ c_uint8,
+ POINTER(_openusb_intr_request)
+ ]
+
+ lib.openusb_bulk_xfer.restype = c_int32
+
+ # int32_t openusb_bulk_xfer(openusb_dev_handle_t dev,
+ # uint8_t ifc,
+ # uint8_t ept,
+ # openusb_bulk_request_t *bulk);
+ lib.openusb_bulk_xfer.argtypes = [
+ _openusb_dev_handle,
+ c_uint8,
+ c_uint8,
+ POINTER(_openusb_bulk_request)
+ ]
+
+ lib.openusb_bulk_xfer.restype = c_int32
+
+ # int32_t openusb_isoc_xfer(openusb_dev_handle_t dev,
+ # uint8_t ifc,
+ # uint8_t ept,
+ # openusb_isoc_request_t *isoc);
+ lib.openusb_isoc_xfer.argtypes = [
+ _openusb_dev_handle,
+ c_uint8,
+ c_uint8,
+ POINTER(_openusb_isoc_request)
+ ]
+
+ lib.openusb_isoc_xfer.restype = c_int32
+
+def _check(retval):
+ ret = retval.value
+ if ret != 0:
+ from usb.core import USBError
+ raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret])
+ return retval
+
+class _Context(object):
+ def __init__(self):
+ self.handle = _openusb_handle()
+ _check(_lib.openusb_init(0, byref(self.handle)))
+ def __del__(self):
+ _lib.openusb_fini(self.handle)
+
+class _BusIterator(object):
+ def __init__(self):
+ self.buslist = POINTER(openusb_busid)()
+ num_busids = c_uint32()
+ _check(_lib.openusb_get_busid_list(_ctx.handle,
+ byref(self.buslist),
+ byref(num_busids)))
+ self.num_busids = num_busids.value
+ def __iter__(self):
+ for i in range(self.num_busids):
+ yield self.buslist[i]
+ def __del__(self):
+ _lib.openusb_free_busid_list(self.buslist)
+
+class _DevIterator(object):
+ def __init__(self, busid):
+ self.devlist = POINTER(_openusb_devid)()
+ num_devids = c_uint32()
+ _check(_lib.openusb_get_devids_by_bus(_ctx.handle,
+ busid,
+ byref(self.devlist),
+ byref(num_devids)))
+ self.num_devids = num_devids.value
+ def __iter__(self):
+ for i in range(self.num_devids):
+ yield self.devlist[i]
+ def __del__(self):
+ _lib.openusb_free_devid_list(self.devlist)
+
+class _OpenUSB(usb.backend.IBackend):
+ @methodtrace(_logger)
+ def enumerate_devices(self):
+ for bus in _BusIterator():
+ for devid in _DevIterator(bus):
+ yield devid
+
+ @methodtrace(_logger)
+ def get_device_descriptor(self, dev):
+ desc = _usb_device_desc()
+ _check(_lib.openusb_parse_device_desc(_ctx.handle,
+ dev,
+ None,
+ 0,
+ byref(desc)))
+ desc.bus = None
+ desc.address = None
+ return desc
+
+ @methodtrace(_logger)
+ def get_configuration_descriptor(self, dev, config):
+ desc = _usb_config_desc()
+ _check(_lib.openusb_parse_config_desc(_ctx.handle,
+ dev,
+ None,
+ 0,
+ config,
+ byref(desc)))
+ return desc
+
+ @methodtrace(_logger)
+ def get_interface_descriptor(self, dev, intf, alt, config):
+ desc = _usb_interface_desc()
+ _check(_lib.openusb_parse_interface_desc(_ctx.handle,
+ dev,
+ None,
+ 0,
+ config,
+ intf,
+ alt,
+ byref(desc)))
+ return desc
+
+ @methodtrace(_logger)
+ def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
+ desc = _usb_endpoint_desc()
+ _check(_lib.openusb_parse_endpoint_desc(_ctx.handle,
+ dev,
+ None,
+ 0,
+ config,
+ intf,
+ alt,
+ ep,
+ byref(desc)))
+ return desc
+
+ @methodtrace(_logger)
+ def open_device(self, dev):
+ handle = _openusb_dev_handle()
+ _check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle)))
+ return handle
+
+ @methodtrace(_logger)
+ def close_device(self, dev_handle):
+ _lib.openusb_close_device(dev_handle)
+
+ @methodtrace(_logger)
+ def set_configuration(self, dev_handle, config_value):
+ _check(_lib.openusb_set_configuration(dev_handle, config_value))
+
+ @methodtrace(_logger)
+ def get_configuration(self, dev_handle):
+ config = c_uint8()
+ _check(_lib.openusb_get_configuration(dev_handle, byref(config)))
+ return config.value
+
+ @methodtrace(_logger)
+ def set_interface_altsetting(self, dev_handle, intf, altsetting):
+ _check(_lib.set_altsetting(dev_handle, intf, altsetting))
+
+ @methodtrace(_logger)
+ def claim_interface(self, dev_handle, intf):
+ _check(_lib.openusb_claim_interface(dev_handle, intf, 0))
+
+ @methodtrace(_logger)
+ def release_interface(self, dev_handle, intf):
+ _lib.openusb_release_interface(dev_handle, intf)
+
+ @methodtrace(_logger)
+ 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()
+ request.timeout = timeout
+ _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
+ return request.transfered_bytes.value
+
+ @methodtrace(_logger)
+ def bulk_read(self, dev_handle, ep, intf, size, timeout):
+ request = _openusb_bulk_request()
+ buffer = array.array('B', '\x00' * size)
+ memset(byref(request), 0, sizeof(request))
+ request.payload, request.length = buffer.buffer_info()
+ request.timeout = timeout
+ _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
+ return buffer[:request.transfered_bytes.value]
+
+ @methodtrace(_logger)
+ def intr_write(self, dev_handle, ep, intf, data, timeout):
+ request = _openusb_intr_request()
+ memset(byref(request), 0, sizeof(request))
+ payload, request.length = data.buffer_info()
+ 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
+
+ @methodtrace(_logger)
+ def intr_read(self, dev_handle, ep, intf, size, timeout):
+ request = _openusb_intr_request()
+ buffer = array.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]
+
+# TODO: implement isochronous
+# @methodtrace(_logger)
+# def iso_write(self, dev_handle, ep, intf, data, timeout):
+# pass
+
+# @methodtrace(_logger)
+# def iso_read(self, dev_handle, ep, intf, size, timeout):
+# pass
+
+ @methodtrace(_logger)
+ def ctrl_transfer(self,
+ dev_handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ data_or_wLength,
+ timeout):
+ request = _openusb_ctrl_request()
+ request.setup.bmRequestType = bmRequestType
+ request.setup.bRequest = bRequest
+ request.setup.wValue
+ request.setup.wIndex
+ request.timeout = timeout
+
+ direction = usb.util.ctrl_direction(bmRequestType)
+
+ if direction == ENDPOINT_OUT:
+ buffer = data_or_wLength
+ else:
+ buffer = array.array('B', '\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)))
+
+ if direction == ENDPOINT_OUT:
+ ret
+ else:
+ buffer[:ret]
+
+ @methodtrace(_logger)
+ def reset_device(self, dev_handle):
+ _check(_lib.openusb_reset(dev_handle))
+
+def get_backend():
+ try:
+ global _lib, _ctx
+ if _lib is None:
+ _lib = _load_library()
+ _setup_prototypes(_lib)
+ _ctx = _Context()
+ return _OpenUSB()
+ except Exception:
+ _logger.error('Error loading OpenUSB backend', exc_info=True)
+ return None
diff --git a/plugins/wedo_plugin/usb/control.py b/plugins/wedo_plugin/usb/control.py
new file mode 100644
index 0000000..8647c14
--- /dev/null
+++ b/plugins/wedo_plugin/usb/control.py
@@ -0,0 +1,252 @@
+# Copyright (C) 2009-2011 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.
+
+r"""usb.control - USB standard control requests
+
+This module exports:
+
+get_status - get recipeint status
+clear_feature - clear a recipient feature
+set_feature - set a recipient feature
+get_descriptor - get a device descriptor
+set_descriptor - set a device descriptor
+get_configuration - get a device configuration
+set_configuration - set a device configuration
+get_interface - get a device interface
+set_interface - set a device interface
+"""
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = ['get_status',
+ 'clear_feature',
+ 'set_feature',
+ 'get_descriptor',
+ 'set_descriptor',
+ 'get_configuration',
+ 'set_configuration',
+ 'get_interface',
+ 'set_interface',
+ 'ENDPOINT_HALT',
+ 'FUNCTION_SUSPEND',
+ 'DEVICE_REMOTE_WAKEUP',
+ 'U1_ENABLE',
+ 'U2_ENABLE',
+ 'LTM_ENABLE']
+
+import usb.util as util
+import usb.core as core
+
+def _parse_recipient(recipient, direction):
+ if recipient is None:
+ r = util.CTRL_RECIPIENT_DEVICE
+ wIndex = 0
+ elif isinstance(recipient, core.Interface):
+ r = util.CTRL_RECIPIENT_INTERFACE
+ wIndex = recipient.bInterfaceNumber
+ elif isinstance(recipient, core.Endpoint):
+ r = util.CTRL_RECIPIENT_ENDPOINT
+ wIndex = recipient.bEndpointAddress
+ else:
+ raise ValueError('Invalid recipient.')
+ bmRequestType = util.build_request_type(
+ direction,
+ util.CTRL_TYPE_STANDARD,
+ r
+ )
+ return (bmRequestType, wIndex)
+
+# standard feature selectors from USB 2.0/3.0
+ENDPOINT_HALT = 0
+FUNCTION_SUSPEND = 0
+DEVICE_REMOTE_WAKEUP = 1
+U1_ENABLE = 48
+U2_ENABLE = 49
+LTM_ENABLE = 50
+
+def get_status(dev, recipient = None):
+ r"""Return the status for the specified recipient.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ The recipient can be None (on which the status will be queried
+ on the device), an Interface or Endpoint descriptors.
+
+ The status value is returned as an integer with the lower
+ word being the two bytes status value.
+ """
+ bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_IN)
+ ret = dev.ctrl_transfer(bmRequestType = bmRequestType,
+ bRequest = 0x00,
+ wIndex = wIndex,
+ data_or_wLength = 2)
+ return ret[0] | (ret[1] << 8)
+
+def clear_feature(dev, feature, recipient = None):
+ r"""Clear/disable a specific feature.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ feature is the feature you want to disable.
+
+ The recipient can be None (on which the status will be queried
+ on the device), an Interface or Endpoint descriptors.
+ """
+ bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT)
+ dev.ctrl_transfer(bmRequestType = bmRequestType,
+ bRequest = 0x01,
+ wIndex = wIndex,
+ wValue = feature)
+
+def set_feature(dev, feature, recipient = None):
+ r"""Set/enable a specific feature.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ feature is the feature you want to enable.
+
+ The recipient can be None (on which the status will be queried
+ on the device), an Interface or Endpoint descriptors.
+ """
+ bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT)
+ dev.ctrl_transfer(bmRequestType = bmRequestType,
+ bRequest = 0x03,
+ wIndex = wIndex,
+ wValue = feature)
+
+def get_descriptor(dev, desc_size, desc_type, desc_index, wIndex = 0):
+ r"""Return the specified descriptor.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ desc_size is the descriptor size.
+
+ desc_type and desc_index are the descriptor type and index,
+ respectively. wIndex index is used for string descriptors
+ and represents the Language ID. For other types of descriptors,
+ it is zero.
+ """
+ wValue = desc_index | (desc_type << 8)
+ bmRequestType = util.build_request_type(
+ util.CTRL_IN,
+ util.CTRL_TYPE_STANDARD,
+ util.CTRL_RECIPIENT_DEVICE
+ )
+ return dev.ctrl_transfer(
+ bmRequestType = bmRequestType,
+ bRequest = 0x06,
+ wValue = wValue,
+ wIndex = wIndex,
+ data_or_wLength = desc_size
+ )
+
+def set_descriptor(dev, desc, desc_type, desc_index, wIndex = None):
+ r"""Update an existing descriptor or add a new one.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ The desc parameter is the descriptor to be sent to the device.
+ desc_type and desc_index are the descriptor type and index,
+ respectively. wIndex index is used for string descriptors
+ and represents the Language ID. For other types of descriptors,
+ it is zero.
+ """
+ wValue = desc_index | (desc_type << 8)
+ bmRequestType = util.build_request_type(
+ util.CTRL_OUT,
+ util.CTRL_TYPE_STANDARD,
+ util.CTRL_RECIPIENT_DEVICE
+ )
+ dev.ctrl_transfer(
+ bmRequestType = bmRequestType,
+ bRequest = 0x07,
+ wValue = wValue,
+ wIndex = wIndex,
+ data_or_wLength = desc
+ )
+
+def get_configuration(dev):
+ r"""Get the current active configuration of the device.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ This function differs from the Device.get_active_configuration
+ method because the later may use cached data, while this
+ function always does a device request.
+ """
+ bmRequestType = util.build_request_type(
+ util.CTRL_IN,
+ util.CTRL_TYPE_STANDARD,
+ util.CTRL_RECIPIENT_DEVICE
+ )
+ return dev.ctrl_transfer(
+ bmRequestType,
+ bRequest = 0x08,
+ data_or_wLength = 1
+ )[0]
+
+def set_configuration(dev, bConfigurationNumber):
+ r"""Set the current device configuration.
+
+ dev is the Device object to which the request will be
+ sent to.
+ """
+ dev.set_configuration(bConfigurationNumber)
+
+def get_interface(dev, bInterfaceNumber):
+ r"""Get the current alternate setting of the interface.
+
+ dev is the Device object to which the request will be
+ sent to.
+ """
+ bmRequestType = util.build_request_type(
+ util.CTRL_IN,
+ util.CTRL_TYPE_STANDARD,
+ util.CTRL_RECIPIENT_INTERFACE
+ )
+ return dev.ctrl_transfer(
+ bmRequestType = bmRequestType,
+ bRequest = 0x0a,
+ wIndex = bInterfaceNumber,
+ data_or_wLength = 1
+ )[0]
+
+def set_interface(dev, bInterfaceNumber, bAlternateSetting):
+ r"""Set the alternate setting of the interface.
+
+ dev is the Device object to which the request will be
+ sent to.
+ """
+ dev.set_interface_altsetting(bInterfaceNumber, bAlternateSetting)
+
diff --git a/plugins/wedo_plugin/usb/core.py b/plugins/wedo_plugin/usb/core.py
new file mode 100644
index 0000000..c90d011
--- /dev/null
+++ b/plugins/wedo_plugin/usb/core.py
@@ -0,0 +1,856 @@
+# Copyright (C) 2009-2011 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.
+
+r"""usb.core - Core USB features.
+
+This module exports:
+
+Device - a class representing a USB device.
+Configuration - a class representing a configuration descriptor.
+Interface - a class representing an interface descriptor.
+Endpoint - a class representing an endpoint descriptor.
+find() - a function to find USB devices.
+"""
+
+__author__ = 'Wander Lairson Costa'
+
+__all__ = ['Device', 'Configuration', 'Interface', 'Endpoint', 'find']
+
+import usb.util as util
+import copy
+import operator
+import usb._interop as _interop
+import logging
+
+_logger = logging.getLogger('usb.core')
+
+_DEFAULT_TIMEOUT = 1000
+
+def _set_attr(input, output, fields):
+ for f in fields:
+ setattr(output, f, int(getattr(input, f)))
+
+class _ResourceManager(object):
+ def __init__(self, dev, backend):
+ self.backend = backend
+ self._active_cfg_index = None
+ self.dev = dev
+ self.handle = None
+ self._claimed_intf = _interop._set()
+ self._alt_set = {}
+ self._ep_type_map = {}
+
+ def managed_open(self):
+ if self.handle is None:
+ self.handle = self.backend.open_device(self.dev)
+ return self.handle
+
+ def managed_close(self):
+ if self.handle is not None:
+ self.backend.close_device(self.handle)
+ self.handle = None
+
+ def managed_set_configuration(self, device, config):
+ if config is None:
+ cfg = device[0]
+ elif isinstance(config, Configuration):
+ cfg = config
+ elif config == 0: # unconfigured state
+ class FakeConfiguration(object):
+ def __init__(self):
+ self.index = None
+ self.bConfigurationValue = 0
+ cfg = FakeConfiguration()
+ else:
+ cfg = util.find_descriptor(device, bConfigurationValue=config)
+ self.managed_open()
+ self.backend.set_configuration(self.handle, cfg.bConfigurationValue)
+ # cache the index instead of the object to avoid cyclic references
+ # of the device and Configuration (Device tracks the _ResourceManager,
+ # which tracks the Configuration, which tracks the Device)
+ self._active_cfg_index = cfg.index
+ # after changing configuration, our alternate setting and endpoint type caches
+ # are not valid anymore
+ self._ep_type_map.clear()
+ self._alt_set.clear()
+
+ def managed_claim_interface(self, device, intf):
+ self.managed_open()
+ if intf is None:
+ cfg = self.get_active_configuration(device)
+ i = cfg[(0,0)].bInterfaceNumber
+ elif isinstance(intf, Interface):
+ i = intf.bInterfaceNumber
+ else:
+ i = intf
+ if i not in self._claimed_intf:
+ self.backend.claim_interface(self.handle, i)
+ self._claimed_intf.add(i)
+
+ def managed_release_interface(self, device, intf):
+ if intf is None:
+ cfg = self.get_active_configuration(device)
+ i = cfg[(0,0)].bInterfaceNumber
+ elif isinstance(intf, Interface):
+ i = intf.bInterfaceNumber
+ else:
+ i = intf
+ if i in self._claimed_intf:
+ self.backend.release_interface(self.handle, i)
+ 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):
+ i = intf
+ else:
+ cfg = self.get_active_configuration(device)
+ if alt is not None:
+ i = util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=alt)
+ else:
+ i = util.find_descriptor(cfg, bInterfaceNumber=intf)
+ self.managed_claim_interface(device, i)
+ if alt is None:
+ alt = i.bAlternateSetting
+ self.backend.set_interface_altsetting(self.handle, i.bInterfaceNumber, alt)
+ self._alt_set[i.bInterfaceNumber] = alt
+
+ 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):
+ return intf
+ else:
+ cfg = self.get_active_configuration(device)
+ if intf in self._alt_set:
+ return util.find_descriptor(cfg,
+ bInterfaceNumber=intf,
+ bAlternateSetting=self._alt_set[intf])
+ else:
+ return util.find_descriptor(cfg, bInterfaceNumber=intf)
+
+ def get_active_configuration(self, device):
+ if self._active_cfg_index is None:
+ self.managed_open()
+ cfg = util.find_descriptor(
+ device,
+ bConfigurationValue=self.backend.get_configuration(self.handle)
+ )
+ if cfg is None:
+ raise USBError('Configuration not set')
+ self._active_cfg_index = cfg.index
+ return cfg
+ return device[self._active_cfg_index]
+
+ def get_endpoint_type(self, device, address, intf):
+ intf = self.get_interface(device, intf)
+ key = (address, intf.bInterfaceNumber, intf.bAlternateSetting)
+ try:
+ return self._ep_type_map[key]
+ except KeyError:
+ e = util.find_descriptor(intf, bEndpointAddress=address)
+ etype = util.endpoint_type(e.bmAttributes)
+ self._ep_type_map[key] = etype
+ return etype
+
+ def release_all_interfaces(self, device):
+ claimed = copy.copy(self._claimed_intf)
+ for i in claimed:
+ self.managed_release_interface(device, i)
+
+ def dispose(self, device, close_handle = True):
+ self.release_all_interfaces(device)
+ if close_handle:
+ self.managed_close()
+ self._ep_type_map.clear()
+ self._alt_set.clear()
+ self._active_cfg_index = None
+
+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.
+ """
+
+ def __init__(self, strerror, error_code = None, errno = None):
+ r"""Initialize the object.
+
+ This initializes the USBError object. The strerror and errno are passed
+ to the parent object. The error_code parameter is attributed to the
+ backend_error_code member variable.
+ """
+ IOError.__init__(self, errno, strerror)
+ self.backend_error_code = error_code
+
+class Endpoint(object):
+ r"""Represent an endpoint object.
+
+ This class contains all fields of the Endpoint Descriptor
+ according to the USB Specification. You may access them as class
+ properties. For example, to access the field bEndpointAddress
+ of the endpoint descriptor:
+
+ >>> import usb.core
+ >>> dev = usb.core.find()
+ >>> for cfg in dev:
+ >>> for i in cfg:
+ >>> for e in i:
+ >>> print e.bEndpointAddress
+ """
+
+ def __init__(self, device, endpoint, interface = 0,
+ alternate_setting = 0, configuration = 0):
+ r"""Initialize the Endpoint object.
+
+ The device parameter is the device object returned by the find()
+ function. endpoint is the endpoint logical index (not the endpoint address).
+ The configuration parameter is the logical index of the
+ configuration (not the bConfigurationValue field). The interface
+ parameter is the interface logical index (not the bInterfaceNumber field)
+ and alternate_setting is the alternate setting logical index (not the
+ bAlternateSetting value). Not every interface has more than one alternate
+ setting. In this case, the alternate_setting parameter should be zero.
+ By "logical index" we mean the relative order of the configurations returned by the
+ peripheral as a result of GET_DESCRIPTOR request.
+ """
+ self.device = device
+ intf = Interface(device, interface, alternate_setting, configuration)
+ self.interface = intf.bInterfaceNumber
+ self.index = endpoint
+
+ backend = device._ctx.backend
+
+ desc = backend.get_endpoint_descriptor(
+ device._ctx.dev,
+ endpoint,
+ interface,
+ alternate_setting,
+ configuration
+ )
+
+ _set_attr(
+ desc,
+ self,
+ (
+ 'bLength',
+ 'bDescriptorType',
+ 'bEndpointAddress',
+ 'bmAttributes',
+ 'wMaxPacketSize',
+ 'bInterval',
+ 'bRefresh',
+ 'bSynchAddress'
+ )
+ )
+
+ 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.
+
+ The method returns the number of bytes written.
+
+ For details, see the Device.write() method.
+ """
+ return self.device.write(self.bEndpointAddress, data, self.interface, timeout)
+
+ 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.
+
+ The method returns an array.array object with the data read.
+
+ For details, see the Device.read() method.
+ """
+ return self.device.read(self.bEndpointAddress, size, self.interface, timeout)
+
+class Interface(object):
+ r"""Represent an interface object.
+
+ This class contains all fields of the Interface Descriptor
+ according to the USB Specification. You may access them as class
+ properties. For example, to access the field bInterfaceNumber
+ of the interface descriptor:
+
+ >>> import usb.core
+ >>> dev = usb.core.find()
+ >>> for cfg in dev:
+ >>> for i in cfg:
+ >>> print i.bInterfaceNumber
+ """
+
+ def __init__(self, device, interface = 0,
+ alternate_setting = 0, configuration = 0):
+ r"""Initialize the interface object.
+
+ The device parameter is the device object returned by the find()
+ function. The configuration parameter is the logical index of the
+ configuration (not the bConfigurationValue field). The interface
+ parameter is the interface logical index (not the bInterfaceNumber field)
+ and alternate_setting is the alternate setting logical index (not the
+ bAlternateSetting value). Not every interface has more than one alternate
+ setting. In this case, the alternate_setting parameter should be zero.
+ By "logical index" we mean the relative order of the configurations returned by the
+ peripheral as a result of GET_DESCRIPTOR request.
+ """
+ self.device = device
+ self.alternate_index = alternate_setting
+ self.index = interface
+ self.configuration = configuration
+
+ backend = device._ctx.backend
+
+ desc = backend.get_interface_descriptor(
+ self.device._ctx.dev,
+ interface,
+ alternate_setting,
+ configuration
+ )
+
+ _set_attr(
+ desc,
+ self,
+ (
+ 'bLength',
+ 'bDescriptorType',
+ 'bInterfaceNumber',
+ 'bAlternateSetting',
+ 'bNumEndpoints',
+ 'bInterfaceClass',
+ 'bInterfaceSubClass',
+ 'bInterfaceProtocol',
+ 'iInterface',
+ )
+ )
+
+ def set_altsetting(self):
+ r"""Set the interface alternate setting."""
+ self.device.set_interface_altsetting(
+ self.bInterfaceNumber,
+ self.bAlternateSetting
+ )
+
+ def __iter__(self):
+ r"""Iterate over all endpoints of the interface."""
+ for i in range(self.bNumEndpoints):
+ yield Endpoint(
+ self.device,
+ i,
+ self.index,
+ self.alternate_index,
+ self.configuration
+ )
+ def __getitem__(self, index):
+ r"""Return the Endpoint object in the given position."""
+ return Endpoint(
+ self.device,
+ index,
+ self.index,
+ self.alternate_index,
+ self.configuration
+ )
+
+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
+ of the configuration descriptor:
+
+ >>> import usb.core
+ >>> dev = usb.core.find()
+ >>> for cfg in dev:
+ >>> print cfg.bConfigurationValue
+ """
+
+ def __init__(self, device, configuration = 0):
+ r"""Initialize the configuration object.
+
+ The device parameter is the device object returned by the find()
+ function. The configuration parameter is the logical index of the
+ configuration (not the bConfigurationValue field). By "logical index"
+ we mean the relative order of the configurations returned by the
+ peripheral as a result of GET_DESCRIPTOR request.
+ """
+ self.device = device
+ self.index = configuration
+
+ backend = device._ctx.backend
+
+ desc = backend.get_configuration_descriptor(
+ self.device._ctx.dev,
+ configuration
+ )
+
+ _set_attr(
+ desc,
+ self,
+ (
+ 'bLength',
+ 'bDescriptorType',
+ 'wTotalLength',
+ 'bNumInterfaces',
+ 'bConfigurationValue',
+ 'iConfiguration',
+ 'bmAttributes',
+ 'bMaxPower'
+ )
+ )
+
+ def set(self):
+ r"""Set this configuration as the active one."""
+ self.device.set_configuration(self.bConfigurationValue)
+
+ def __iter__(self):
+ r"""Iterate over all interfaces of the configuration."""
+ for i in range(self.bNumInterfaces):
+ alt = 0
+ try:
+ while True:
+ yield Interface(self.device, i, alt, self.index)
+ alt += 1
+ except (USBError, IndexError):
+ pass
+ def __getitem__(self, index):
+ r"""Return the Interface object in the given position.
+
+ index is a tuple of two values with interface index and
+ alternate setting index, respectivally. Example:
+
+ >>> interface = config[(0, 0)]
+ """
+ return Interface(self.device, index[0], index[1], self.index)
+
+
+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
+ descriptor:
+
+ >>> import usb.core
+ >>> dev = usb.core.find()
+ >>> dev.bDescriptorType
+
+ Additionally, the class provides methods to communicate with
+ the hardware. Typically, an application will first call the
+ set_configuration() method to put the device in a known configured
+ state, optionally call the set_interface_altsetting() to select the
+ alternate setting (if there is more than one) of the interface used,
+ and call the write() and read() method to send and receive data.
+
+ When working in a new hardware, one first try would be like this:
+
+ >>> import usb.core
+ >>> dev = usb.core.find(idVendor=myVendorId, idProduct=myProductId)
+ >>> dev.set_configuration()
+ >>> dev.write(1, 'test')
+
+ This sample finds the device of interest (myVendorId and myProductId should be
+ replaced by the corresponding values of your device), then configures the device
+ (by default, the configuration value is 1, which is a typical value for most
+ devices) and then writes some data to the endpoint 0x01.
+
+ Timeout values for the write, read and ctrl_transfer methods are specified in
+ miliseconds. If the parameter is omitted, Device.default_timeout value will
+ be used instead. This property can be set by the user at anytime.
+ """
+
+ def __init__(self, dev, backend):
+ r"""Initialize the Device object.
+
+ Library users should normally get a Device instance through
+ the find function. The dev parameter is the identification
+ of a device to the backend and its meaning is opaque outside
+ of it. The backend parameter is a instance of a backend
+ object.
+ """
+ self._ctx = _ResourceManager(dev, backend)
+ self.__default_timeout = _DEFAULT_TIMEOUT
+
+ desc = backend.get_device_descriptor(dev)
+
+ _set_attr(
+ desc,
+ self,
+ (
+ 'bLength',
+ 'bDescriptorType',
+ 'bcdUSB',
+ 'bDeviceClass',
+ 'bDeviceSubClass',
+ 'bDeviceProtocol',
+ 'bMaxPacketSize0',
+ 'idVendor',
+ 'idProduct',
+ 'bcdDevice',
+ 'iManufacturer',
+ 'iProduct',
+ 'iSerialNumber',
+ 'bNumConfigurations',
+ 'address',
+ 'bus'
+ )
+ )
+
+ 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
+
+ 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.
+ As a device hardly ever has more than one configuration, calling
+ the method without parameter is enough to get the device ready.
+ """
+ self._ctx.managed_set_configuration(self, configuration)
+
+ def get_active_configuration(self):
+ r"""Return a Configuration object representing the current configuration set."""
+ return self._ctx.get_active_configuration(self)
+
+ 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
+ be selected the first one found in the Device in the same way of set_configuration
+ method.
+
+ Commonly, an interface has only one alternate setting and this call is
+ not necessary. For most of the devices, either it has more than one alternate
+ setting or not, it is not harmful to make a call to this method with no arguments,
+ as devices will silently ignore the request when there is only one alternate
+ setting, though the USB Spec allows devices with no additional alternate setting
+ return an error to the Host in response to a SET_INTERFACE request.
+
+ If you are in doubt, you may want to call it with no arguments wrapped by
+ a try/except clause:
+
+ >>> try:
+ >>> dev.set_interface_altsetting()
+ >>> except usb.core.USBError:
+ >>> pass
+ """
+ self._ctx.managed_set_interface(self, interface, alternate_setting)
+
+ def reset(self):
+ r"""Reset the device."""
+ self._ctx.dispose(self, False)
+ self._ctx.backend.reset_device(self._ctx.handle)
+ self._ctx.dispose(self, True)
+
+ def write(self, endpoint, data, interface = None, timeout = None):
+ r"""Write data to the endpoint.
+
+ This method is used to send data to the device. The endpoint parameter
+ corresponds to the bEndpointAddress member whose endpoint you want to
+ 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 data parameter should be a sequence like type convertible to
+ array type (see array module).
+
+ The timeout is specified in miliseconds.
+
+ The method returns the number of bytes written.
+ """
+ backend = self._ctx.backend
+
+ fn_map = {
+ util.ENDPOINT_TYPE_BULK:backend.bulk_write,
+ util.ENDPOINT_TYPE_INTR:backend.intr_write,
+ util.ENDPOINT_TYPE_ISO:backend.iso_write
+ }
+
+ intf = self._ctx.get_interface(self, interface)
+ fn = fn_map[self._ctx.get_endpoint_type(self, endpoint, intf)]
+ self._ctx.managed_claim_interface(self, intf)
+
+ return fn(
+ self._ctx.handle,
+ endpoint,
+ intf.bInterfaceNumber,
+ _interop.as_array(data),
+ self.__get_timeout(timeout)
+ )
+
+ def read(self, endpoint, size, interface = None, timeout = None):
+ r"""Read data from the endpoint.
+
+ This method is used to receive data from the device. The endpoint parameter
+ corresponds to the bEndpointAddress member whose endpoint you want to
+ 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.
+
+ The timeout is specified in miliseconds.
+
+ The method returns an array object with the data read.
+ """
+ backend = self._ctx.backend
+
+ fn_map = {
+ util.ENDPOINT_TYPE_BULK:backend.bulk_read,
+ util.ENDPOINT_TYPE_INTR:backend.intr_read,
+ util.ENDPOINT_TYPE_ISO:backend.iso_read
+ }
+
+ intf = self._ctx.get_interface(self, interface)
+ fn = fn_map[self._ctx.get_endpoint_type(self, endpoint, intf)]
+ self._ctx.managed_claim_interface(self, intf)
+
+ return fn(
+ self._ctx.handle,
+ endpoint,
+ intf.bInterfaceNumber,
+ size,
+ self.__get_timeout(timeout)
+ )
+
+
+ def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,
+ data_or_wLength = None, timeout = None):
+ r"""Do a control transfer on the endpoint 0.
+
+ This method is used to issue a control transfer over the
+ endpoint 0(endpoint 0 is required to always be a control endpoint).
+
+ The parameters bmRequestType, bRequest, wValue and wIndex are the
+ same of the USB Standard Control Request format.
+
+ Control requests may or may not have a data payload to write/read.
+ In cases which it has, the direction bit of the bmRequestType
+ field is used to infere the desired request direction. For
+ host to device requests (OUT), data_or_wLength parameter is
+ the data payload to send, and it must be a sequence type convertible
+ to an array object. In this case, the return value is the number of data
+ payload written. For device to host requests (IN), data_or_wLength
+ is the wLength parameter of the control request specifying the
+ number of bytes to read in data payload. In this case, the return
+ value is the data payload read, as an array object.
+ """
+ if util.ctrl_direction(bmRequestType) == util.CTRL_OUT:
+ a = _interop.as_array(data_or_wLength)
+ elif data_or_wLength is None:
+ a = 0
+ else:
+ a = data_or_wLength
+
+ self._ctx.managed_open()
+
+ return self._ctx.backend.ctrl_transfer(
+ self._ctx.handle,
+ bmRequestType,
+ bRequest,
+ wValue,
+ wIndex,
+ a,
+ self.__get_timeout(timeout)
+ )
+
+ def is_kernel_driver_active(self, interface):
+ r"""Determine if there is kernel driver associated with the interface.
+
+ 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)
+
+ def detach_kernel_driver(self, interface):
+ r"""Detach a kernel driver.
+
+ 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)
+
+ 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)
+
+ def __iter__(self):
+ r"""Iterate over all configurations of the device."""
+ for i in range(self.bNumConfigurations):
+ yield Configuration(self, i)
+
+ def __getitem__(self, index):
+ r"""Return the Configuration object in the given position."""
+ return Configuration(self, index)
+
+ def __del__(self):
+ self._ctx.dispose(self)
+
+ def __get_timeout(self, timeout):
+ if timeout is not None:
+ return timeout
+ return self.__default_timeout
+
+ def __set_def_tmo(self, tmo):
+ if tmo < 0:
+ raise ValueError('Timeout cannot be a negative value')
+ self.__default_timeout = tmo
+
+ def __get_def_tmo(self):
+ return self.__default_timeout
+
+ default_timeout = property(
+ __get_def_tmo,
+ __set_def_tmo,
+ doc = 'Default timeout for transfer I/O functions'
+ )
+
+def find(find_all=False, backend = None, custom_match = None, **args):
+ r"""Find an USB device and return it.
+
+ find() is the function used to discover USB devices.
+ You can pass as arguments any combination of the
+ USB Device Descriptor fields to match a device. For example:
+
+ find(idVendor=0x3f4, idProduct=0x2009)
+
+ will return the Device object for the device with
+ idVendor Device descriptor field equals to 0x3f4 and
+ idProduct equals to 0x2009.
+
+ If there is more than one device which matchs the criteria,
+ the first one found will be returned. If a matching device cannot
+ be found the function returns None. If you want to get all
+ devices, you can set the parameter find_all to True, then find
+ will return an list with all matched devices. If no matching device
+ is found, it will return an empty list. Example:
+
+ printers = find(find_all=True, bDeviceClass=7)
+
+ This call will get all the USB printers connected to the system.
+ (actually may be not, because some devices put their class
+ information in the Interface Descriptor).
+
+ You can also use a customized match criteria:
+
+ dev = find(custom_match = lambda d: d.idProduct=0x3f4 and d.idvendor=0x2009)
+
+ A more accurate printer finder using a customized match would be like
+ so:
+
+ def is_printer(dev):
+ import usb.util
+ if dev.bDeviceClass == 7:
+ return True
+ for cfg in dev:
+ if usb.util.find_descriptor(cfg, bInterfaceClass=7) is not None:
+ return True
+
+ printers = find(find_all=True, custom_match = is_printer)
+
+ Now even if the device class code is in the interface descriptor the
+ printer will be found.
+
+ You can combine a customized match with device descriptor fields. In this
+ case, the fields must match and the custom_match must return True. In the our
+ previous example, if we would like to get all printers belonging to the
+ manufacturer 0x3f4, the code would be like so:
+
+ printers = find(find_all=True, idVendor=0x3f4, custom_match=is_printer)
+
+ If you want to use find as a 'list all devices' function, just call
+ it with find_all = True:
+
+ devices = find(find_all=True)
+
+ Finally, you may pass a custom backend to the find function:
+
+ find(backend = MyBackend())
+
+ PyUSB has builtin backends for libusb 0.1, libusb 1.0 and OpenUSB.
+ If you do not supply a backend explicitly, find() function will select
+ one of the predefineds backends according to system availability.
+
+ Backends are explained in the usb.backend module.
+ """
+
+ 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(
+ lambda a, b: a and b,
+ map(
+ operator.eq,
+ v,
+ map(lambda i: getattr(d, i), k)
+ ),
+ True
+ ):
+ yield d
+
+ if backend is None:
+ import usb.backend.libusb10 as libusb10
+ import usb.backend.libusb01 as libusb01
+ import usb.backend.openusb as openusb
+
+ for m in (libusb10, openusb, libusb01):
+ backend = m.get_backend()
+ if backend is not None:
+ _logger.info('find(): using backend "%s"', m.__name__)
+ break
+ else:
+ raise ValueError('No backend available')
+
+ k, v = args.keys(), args.values()
+
+ if find_all:
+ return [d for d in device_iter(k, v)]
+ else:
+ try:
+ return _interop._next(device_iter(k, v))
+ except StopIteration:
+ return None
diff --git a/plugins/wedo_plugin/usb/legacy.py b/plugins/wedo_plugin/usb/legacy.py
new file mode 100644
index 0000000..0c9c52c
--- /dev/null
+++ b/plugins/wedo_plugin/usb/legacy.py
@@ -0,0 +1,334 @@
+# Copyright (C) 2009-2011 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.
+
+import usb.core as core
+import usb.util as util
+import usb._interop as _interop
+import usb.control as control
+
+__author__ = 'Wander Lairson Costa'
+
+USBError = core.USBError
+
+CLASS_AUDIO = 1
+CLASS_COMM = 2
+CLASS_DATA = 10
+CLASS_HID = 3
+CLASS_HUB = 9
+CLASS_MASS_STORAGE = 8
+CLASS_PER_INTERFACE = 0
+CLASS_PRINTER = 7
+CLASS_VENDOR_SPEC = 255
+DT_CONFIG = 2
+DT_CONFIG_SIZE = 9
+DT_DEVICE = 1
+DT_DEVICE_SIZE = 18
+DT_ENDPOINT = 5
+DT_ENDPOINT_AUDIO_SIZE = 9
+DT_ENDPOINT_SIZE = 7
+DT_HID = 33
+DT_HUB = 41
+DT_HUB_NONVAR_SIZE = 7
+DT_INTERFACE = 4
+DT_INTERFACE_SIZE = 9
+DT_PHYSICAL = 35
+DT_REPORT = 34
+DT_STRING = 3
+ENDPOINT_ADDRESS_MASK = 15
+ENDPOINT_DIR_MASK = 128
+ENDPOINT_IN = 128
+ENDPOINT_OUT = 0
+ENDPOINT_TYPE_BULK = 2
+ENDPOINT_TYPE_CONTROL = 0
+ENDPOINT_TYPE_INTERRUPT = 3
+ENDPOINT_TYPE_ISOCHRONOUS = 1
+ENDPOINT_TYPE_MASK = 3
+ERROR_BEGIN = 500000
+MAXALTSETTING = 128
+MAXCONFIG = 8
+MAXENDPOINTS = 32
+MAXINTERFACES = 32
+RECIP_DEVICE = 0
+RECIP_ENDPOINT = 2
+RECIP_INTERFACE = 1
+RECIP_OTHER = 3
+REQ_CLEAR_FEATURE = 1
+REQ_GET_CONFIGURATION = 8
+REQ_GET_DESCRIPTOR = 6
+REQ_GET_INTERFACE = 10
+REQ_GET_STATUS = 0
+REQ_SET_ADDRESS = 5
+REQ_SET_CONFIGURATION = 9
+REQ_SET_DESCRIPTOR = 7
+REQ_SET_FEATURE = 3
+REQ_SET_INTERFACE = 11
+REQ_SYNCH_FRAME = 12
+TYPE_CLASS = 32
+TYPE_RESERVED = 96
+TYPE_STANDARD = 0
+TYPE_VENDOR = 64
+
+class Endpoint(object):
+ r"""Endpoint descriptor object."""
+ def __init__(self, ep):
+ self.address = ep.bEndpointAddress
+ self.interval = ep.bInterval
+ self.maxPacketSize = ep.wMaxPacketSize
+ self.type = util.endpoint_type(ep.bmAttributes)
+
+class Interface(object):
+ r"""Interface descriptor object."""
+ def __init__(self, intf):
+ self.alternateSetting = intf.bAlternateSetting
+ self.interfaceNumber = intf.bInterfaceNumber
+ self.iInterface = intf.iInterface
+ self.interfaceClass = intf.bInterfaceClass
+ self.interfaceSubClass = intf.bInterfaceSubClass
+ self.interfaceProtocol = intf.bInterfaceProtocol
+ self.endpoints = [Endpoint(e) for e in intf]
+
+class Configuration(object):
+ r"""Configuration descriptor object."""
+ def __init__(self, cfg):
+ self.iConfiguration = cfg.iConfiguration
+ self.maxPower = cfg.bMaxPower << 2
+ self.remoteWakeup = (cfg.bmAttributes >> 5) & 1
+ self.selfPowered = (cfg.bmAttributes >> 6) & 1
+ self.totalLength = cfg.wTotalLength
+ self.value = cfg.bConfigurationValue
+ self.interfaces = [
+ list(g) for k, g in _interop._groupby(
+ _interop._sorted(
+ [Interface(i) for i in cfg],
+ key=lambda i: i.interfaceNumber
+ ),
+ lambda i: i.alternateSetting)
+ ]
+
+class DeviceHandle(object):
+ def __init__(self, dev):
+ self.dev = dev
+ self.__claimed_interface = -1
+
+ def bulkWrite(self, endpoint, buffer, timeout = 100):
+ r"""Perform a bulk write request to the endpoint specified.
+
+ Arguments:
+ endpoint: endpoint number.
+ buffer: sequence data buffer to write.
+ This parameter can be any sequence type.
+ timeout: operation timeout in miliseconds. (default: 100)
+ Returns the number of bytes written.
+ """
+ return self.dev.write(endpoint, buffer, self.__claimed_interface, timeout)
+
+ def bulkRead(self, endpoint, size, timeout = 100):
+ r"""Performs a bulk read request to the endpoint specified.
+
+ Arguments:
+ endpoint: endpoint number.
+ size: number of bytes to read.
+ timeout: operation timeout in miliseconds. (default: 100)
+ Return a tuple with the data read.
+ """
+ return self.dev.read(endpoint, size, self.__claimed_interface, timeout)
+
+ def interruptWrite(self, endpoint, buffer, timeout = 100):
+ r"""Perform a interrupt write request to the endpoint specified.
+
+ Arguments:
+ endpoint: endpoint number.
+ buffer: sequence data buffer to write.
+ This parameter can be any sequence type.
+ timeout: operation timeout in miliseconds. (default: 100)
+ Returns the number of bytes written.
+ """
+ return self.dev.write(endpoint, buffer, self.__claimed_interface, timeout)
+
+ def interruptRead(self, endpoint, size, timeout = 100):
+ r"""Performs a interrupt read request to the endpoint specified.
+
+ Arguments:
+ endpoint: endpoint number.
+ size: number of bytes to read.
+ timeout: operation timeout in miliseconds. (default: 100)
+ Return a tuple with the data read.
+ """
+ return self.dev.read(endpoint, size, self.__claimed_interface, timeout)
+
+ def controlMsg(self, requestType, request, buffer, value = 0, index = 0, timeout = 100):
+ r"""Perform a control request to the default control pipe on a device.
+
+ Arguments:
+ requestType: specifies the direction of data flow, the type
+ of request, and the recipient.
+ request: specifies the request.
+ buffer: if the transfer is a write transfer, buffer is a sequence
+ with the transfer data, otherwise, buffer is the number of
+ bytes to read.
+ value: specific information to pass to the device. (default: 0)
+ index: specific information to pass to the device. (default: 0)
+ timeout: operation timeout in miliseconds. (default: 100)
+ Return the number of bytes written.
+ """
+ return self.dev.ctrl_transfer(
+ requestType,
+ request,
+ wValue = value,
+ wIndex = index,
+ data_or_wLength = buffer,
+ timeout = timeout
+ )
+
+ def clearHalt(self, endpoint):
+ r"""Clears any halt status on the specified endpoint.
+
+ Arguments:
+ endpoint: endpoint number.
+ """
+ cfg = self.dev.get_active_configuration()
+ intf = util.find_descriptor(cfg, bInterfaceNumber = self.__claimed_interface)
+ e = util.find_descriptor(intf, bEndpointAddress = endpoint)
+ control.clear_feature(self.dev, control.ENDPOINT_HALT, e)
+
+ def claimInterface(self, interface):
+ r"""Claims the interface with the Operating System.
+
+ Arguments:
+ interface: interface number or an Interface object.
+ """
+ if_num = interface.interfaceNumber \
+ if isinstance(interface, Interface) else interface
+
+ util.claim_interface(self.dev, if_num)
+ self.__claimed_interface = if_num
+
+ def releaseInterface(self):
+ r"""Release an interface previously claimed with claimInterface."""
+ util.release_interface(self.dev, self.__claimed_interface)
+ self.__claimed_interface = -1
+
+ def reset(self):
+ r"""Reset the specified device by sending a RESET
+ down the port it is connected to."""
+ self.dev.reset()
+
+ def resetEndpoint(self, endpoint):
+ r"""Reset all states for the specified endpoint.
+
+ Arguments:
+ endpoint: endpoint number.
+ """
+ self.clearHalt(endpoint)
+
+ def setConfiguration(self, configuration):
+ r"""Set the active configuration of a device.
+
+ Arguments:
+ configuration: a configuration value or a Configuration object.
+ """
+ self.dev.set_configuration(configuration)
+
+ def setAltInterface(self, alternate):
+ r"""Sets the active alternate setting of the current interface.
+
+ Arguments:
+ alternate: an alternate setting number or an Interface object.
+ """
+ self.dev.set_interface_altsetting(self.__claimed_interface, alternate)
+
+ def getString(self, index, length, langid = None):
+ r"""Retrieve the string descriptor specified by index
+ and langid from a device.
+
+ Arguments:
+ index: index of descriptor in the device.
+ length: number of bytes of the string
+ langid: Language ID. If it is omittedi, will be
+ used the first language.
+ """
+ return util.get_string(self.dev, length, index, langid).encode('ascii')
+
+ def getDescriptor(self, desc_type, desc_index, length, endpoint = -1):
+ r"""Retrieves a descriptor from the device identified by the type
+ and index of the descriptor.
+
+ Arguments:
+ desc_type: descriptor type.
+ desc_index: index of the descriptor.
+ len: descriptor length.
+ endpoint: ignored.
+ """
+ return control.get_descriptor(self.dev, length, desc_type, desc_index)
+
+ def detachKernelDriver(self, interface):
+ r"""Detach a kernel driver from the interface (if one is attached,
+ we have permission and the operation is supported by the OS)
+
+ Arguments:
+ interface: interface number or an Interface object.
+ """
+ self.dev.detach_kernel_driver(interface)
+
+class Device(object):
+ r"""Device descriptor object"""
+ def __init__(self, dev):
+ self.deviceClass = dev.bDeviceClass
+ self.deviceSubClass = dev.bDeviceSubClass
+ self.deviceProtocol = dev.bDeviceProtocol
+ self.deviceVersion = dev.bcdDevice
+ self.devnum = None
+ self.filename = ''
+ self.iManufacturer = dev.iManufacturer
+ self.iProduct = dev.iProduct
+ self.iSerialNumber = dev.iSerialNumber
+ self.idProduct = dev.idProduct
+ self.idVendor = dev.idVendor
+ self.maxPacketSize = dev.bMaxPacketSize0
+ self.usbVersion = dev.bcdUSB
+ self.configurations = [Configuration(c) for c in dev]
+ self.dev = dev
+
+ def open(self):
+ r"""Open the device for use.
+
+ Return a DeviceHandle object
+ """
+ return DeviceHandle(self.dev)
+
+class Bus(object):
+ r"""Bus object."""
+ def __init__(self):
+ self.dirname = ''
+ self.localtion = 0
+ self.devices = [Device(d) for d in core.find(find_all=True)]
+
+def busses():
+ r"""Return a tuple with the usb busses."""
+ return (Bus(),)
+
diff --git a/plugins/wedo_plugin/usb/util.py b/plugins/wedo_plugin/usb/util.py
new file mode 100644
index 0000000..1f8cee3
--- /dev/null
+++ b/plugins/wedo_plugin/usb/util.py
@@ -0,0 +1,260 @@
+# Copyright (C) 2009-2011 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.
+
+r"""usb.util - Utility functions.
+
+This module exports:
+
+endpoint_address - return the endpoint absolute address.
+endpoint_direction - return the endpoint transfer direction.
+endpoint_type - return the endpoint type
+ctrl_direction - return the direction of a control transfer
+build_request_type - build a bmRequestType field of a control transfer.
+find_descriptor - find an inner descriptor.
+claim_interface - explicitly claim an interface.
+release_interface - explicitly release an interface.
+dispose_resources - release internal resources allocated by the object.
+get_string - retrieve a string descriptor from the device.
+"""
+
+__author__ = 'Wander Lairson Costa'
+
+import operator
+import usb._interop as _interop
+
+# descriptor type
+DESC_TYPE_DEVICE = 0x01
+DESC_TYPE_CONFIG = 0x02
+DESC_TYPE_STRING = 0x03
+DESC_TYPE_INTERFACE = 0x04
+DESC_TYPE_ENDPOINT = 0x05
+
+# endpoint direction
+ENDPOINT_IN = 0x80
+ENDPOINT_OUT = 0x00
+
+# endpoint type
+ENDPOINT_TYPE_CTRL = 0x00
+ENDPOINT_TYPE_ISO = 0x01
+ENDPOINT_TYPE_BULK = 0x02
+ENDPOINT_TYPE_INTR = 0x03
+
+# control request type
+CTRL_TYPE_STANDARD = (0 << 5)
+CTRL_TYPE_CLASS = (1 << 5)
+CTRL_TYPE_VENDOR = (2 << 5)
+CTRL_TYPE_RESERVED = (3 << 5)
+
+# control request recipient
+CTRL_RECIPIENT_DEVICE = 0
+CTRL_RECIPIENT_INTERFACE = 1
+CTRL_RECIPIENT_ENDPOINT = 2
+CTRL_RECIPIENT_OTHER = 3
+
+# control request direction
+CTRL_OUT = 0x00
+CTRL_IN = 0x80
+
+_ENDPOINT_ADDR_MASK = 0x0f
+_ENDPOINT_DIR_MASK = 0x80
+_ENDPOINT_TRANSFER_TYPE_MASK = 0x03
+_CTRL_DIR_MASK = 0x80
+
+def endpoint_address(address):
+ r"""Return the endpoint absolute address.
+
+ The address parameter is the bEndpointAddress field
+ of the endpoint descriptor.
+ """
+ return address & _ENDPOINT_ADDR_MASK
+
+def endpoint_direction(address):
+ r"""Return the endpoint direction.
+
+ The address parameter is the bEndpointAddress field
+ of the endpoint descriptor.
+ The possible return values are ENDPOINT_OUT or ENDPOINT_IN.
+ """
+ return address & _ENDPOINT_DIR_MASK
+
+def endpoint_type(bmAttributes):
+ r"""Return the transfer type of the endpoint.
+
+ The bmAttributes parameter is the bmAttributes field
+ of the endpoint descriptor.
+ The possible return values are: ENDPOINT_TYPE_CTRL,
+ ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR.
+ """
+ return bmAttributes & _ENDPOINT_TRANSFER_TYPE_MASK
+
+def ctrl_direction(bmRequestType):
+ r"""Return the direction of a control request.
+
+ The bmRequestType parameter is the value of the
+ bmRequestType field of a control transfer.
+ The possible return values are CTRL_OUT or CTRL_IN.
+ """
+ return bmRequestType & _CTRL_DIR_MASK
+
+def build_request_type(direction, type, recipient):
+ r"""Build a bmRequestType field for control requests.
+
+ These is a conventional function to build a bmRequestType
+ for a control request.
+
+ The direction parameter can be CTRL_OUT or CTRL_IN.
+ The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS,
+ CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values.
+ The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE,
+ CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER.
+
+ Return the bmRequestType value.
+ """
+ return recipient | type | direction
+
+def find_descriptor(desc, find_all=False, custom_match=None, **args):
+ r"""Find an inner descriptor.
+
+ find_descriptor works in the same way the core.find() function does,
+ but it acts on general descriptor objects. For example, suppose you
+ have a Device object called dev and want a Configuration of this
+ object with its bConfigurationValue equals to 1, the code would
+ be like so:
+
+ >>> cfg = util.find_descriptor(dev, bConfigurationValue=1)
+
+ You can use any field of the Descriptor as a match criteria, and you
+ can supply a customized match just like core.find() does. The
+ find_descriptor function also accepts the find_all parameter to get
+ a list of descriptor instead of just one.
+ """
+ def desc_iter(k, v):
+ for d in desc:
+ if (custom_match is None or custom_match(d)) and \
+ _interop._reduce(
+ lambda a, b: a and b,
+ map(
+ operator.eq,
+ v,
+ map(lambda i: getattr(d, i), k)
+ ),
+ True
+ ):
+ yield d
+
+ k, v = args.keys(), args.values()
+
+ if find_all:
+ return [d for d in desc_iter(k, v)]
+ else:
+ try:
+ return _interop._next(desc_iter(k, v))
+ except StopIteration:
+ return None
+
+def claim_interface(device, interface):
+ r"""Explicitly claim an interface.
+
+ PyUSB users normally do not have to worry about interface claiming,
+ as the library takes care of it automatically. But there are situations
+ where you need deterministic interface claiming. For these uncommon
+ cases, you can use claim_interface.
+
+ If the interface is already claimed, either through a previously call
+ to claim_interface or internally by the device object, nothing happens.
+ """
+ device._ctx.managed_claim_interface(device, interface)
+
+def release_interface(device, interface):
+ r"""Explicitly release an interface.
+
+ This function is used to release an interface previously claimed,
+ either through a call to claim_interface or internally by the
+ device object.
+
+ Normally, you do not need to worry about claiming policies, as
+ the device object takes care of it automatically.
+ """
+ device._ctx.managed_release_interface(device, interface)
+
+def dispose_resources(device):
+ r"""Release internal resources allocated by the object.
+
+ Sometimes you need to provide deterministic resources
+ freeing, for example to allow another application to
+ talk to the device. As Python does not provide deterministic
+ destruction, this function releases all internal resources
+ allocated by the device, like device handle and interface
+ policy.
+
+ After calling this function, you can continue using the device
+ object normally. If the resources will be necessary again, it
+ will allocate them automatically.
+ """
+ device._ctx.dispose(device)
+
+def get_string(dev, length, index, langid = None):
+ r"""Retrieve a string descriptor from the device.
+
+ dev is the Device object to which the request will be
+ sent to.
+
+ length is the length of 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
+ of the first Language ID will be returned.
+
+ The return value is the unicode string present in the descriptor.
+ """
+ from usb.control import get_descriptor
+ if langid is None:
+ # Asking for the zero'th index is special - it returns a string
+ # descriptor that contains all the language IDs supported by the device.
+ # Typically there aren't many - often only one. The language IDs are 16
+ # bit numbers, and they start at the third byte in the descriptor. See
+ # USB 2.0 specification section 9.6.7 for more information.
+ #
+ # Note from libusb 1.0 sources (descriptor.c)
+ buf = get_descriptor(
+ dev,
+ 1024,
+ DESC_TYPE_STRING,
+ 0
+ )
+ assert len(buf) >= 4
+ langid = buf[2] | (buf[3] << 8)
+
+ buf = get_descriptor(
+ dev,
+ length * 2 + 2, # string is utf16 + 2 bytes of the descriptor
+ DESC_TYPE_STRING,
+ index,
+ langid
+ )
+ return buf[2:].tostring().decode('utf-16-le')
diff --git a/plugins/wedo_plugin/wedo_plugin.py b/plugins/wedo_plugin/wedo_plugin.py
new file mode 100644
index 0000000..e478b67
--- /dev/null
+++ b/plugins/wedo_plugin/wedo_plugin.py
@@ -0,0 +1,126 @@
+#Copyright (c) 2012, Tony Forster, Ian Daniher, Walter Bender
+#
+# This program 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.
+#
+# This program 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+from plugins.plugin import Plugin
+from WeDoMore import WeDo
+
+from TurtleArt.tapalette import make_palette
+from TurtleArt.taconstants import XO1, XO15
+from TurtleArt.talogo import primitive_dictionary
+
+import logging
+_logger = logging.getLogger('turtleart-activity WeDo plugin')
+
+
+class Wedo_plugin(Plugin):
+
+ def __init__(self, parent):
+ self.WeDo = WeDo()
+ self._parent = parent
+ if self.WeDo.dev is None:
+ self._status = False # no WeDo device found
+ else:
+ self._status = True
+
+ def setup(self):
+
+ palette = make_palette('WeDo', colors=["#FF6060", "#A06060"],
+ help_string=_('Palette of WeDo blocks'))
+
+ primitive_dictionary['wedotilt'] = self.WeDo.getTilt
+ palette.add_block('tilt',
+ style='box-style',
+ label=_('tilt'),
+ help_string=_('tilt sensor output: (-1 == no tilt,\
+ 0 == tilt forward, 3 == tilt back, 1 == tilt left, 2 == tilt right)'),
+ value_block=True,
+ prim_name = 'wedotilt')
+ self._parent.lc.def_prim(
+ 'wedotilt', 0, lambda self: primitive_dictionary['wedotilt']())
+
+ primitive_dictionary['wedodistance'] = self.WeDo.getDistance
+ palette.add_block('wedodistance',
+ style='box-style',
+ label=_('distance'),
+ help_string=_('distance sensor output'),
+ value_block=True,
+ prim_name = 'wedodistance')
+ self._parent.lc.def_prim(
+ 'wedodistance', 0,
+ lambda self: primitive_dictionary['wedodistance']())
+
+ primitive_dictionary['wedogetMotorA'] = self.WeDo.getMotorA
+ palette.add_block('wedogetMotorA',
+ style='box-style',
+ label=_('Motor A'),
+ help_string=_('returns the current value of Motor A'),
+ value_block=True,
+ prim_name = 'wedogetMotorA')
+
+ self._parent.lc.def_prim('wedogetMotorA', 0,
+ lambda self: primitive_dictionary['wedogetMotorA']())
+
+ primitive_dictionary['wedogetMotorB'] = self.WeDo.getMotorB
+ palette.add_block('wedogetMotorB',
+ style='box-style',
+ label=_('Motor B'),
+ help_string=_('returns the current value of Motor B'),
+ value_block=True,
+ prim_name = 'wedogetMotorB')
+ self._parent.lc.def_prim(
+ 'wedogetMotorB', 0,
+ lambda self: primitive_dictionary['wedogetMotorB']())
+
+ primitive_dictionary['wedosetMotorA'] = self.WeDo.setMotorA
+ palette.add_block('wedosetMotorA',
+ style = 'basic-style-1arg',
+ label = _('Motor A'),
+ default = 30,
+ prim_name = 'wedosetMotorA',
+ help_string = _('set the value for Motor A'))
+ self._parent.lc.def_prim(
+ 'wedosetMotorA', 1,
+ lambda self, a: primitive_dictionary['wedosetMotorA'](a))
+
+ primitive_dictionary['wedosetMotorB'] = self.WeDo.setMotorB
+ palette.add_block('wedosetMotorB',
+ style = 'basic-style-1arg',
+ label = _('Motor B'),
+ default = 30,
+ prim_name = 'wedosetMotorB',
+ help_string = _('set the value for Motor B'))
+ self._parent.lc.def_prim(
+ 'wedosetMotorB', 1,
+ lambda self, b: primitive_dictionary['wedosetMotorB'](b))
+
+ def start(self):
+ pass
+
+ def stop(self):
+ if self._status:
+ self.WeDo.setMotors(0, 0)
+
+ def goto_background(self):
+ pass
+
+ def return_to_foreground(self):
+ pass
+
+ def quit(self):
+ if self._status:
+ self.WeDo.setMotors(0, 0)