diff --git a/src/libprs500/__init__.py b/src/libprs500/__init__.py index 187426819f..c30761f556 100644 --- a/src/libprs500/__init__.py +++ b/src/libprs500/__init__.py @@ -29,7 +29,6 @@ The packet structure used by the SONY Reader USB protocol is defined in the module L{prstypes}. The communication logic is defined in the module L{communicate}. -This package requires U{PyUSB}. In order to use it as a non-root user on Linux, you should have the following rule in C{/etc/udev/rules.d/90-local.rules} :: BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", @@ -37,6 +36,6 @@ the following rule in C{/etc/udev/rules.d/90-local.rules} :: You may have to adjust the GROUP and the location of the rules file to suit your distribution. """ -__version__ = "0.3.0" +__version__ = "0.3.1" __docformat__ = "epytext" __author__ = "Kovid Goyal " diff --git a/src/libprs500/communicate.py b/src/libprs500/communicate.py index 7d94f89661..40131902b2 100755 --- a/src/libprs500/communicate.py +++ b/src/libprs500/communicate.py @@ -46,13 +46,14 @@ Contains the logic for communication with the device (a SONY PRS-500). The public interface of class L{PRS500Device} defines the methods for performing various tasks. """ -import usb import sys import os import time from tempfile import TemporaryFile from array import array +from libprs500.libusb import Error as USBError +from libprs500.libusb import get_device_by_id from libprs500.prstypes import * from libprs500.errors import * from libprs500.books import BookList, fix_ids @@ -115,34 +116,6 @@ class File(object): return self.name -class DeviceDescriptor: - """ - Describes a USB device. - - A description is composed of the Vendor Id, Product Id and Interface Id. - See the U{USB spec} - """ - - def __init__(self, vendor_id, product_id, interface_id) : - self.vendor_id = vendor_id - self.product_id = product_id - self.interface_id = interface_id - - def get_device(self) : - """ - Return the device corresponding to the device descriptor if it is - available on a USB bus. Otherwise, return None. Note that the - returned device has yet to be claimed or opened. - """ - buses = usb.busses() - for bus in buses : - for device in bus.devices : - if device.idVendor == self.vendor_id : - if device.idProduct == self.product_id : - return device - return None - - class PRS500Device(Device): """ @@ -154,11 +127,11 @@ class PRS500Device(Device): 2. Listing of directories. See the C{list} method. """ - SONY_VENDOR_ID = 0x054c #: SONY Vendor Id - PRS500_PRODUCT_ID = 0x029b #: Product Id for the PRS-500 - PRS500_INTERFACE_ID = 0 #: The interface we use to talk to the device - PRS500_BULK_IN_EP = 0x81 #: Endpoint for Bulk reads - PRS500_BULK_OUT_EP = 0x02 #: Endpoint for Bulk writes + VENDOR_ID = 0x054c #: SONY Vendor Id + PRODUCT_ID = 0x029b #: Product Id for the PRS-500 + INTERFACE_ID = 0 #: The interface we use to talk to the device + BULK_IN_EP = 0x81 #: Endpoint for Bulk reads + BULK_OUT_EP = 0x02 #: Endpoint for Bulk writes # Location of media.xml file on device MEDIA_XML = "/Data/database/cache/media.xml" # Location of cache.xml on storage card in device @@ -168,13 +141,10 @@ class PRS500Device(Device): # Height for thumbnails of books/images on the device THUMBNAIL_HEIGHT = 68 - device_descriptor = DeviceDescriptor(SONY_VENDOR_ID, \ - PRS500_PRODUCT_ID, PRS500_INTERFACE_ID) - @classmethod def signature(cls): """ Return a two element tuple (vendor id, product id) """ - return (cls.SONY_VENDOR_ID, cls.PRS500_PRODUCT_ID ) + return (cls.VENDOR_ID, cls.PRODUCT_ID ) def safe(func): """ @@ -202,7 +172,7 @@ class PRS500Device(Device): if not kwargs.has_key("end_session") or kwargs["end_session"]: dev.send_validated_command(EndSession()) raise - except usb.USBError, err: + except USBError, err: if "No such device" in str(err): raise DeviceError() elif "Connection timed out" in str(err): @@ -229,8 +199,7 @@ class PRS500Device(Device): task does not have any progress information """ Device.__init__(self) - # The actual device (PyUSB object) - self.device = self.device_descriptor.get_device() + self.device = get_device_by_id(self.VENDOR_ID, self.PRODUCT_ID) # Handle that is used to communicate with device. Setup in L{open} self.handle = None self.log_packets = log_packets @@ -238,7 +207,7 @@ class PRS500Device(Device): def reconnect(self): """ Only recreates the device node and deleted the connection handle """ - self.device = self.device_descriptor.get_device() + self.device = get_device_by_id(self.VENDOR_ID, self.PRODUCT_ID) self.handle = None @classmethod @@ -249,7 +218,7 @@ class PRS500Device(Device): software connection. You may need to call L{reconnect} if you keep getting L{DeviceError}. """ - return cls.device_descriptor.get_device() != None + return get_device_by_id(cls.VENDOR_ID, cls.PRODUCT_ID) != None def open(self) : @@ -261,13 +230,13 @@ class PRS500Device(Device): @todo: Implement unlocking of the device """ - self.device = self.device_descriptor.get_device() + self.device = get_device_by_id(self.VENDOR_ID, self.PRODUCT_ID) if not self.device: raise DeviceError() try: self.handle = self.device.open() - self.handle.claimInterface(self.device_descriptor.interface_id) - except usb.USBError, err: + self.handle.claim_interface(self.INTERFACE_ID) + except USBError, err: print >> sys.stderr, err raise DeviceBusy() # Large timeout as device may still be initializing @@ -292,7 +261,7 @@ class PRS500Device(Device): """ Release device interface """ try: self.handle.reset() - self.handle.releaseInterface() + self.handle.release_interface() except Exception, err: print >> sys.stderr, err self.handle, self.device = None, None @@ -309,11 +278,11 @@ class PRS500Device(Device): """ if self.log_packets: self.log_packet(command, "Command") - bytes_sent = self.handle.controlMsg(0x40, 0x80, command) + bytes_sent = self.handle.control_msg(0x40, 0x80, command) if bytes_sent != len(command): raise ControlError(desc="Could not send control request to device\n"\ + str(command)) - response = response_type(self.handle.controlMsg(0xc0, 0x81, \ + response = response_type(self.handle.control_msg(0xc0, 0x81, \ Response.SIZE, timeout=timeout)) if self.log_packets: self.log_packet(response, "Response") @@ -342,7 +311,7 @@ class PRS500Device(Device): C{data} is broken up into packets to be sent to device. """ def bulk_write_packet(packet): - self.handle.bulkWrite(PRS500Device.PRS500_BULK_OUT_EP, packet) + self.handle.bulk_write(self.BULK_OUT_EP, packet) if self.log_packets: self.log_packet(Answer(packet), "Answer h->d") @@ -366,7 +335,7 @@ class PRS500Device(Device): bulk_write_packet(data[pos:endpos]) bytes_left -= endpos - pos pos = endpos - res = Response(self.handle.controlMsg(0xc0, 0x81, Response.SIZE, \ + res = Response(self.handle.control_msg(0xc0, 0x81, Response.SIZE, \ timeout=5000)) if self.log_packets: self.log_packet(res, "Response") @@ -390,8 +359,7 @@ class PRS500Device(Device): Each packet is of type data_type """ def bulk_read_packet(data_type=Answer, size=0x1000): - data = data_type(self.handle.bulkRead(PRS500Device.PRS500_BULK_IN_EP, \ - size)) + data = data_type(self.handle.bulk_read(self.BULK_IN_EP, size)) if self.log_packets: self.log_packet(data, "Answer d->h") return data @@ -844,4 +812,4 @@ class PRS500Device(Device): f.seek(0) self.put_file(f, path, replace_file=True, end_session=False) f.close() - + \ No newline at end of file diff --git a/src/libprs500/libusb.py b/src/libprs500/libusb.py index 4568158b3e..17f50bc535 100644 --- a/src/libprs500/libusb.py +++ b/src/libprs500/libusb.py @@ -1,11 +1,15 @@ import sys -from ctypes import * +from ctypes import cdll, POINTER, byref, pointer, Structure, \ + c_ubyte, c_ushort, c_int, c_char, c_void_p, c_byte from errno import EBUSY, ENOMEM iswindows = 'win32' in sys.platform.lower() +isosx = 'darwin' in sys.platform.lower() _libusb_name = 'libusb.so' if iswindows: _libusb_name = 'libusb0' +elif isosx: + _libusb_name = 'libusb.dylib' _libusb = cdll.LoadLibrary(_libusb_name) # TODO: Need to set this in a platform dependednt way (limits.h in linux) @@ -96,7 +100,11 @@ class Device(Structure): class Bus(Structure): @apply def device_list(): - doc = """ Flat list of devices on this bus. Note: children are not explored """ + doc = """ + Flat list of devices on this bus. + Note: children are not explored + TODO: Check if exploring children is neccessary (e.g. with an external hub) + """ def fget(self): if _libusb.usb_find_devices() < 0: raise Error('Unable to search for USB devices') @@ -162,7 +170,7 @@ class DeviceHandle(Structure): if rsize < size: raise Error('Could not read ' + str(size) + ' bytes on the '\ 'control bus. Read: ' + str(rsize) + ' bytes.') - return list(arr) + return tuple(arr) else: ArrayType = c_byte * size _libusb.usb_control_msg.argtypes = [POINTER(DeviceHandle), c_int, \ @@ -185,7 +193,7 @@ class DeviceHandle(Structure): if rsize < size: raise Error('Could not read ' + str(size) + ' bytes on the '\ 'bulk bus. Read: ' + str(rsize) + ' bytes.') - return list(arr) + return tuple(arr) def bulk_write(self, endpoint, bytes, timeout=100): size = len(bytes) @@ -268,17 +276,3 @@ def get_device_by_id(idVendor, idProduct): if dev.device_descriptor.idVendor == idVendor and \ dev.device_descriptor.idProduct == idProduct: return dev - -#dev = get_device_by_id(0x054c,0x029b) -#handle = dev.open() -#handle.claim_interface(0) -#from libprs500.prstypes import * -#comm = GetUSBProtocolVersion() -#handle.control_msg(0x40, 0x80, comm) -#ret = handle.control_msg(0xc0, 0x81, 32) -#print ret -#ret = handle.bulk_read(0x81, 24) -#print ret -# -#handle.release_interface(0) -#handle.close() \ No newline at end of file diff --git a/src/libprs500/prstypes.py b/src/libprs500/prstypes.py index fbb2645d18..3dd4b22193 100755 --- a/src/libprs500/prstypes.py +++ b/src/libprs500/prstypes.py @@ -63,7 +63,7 @@ class TransferBuffer(list): """ Represents raw (unstructured) data packets sent over the usb bus. - C{TransferBuffer} is a wrapper around the tuples used by L{PyUSB} for communication. + C{TransferBuffer} is a wrapper around the tuples used by libusb for communication. It has convenience methods to read and write data from the underlying buffer. See L{TransferBuffer.pack} and L{TransferBuffer.unpack}. """