From 39b30e64202057ca1045871eb2e501b4a5627eec Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Mon, 17 Sep 2012 19:52:40 +0000 Subject: adding wedo to project --- (limited to 'plugins/wedo_plugin/usb/backend') 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 -- cgit v0.9.1