mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Added time sync functionality. Now libprs500 automatically syncs the time on the device to local time everytime a connection is opened to the device
Added option to replace existing files to put_file for convenience
This commit is contained in:
parent
3b21f2c4dd
commit
fc5b8a22e6
@ -158,10 +158,10 @@ class PRS500Device(object):
|
||||
try:
|
||||
if not dev.handle: dev.open()
|
||||
res = func(*args, **kwargs)
|
||||
except ArgumentError, e:
|
||||
except ArgumentError:
|
||||
if not kwargs.has_key("end_session") or kwargs["end_session"]:
|
||||
dev._send_validated_command(EndSession())
|
||||
raise e
|
||||
raise
|
||||
except usb.USBError, e:
|
||||
if "No such device" in str(e):
|
||||
raise DeviceError()
|
||||
@ -172,7 +172,7 @@ class PRS500Device(object):
|
||||
dev.close()
|
||||
raise ProtocolError("There was an unknown error in the protocol. Contact " + AUTHOR)
|
||||
dev.close()
|
||||
raise e
|
||||
raise
|
||||
if not kwargs.has_key("end_session") or kwargs["end_session"]:
|
||||
dev._send_validated_command(EndSession())
|
||||
return res
|
||||
@ -182,7 +182,7 @@ class PRS500Device(object):
|
||||
def __init__(self, log_packets=False, report_progress=None) :
|
||||
"""
|
||||
@param log_packets: If true the packet stream to/from the device is logged
|
||||
@param: report_progress: Function that is called with a % progress (number between 0 and 100) for various tasks
|
||||
@param report_progress: Function that is called with a % progress (number between 0 and 100) for various tasks
|
||||
If it is called with -1 that means that the task does not have any progress information
|
||||
"""
|
||||
self.device = self.device_descriptor.getDevice() #: The actual device (PyUSB object)
|
||||
@ -237,6 +237,9 @@ class PRS500Device(object):
|
||||
self._send_validated_command(UnlockDevice(key=0x312d))
|
||||
if res.code != 0:
|
||||
raise ProtocolError("Unlocking of device not implemented. Remove locking and retry.")
|
||||
res = self._send_validated_command(SetTime())
|
||||
if res.code != 0:
|
||||
raise ProtocolError("Could not set time on device")
|
||||
|
||||
def close(self):
|
||||
""" Release device interface """
|
||||
@ -476,8 +479,8 @@ class PRS500Device(object):
|
||||
try:
|
||||
dest = self.path_properties(path, end_session=False)
|
||||
except PathError, e:
|
||||
if "does not exist" in str(e): return (False, None)
|
||||
else: raise e
|
||||
if "does not exist" in str(e) or "not mounted" in str(e): return (False, None)
|
||||
else: raise
|
||||
return (True, dest)
|
||||
|
||||
@safe
|
||||
@ -497,22 +500,23 @@ class PRS500Device(object):
|
||||
|
||||
|
||||
@safe
|
||||
def put_file(self, infile, path, end_session=True):
|
||||
def put_file(self, infile, path, replace_file=False, end_session=True):
|
||||
"""
|
||||
Put infile onto the devoce at path
|
||||
@param infile: An open file object
|
||||
@param path: The path on the device at which to put infile. It should point to an existing directory.
|
||||
@param replace_file: If True and path points to a file that already exists, it is replaced
|
||||
"""
|
||||
exists, dest = self._exists(path)
|
||||
if exists:
|
||||
if not dest.is_dir: raise PathError("Cannot write to " + path + " as it already exists")
|
||||
if not path.endswith("/"): path += "/"
|
||||
path += os.path.basename(infile.name)
|
||||
exists, dest = self._exists(path)
|
||||
if exists: raise PathError("Cannot write to " + path + " as it already exists")
|
||||
res = self._send_validated_command(FileCreate(path))
|
||||
if res.code != 0:
|
||||
raise ProtocolError("There was an error creating device:"+path+". Response code: "+hex(res.code))
|
||||
if dest.is_dir:
|
||||
if not path.endswith("/"): path += "/"
|
||||
path += os.path.basename(infile.name)
|
||||
return self.put_file(infile, path, replace_file=replace_file, end_session=False)
|
||||
elif not replace_file: raise PathError("Cannot write to " + path + " as it already exists")
|
||||
else:
|
||||
res = self._send_validated_command(FileCreate(path))
|
||||
if res.code != 0: raise ProtocolError("There was an error creating "+path+" on device. Response code: "+hex(res.code))
|
||||
chunk_size = 0x8000
|
||||
data_left = True
|
||||
res = self._send_validated_command(FileOpen(path, mode=FileOpen.WRITE))
|
||||
@ -611,7 +615,7 @@ class PRS500Device(object):
|
||||
return BookList(prefix=prefix, root=root, file=file)
|
||||
|
||||
@safe
|
||||
def add_book(self, infile, name, info, booklists, oncard=False, end_session=True):
|
||||
def add_book(self, infile, name, info, booklists, oncard=False, sync_booklists=False, end_session=True):
|
||||
"""
|
||||
Add a book to the device. If oncard is True then the book is copied to the card rather than main memory.
|
||||
|
||||
@ -635,6 +639,24 @@ class PRS500Device(object):
|
||||
else: name = "books/"+name
|
||||
path = prefix + name
|
||||
self.put_file(infile, path, end_session=False)
|
||||
if oncard: booklists[1].add_book(info, name, size)
|
||||
else: booklists[0].add_book(info, name, size)
|
||||
bl = booklists[1] if oncard else booklists[0]
|
||||
bl.add_book(info, name, size)
|
||||
fix_ids(booklists[0], booklists[1])
|
||||
if sync_booklists:
|
||||
self.upload_book_list(booklists[0], end_session=False)
|
||||
if len(booklists[1]):
|
||||
self.upload_book_list(booklists[1], end_session=False)
|
||||
|
||||
@safe
|
||||
def upload_book_list(self, booklist, end_session=True):
|
||||
if not len(booklist): raise ArgumentError("booklist is empty")
|
||||
path = self.MEDIA_XML
|
||||
if not booklist.prefix:
|
||||
card = self.card(end_session=True)
|
||||
if not card: raise ArgumentError("Cannot upload list to card as card is not present")
|
||||
path = card + self.CACHE_XML
|
||||
f = TemporaryFile()
|
||||
booklist.write(f)
|
||||
f.seek(0)
|
||||
self.put_file(f, path, replace_file=True, end_session=False)
|
||||
f.close()
|
||||
|
@ -37,7 +37,7 @@ Responses inherit Command as they share header structure.
|
||||
Answers are organized as follows: G{classtree Answer}
|
||||
"""
|
||||
|
||||
import struct
|
||||
import struct, time
|
||||
from errors import PacketError
|
||||
|
||||
DWORD = "<I" #: Unsigned integer little endian encoded in 4 bytes
|
||||
@ -205,7 +205,6 @@ class Command(TransferBuffer):
|
||||
Command numbers are:
|
||||
0 GetUsbProtocolVersion
|
||||
1 ReqEndSession
|
||||
|
||||
10 FskFileOpen
|
||||
11 FskFileClose
|
||||
12 FskGetSize
|
||||
@ -219,19 +218,15 @@ class Command(TransferBuffer):
|
||||
1A FskFileCreate
|
||||
1B FskFileDelete
|
||||
1C FskFileRename
|
||||
|
||||
30 FskFileCreateDirectory
|
||||
31 FskFileDeleteDirectory
|
||||
32 FskFileRenameDirectory
|
||||
33 FskDirectoryIteratorNew
|
||||
34 FskDirectoryIteratorDispose
|
||||
35 FskDirectoryIteratorGetNext
|
||||
|
||||
52 FskVolumeGetInfo
|
||||
53 FskVolumeGetInfoFromPath
|
||||
|
||||
80 FskFileTerminate
|
||||
|
||||
100 ConnectDevice
|
||||
101 GetProperty
|
||||
102 GetMediaInfo
|
||||
@ -240,12 +235,10 @@ class Command(TransferBuffer):
|
||||
105 DeviceBeginEnd
|
||||
106 UnlockDevice
|
||||
107 SetBulkSize
|
||||
|
||||
110 GetHttpRequest
|
||||
111 SetHttpRespponse
|
||||
112 Needregistration
|
||||
114 GetMarlinState
|
||||
|
||||
200 ReqDiwStart
|
||||
201 SetDiwPersonalkey
|
||||
202 GetDiwPersonalkey
|
||||
@ -270,7 +263,6 @@ class Command(TransferBuffer):
|
||||
214 GetDiwMacaddress
|
||||
215 ReqDiwTest
|
||||
216 ReqDiwDeletekey
|
||||
|
||||
300 UpdateChangemode
|
||||
301 UpdateDeletePartition
|
||||
302 UpdateCreatePartition
|
||||
@ -309,6 +301,36 @@ class Command(TransferBuffer):
|
||||
TransferBuffer.__init__(self, packet)
|
||||
|
||||
|
||||
class SetTime(Command):
|
||||
"""
|
||||
Set time on device. All fields refer to time in the GMT time zone.
|
||||
@todo: figure out what the 4 bytes starting at byte 16 are for
|
||||
"""
|
||||
NUMBER = 0x104
|
||||
|
||||
unknown = field(start=0x10, fmt=DWORD) #: Haven't figured out what this is for. Seems to always be set to 4294966816L
|
||||
year = field(start=0x14, fmt=DWORD) #: year e.g. 2006
|
||||
month = field(start=0x18, fmt=DWORD) #: month 1-12
|
||||
day = field(start=0x1c, fmt=DWORD) #: day 1-31
|
||||
hour = field(start=0x20, fmt=DWORD) #: hour 0-23
|
||||
minute = field(start=0x24, fmt=DWORD) #: minute 0-59
|
||||
second = field(start=0x28, fmt=DWORD) #: second 0-59
|
||||
|
||||
def __init__(self, t=None):
|
||||
""" @param t: time as an epoch """
|
||||
self.number = SetTime.NUMBER
|
||||
self.type = 0x01
|
||||
self.length = 0x1c
|
||||
self.unknown = 4294966816L
|
||||
if not t: t = time.time()
|
||||
t = time.gmtime(t)
|
||||
self.year = t[0]
|
||||
self.month = t[1]
|
||||
self.day = t[2]
|
||||
self.hour = t[3]
|
||||
self.minute = t[4]
|
||||
self.second = t[5] if t[5] < 60 else 59 # Hack you should actually update the entire time tree is second is > 59
|
||||
|
||||
|
||||
class ShortCommand(Command):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user