Drop dependency on PyUSB. Version bump.

This commit is contained in:
Kovid Goyal 2007-01-13 04:15:25 +00:00
parent fbdb293ac0
commit 234750d487
4 changed files with 36 additions and 75 deletions

View File

@ -29,7 +29,6 @@ The packet structure used by the SONY Reader USB protocol is defined
in the module L{prstypes}. The communication logic in the module L{prstypes}. The communication logic
is defined in the module L{communicate}. is defined in the module L{communicate}.
This package requires U{PyUSB<http://pyusb.berlios.de/>}.
In order to use it as a non-root user on Linux, you should have 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} :: the following rule in C{/etc/udev/rules.d/90-local.rules} ::
BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", 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 You may have to adjust the GROUP and the location of the rules file to
suit your distribution. suit your distribution.
""" """
__version__ = "0.3.0" __version__ = "0.3.1"
__docformat__ = "epytext" __docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"

View File

@ -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 The public interface of class L{PRS500Device} defines the
methods for performing various tasks. methods for performing various tasks.
""" """
import usb
import sys import sys
import os import os
import time import time
from tempfile import TemporaryFile from tempfile import TemporaryFile
from array import array 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.prstypes import *
from libprs500.errors import * from libprs500.errors import *
from libprs500.books import BookList, fix_ids from libprs500.books import BookList, fix_ids
@ -115,34 +116,6 @@ class File(object):
return self.name 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<http://www.usb.org/developers/docs/usb_20_05122006.zip>}
"""
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): class PRS500Device(Device):
""" """
@ -154,11 +127,11 @@ class PRS500Device(Device):
2. Listing of directories. See the C{list} method. 2. Listing of directories. See the C{list} method.
""" """
SONY_VENDOR_ID = 0x054c #: SONY Vendor Id VENDOR_ID = 0x054c #: SONY Vendor Id
PRS500_PRODUCT_ID = 0x029b #: Product Id for the PRS-500 PRODUCT_ID = 0x029b #: Product Id for the PRS-500
PRS500_INTERFACE_ID = 0 #: The interface we use to talk to the device INTERFACE_ID = 0 #: The interface we use to talk to the device
PRS500_BULK_IN_EP = 0x81 #: Endpoint for Bulk reads BULK_IN_EP = 0x81 #: Endpoint for Bulk reads
PRS500_BULK_OUT_EP = 0x02 #: Endpoint for Bulk writes BULK_OUT_EP = 0x02 #: Endpoint for Bulk writes
# Location of media.xml file on device # Location of media.xml file on device
MEDIA_XML = "/Data/database/cache/media.xml" MEDIA_XML = "/Data/database/cache/media.xml"
# Location of cache.xml on storage card in device # 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 # Height for thumbnails of books/images on the device
THUMBNAIL_HEIGHT = 68 THUMBNAIL_HEIGHT = 68
device_descriptor = DeviceDescriptor(SONY_VENDOR_ID, \
PRS500_PRODUCT_ID, PRS500_INTERFACE_ID)
@classmethod @classmethod
def signature(cls): def signature(cls):
""" Return a two element tuple (vendor id, product id) """ """ 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): def safe(func):
""" """
@ -202,7 +172,7 @@ class PRS500Device(Device):
if not kwargs.has_key("end_session") or kwargs["end_session"]: if not kwargs.has_key("end_session") or kwargs["end_session"]:
dev.send_validated_command(EndSession()) dev.send_validated_command(EndSession())
raise raise
except usb.USBError, err: except USBError, err:
if "No such device" in str(err): if "No such device" in str(err):
raise DeviceError() raise DeviceError()
elif "Connection timed out" in str(err): elif "Connection timed out" in str(err):
@ -229,8 +199,7 @@ class PRS500Device(Device):
task does not have any progress information task does not have any progress information
""" """
Device.__init__(self) Device.__init__(self)
# The actual device (PyUSB object) self.device = get_device_by_id(self.VENDOR_ID, self.PRODUCT_ID)
self.device = self.device_descriptor.get_device()
# Handle that is used to communicate with device. Setup in L{open} # Handle that is used to communicate with device. Setup in L{open}
self.handle = None self.handle = None
self.log_packets = log_packets self.log_packets = log_packets
@ -238,7 +207,7 @@ class PRS500Device(Device):
def reconnect(self): def reconnect(self):
""" Only recreates the device node and deleted the connection handle """ """ 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 self.handle = None
@classmethod @classmethod
@ -249,7 +218,7 @@ class PRS500Device(Device):
software connection. You may need to call L{reconnect} if you keep software connection. You may need to call L{reconnect} if you keep
getting L{DeviceError}. 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) : def open(self) :
@ -261,13 +230,13 @@ class PRS500Device(Device):
@todo: Implement unlocking of the 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: if not self.device:
raise DeviceError() raise DeviceError()
try: try:
self.handle = self.device.open() self.handle = self.device.open()
self.handle.claimInterface(self.device_descriptor.interface_id) self.handle.claim_interface(self.INTERFACE_ID)
except usb.USBError, err: except USBError, err:
print >> sys.stderr, err print >> sys.stderr, err
raise DeviceBusy() raise DeviceBusy()
# Large timeout as device may still be initializing # Large timeout as device may still be initializing
@ -292,7 +261,7 @@ class PRS500Device(Device):
""" Release device interface """ """ Release device interface """
try: try:
self.handle.reset() self.handle.reset()
self.handle.releaseInterface() self.handle.release_interface()
except Exception, err: except Exception, err:
print >> sys.stderr, err print >> sys.stderr, err
self.handle, self.device = None, None self.handle, self.device = None, None
@ -309,11 +278,11 @@ class PRS500Device(Device):
""" """
if self.log_packets: if self.log_packets:
self.log_packet(command, "Command") 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): if bytes_sent != len(command):
raise ControlError(desc="Could not send control request to device\n"\ raise ControlError(desc="Could not send control request to device\n"\
+ str(command)) + str(command))
response = response_type(self.handle.controlMsg(0xc0, 0x81, \ response = response_type(self.handle.control_msg(0xc0, 0x81, \
Response.SIZE, timeout=timeout)) Response.SIZE, timeout=timeout))
if self.log_packets: if self.log_packets:
self.log_packet(response, "Response") self.log_packet(response, "Response")
@ -342,7 +311,7 @@ class PRS500Device(Device):
C{data} is broken up into packets to be sent to device. C{data} is broken up into packets to be sent to device.
""" """
def bulk_write_packet(packet): 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: if self.log_packets:
self.log_packet(Answer(packet), "Answer h->d") self.log_packet(Answer(packet), "Answer h->d")
@ -366,7 +335,7 @@ class PRS500Device(Device):
bulk_write_packet(data[pos:endpos]) bulk_write_packet(data[pos:endpos])
bytes_left -= endpos - pos bytes_left -= endpos - pos
pos = endpos pos = endpos
res = Response(self.handle.controlMsg(0xc0, 0x81, Response.SIZE, \ res = Response(self.handle.control_msg(0xc0, 0x81, Response.SIZE, \
timeout=5000)) timeout=5000))
if self.log_packets: if self.log_packets:
self.log_packet(res, "Response") self.log_packet(res, "Response")
@ -390,8 +359,7 @@ class PRS500Device(Device):
Each packet is of type data_type Each packet is of type data_type
""" """
def bulk_read_packet(data_type=Answer, size=0x1000): def bulk_read_packet(data_type=Answer, size=0x1000):
data = data_type(self.handle.bulkRead(PRS500Device.PRS500_BULK_IN_EP, \ data = data_type(self.handle.bulk_read(self.BULK_IN_EP, size))
size))
if self.log_packets: if self.log_packets:
self.log_packet(data, "Answer d->h") self.log_packet(data, "Answer d->h")
return data return data
@ -844,4 +812,4 @@ class PRS500Device(Device):
f.seek(0) f.seek(0)
self.put_file(f, path, replace_file=True, end_session=False) self.put_file(f, path, replace_file=True, end_session=False)
f.close() f.close()

View File

@ -1,11 +1,15 @@
import sys 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 from errno import EBUSY, ENOMEM
iswindows = 'win32' in sys.platform.lower() iswindows = 'win32' in sys.platform.lower()
isosx = 'darwin' in sys.platform.lower()
_libusb_name = 'libusb.so' _libusb_name = 'libusb.so'
if iswindows: if iswindows:
_libusb_name = 'libusb0' _libusb_name = 'libusb0'
elif isosx:
_libusb_name = 'libusb.dylib'
_libusb = cdll.LoadLibrary(_libusb_name) _libusb = cdll.LoadLibrary(_libusb_name)
# TODO: Need to set this in a platform dependednt way (limits.h in linux) # TODO: Need to set this in a platform dependednt way (limits.h in linux)
@ -96,7 +100,11 @@ class Device(Structure):
class Bus(Structure): class Bus(Structure):
@apply @apply
def device_list(): 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): def fget(self):
if _libusb.usb_find_devices() < 0: if _libusb.usb_find_devices() < 0:
raise Error('Unable to search for USB devices') raise Error('Unable to search for USB devices')
@ -162,7 +170,7 @@ class DeviceHandle(Structure):
if rsize < size: if rsize < size:
raise Error('Could not read ' + str(size) + ' bytes on the '\ raise Error('Could not read ' + str(size) + ' bytes on the '\
'control bus. Read: ' + str(rsize) + ' bytes.') 'control bus. Read: ' + str(rsize) + ' bytes.')
return list(arr) return tuple(arr)
else: else:
ArrayType = c_byte * size ArrayType = c_byte * size
_libusb.usb_control_msg.argtypes = [POINTER(DeviceHandle), c_int, \ _libusb.usb_control_msg.argtypes = [POINTER(DeviceHandle), c_int, \
@ -185,7 +193,7 @@ class DeviceHandle(Structure):
if rsize < size: if rsize < size:
raise Error('Could not read ' + str(size) + ' bytes on the '\ raise Error('Could not read ' + str(size) + ' bytes on the '\
'bulk bus. Read: ' + str(rsize) + ' bytes.') 'bulk bus. Read: ' + str(rsize) + ' bytes.')
return list(arr) return tuple(arr)
def bulk_write(self, endpoint, bytes, timeout=100): def bulk_write(self, endpoint, bytes, timeout=100):
size = len(bytes) size = len(bytes)
@ -268,17 +276,3 @@ def get_device_by_id(idVendor, idProduct):
if dev.device_descriptor.idVendor == idVendor and \ if dev.device_descriptor.idVendor == idVendor and \
dev.device_descriptor.idProduct == idProduct: dev.device_descriptor.idProduct == idProduct:
return dev 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()

View File

@ -63,7 +63,7 @@ class TransferBuffer(list):
""" """
Represents raw (unstructured) data packets sent over the usb bus. Represents raw (unstructured) data packets sent over the usb bus.
C{TransferBuffer} is a wrapper around the tuples used by L{PyUSB<usb>} 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 It has convenience methods to read and write data from the underlying buffer. See
L{TransferBuffer.pack} and L{TransferBuffer.unpack}. L{TransferBuffer.pack} and L{TransferBuffer.unpack}.
""" """