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:
|
try:
|
||||||
if not dev.handle: dev.open()
|
if not dev.handle: dev.open()
|
||||||
res = func(*args, **kwargs)
|
res = func(*args, **kwargs)
|
||||||
except ArgumentError, e:
|
except ArgumentError:
|
||||||
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 e
|
raise
|
||||||
except usb.USBError, e:
|
except usb.USBError, e:
|
||||||
if "No such device" in str(e):
|
if "No such device" in str(e):
|
||||||
raise DeviceError()
|
raise DeviceError()
|
||||||
@ -172,7 +172,7 @@ class PRS500Device(object):
|
|||||||
dev.close()
|
dev.close()
|
||||||
raise ProtocolError("There was an unknown error in the protocol. Contact " + AUTHOR)
|
raise ProtocolError("There was an unknown error in the protocol. Contact " + AUTHOR)
|
||||||
dev.close()
|
dev.close()
|
||||||
raise e
|
raise
|
||||||
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())
|
||||||
return res
|
return res
|
||||||
@ -182,7 +182,7 @@ class PRS500Device(object):
|
|||||||
def __init__(self, log_packets=False, report_progress=None) :
|
def __init__(self, log_packets=False, report_progress=None) :
|
||||||
"""
|
"""
|
||||||
@param log_packets: If true the packet stream to/from the device is logged
|
@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
|
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)
|
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))
|
self._send_validated_command(UnlockDevice(key=0x312d))
|
||||||
if res.code != 0:
|
if res.code != 0:
|
||||||
raise ProtocolError("Unlocking of device not implemented. Remove locking and retry.")
|
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):
|
def close(self):
|
||||||
""" Release device interface """
|
""" Release device interface """
|
||||||
@ -476,8 +479,8 @@ class PRS500Device(object):
|
|||||||
try:
|
try:
|
||||||
dest = self.path_properties(path, end_session=False)
|
dest = self.path_properties(path, end_session=False)
|
||||||
except PathError, e:
|
except PathError, e:
|
||||||
if "does not exist" in str(e): return (False, None)
|
if "does not exist" in str(e) or "not mounted" in str(e): return (False, None)
|
||||||
else: raise e
|
else: raise
|
||||||
return (True, dest)
|
return (True, dest)
|
||||||
|
|
||||||
@safe
|
@safe
|
||||||
@ -497,22 +500,23 @@ class PRS500Device(object):
|
|||||||
|
|
||||||
|
|
||||||
@safe
|
@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
|
Put infile onto the devoce at path
|
||||||
@param infile: An open file object
|
@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 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)
|
exists, dest = self._exists(path)
|
||||||
if exists:
|
if exists:
|
||||||
if not dest.is_dir: raise PathError("Cannot write to " + path + " as it already exists")
|
if dest.is_dir:
|
||||||
if not path.endswith("/"): path += "/"
|
if not path.endswith("/"): path += "/"
|
||||||
path += os.path.basename(infile.name)
|
path += os.path.basename(infile.name)
|
||||||
exists, dest = self._exists(path)
|
return self.put_file(infile, path, replace_file=replace_file, end_session=False)
|
||||||
if exists: raise PathError("Cannot write to " + path + " as it already exists")
|
elif not replace_file: raise PathError("Cannot write to " + path + " as it already exists")
|
||||||
res = self._send_validated_command(FileCreate(path))
|
else:
|
||||||
if res.code != 0:
|
res = self._send_validated_command(FileCreate(path))
|
||||||
raise ProtocolError("There was an error creating device:"+path+". Response code: "+hex(res.code))
|
if res.code != 0: raise ProtocolError("There was an error creating "+path+" on device. Response code: "+hex(res.code))
|
||||||
chunk_size = 0x8000
|
chunk_size = 0x8000
|
||||||
data_left = True
|
data_left = True
|
||||||
res = self._send_validated_command(FileOpen(path, mode=FileOpen.WRITE))
|
res = self._send_validated_command(FileOpen(path, mode=FileOpen.WRITE))
|
||||||
@ -582,7 +586,7 @@ class PRS500Device(object):
|
|||||||
def card(self, end_session=True):
|
def card(self, end_session=True):
|
||||||
card = None
|
card = None
|
||||||
if self._exists("a:/")[0]: card = "a:"
|
if self._exists("a:/")[0]: card = "a:"
|
||||||
if self._exists("b:/")[0]: card = "b:"
|
if self._exists("b:/")[0]: card = "b:"
|
||||||
return card
|
return card
|
||||||
|
|
||||||
@safe
|
@safe
|
||||||
@ -611,7 +615,7 @@ class PRS500Device(object):
|
|||||||
return BookList(prefix=prefix, root=root, file=file)
|
return BookList(prefix=prefix, root=root, file=file)
|
||||||
|
|
||||||
@safe
|
@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.
|
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
|
else: name = "books/"+name
|
||||||
path = prefix + name
|
path = prefix + name
|
||||||
self.put_file(infile, path, end_session=False)
|
self.put_file(infile, path, end_session=False)
|
||||||
if oncard: booklists[1].add_book(info, name, size)
|
bl = booklists[1] if oncard else booklists[0]
|
||||||
else: booklists[0].add_book(info, name, size)
|
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}
|
Answers are organized as follows: G{classtree Answer}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import struct
|
import struct, time
|
||||||
from errors import PacketError
|
from errors import PacketError
|
||||||
|
|
||||||
DWORD = "<I" #: Unsigned integer little endian encoded in 4 bytes
|
DWORD = "<I" #: Unsigned integer little endian encoded in 4 bytes
|
||||||
@ -204,8 +204,7 @@ class Command(TransferBuffer):
|
|||||||
|
|
||||||
Command numbers are:
|
Command numbers are:
|
||||||
0 GetUsbProtocolVersion
|
0 GetUsbProtocolVersion
|
||||||
1 ReqEndSession
|
1 ReqEndSession
|
||||||
|
|
||||||
10 FskFileOpen
|
10 FskFileOpen
|
||||||
11 FskFileClose
|
11 FskFileClose
|
||||||
12 FskGetSize
|
12 FskGetSize
|
||||||
@ -218,20 +217,16 @@ class Command(TransferBuffer):
|
|||||||
19 FskFileSetFileInfo
|
19 FskFileSetFileInfo
|
||||||
1A FskFileCreate
|
1A FskFileCreate
|
||||||
1B FskFileDelete
|
1B FskFileDelete
|
||||||
1C FskFileRename
|
1C FskFileRename
|
||||||
|
|
||||||
30 FskFileCreateDirectory
|
30 FskFileCreateDirectory
|
||||||
31 FskFileDeleteDirectory
|
31 FskFileDeleteDirectory
|
||||||
32 FskFileRenameDirectory
|
32 FskFileRenameDirectory
|
||||||
33 FskDirectoryIteratorNew
|
33 FskDirectoryIteratorNew
|
||||||
34 FskDirectoryIteratorDispose
|
34 FskDirectoryIteratorDispose
|
||||||
35 FskDirectoryIteratorGetNext
|
35 FskDirectoryIteratorGetNext
|
||||||
|
|
||||||
52 FskVolumeGetInfo
|
52 FskVolumeGetInfo
|
||||||
53 FskVolumeGetInfoFromPath
|
53 FskVolumeGetInfoFromPath
|
||||||
|
80 FskFileTerminate
|
||||||
80 FskFileTerminate
|
|
||||||
|
|
||||||
100 ConnectDevice
|
100 ConnectDevice
|
||||||
101 GetProperty
|
101 GetProperty
|
||||||
102 GetMediaInfo
|
102 GetMediaInfo
|
||||||
@ -239,13 +234,11 @@ class Command(TransferBuffer):
|
|||||||
104 SetTime
|
104 SetTime
|
||||||
105 DeviceBeginEnd
|
105 DeviceBeginEnd
|
||||||
106 UnlockDevice
|
106 UnlockDevice
|
||||||
107 SetBulkSize
|
107 SetBulkSize
|
||||||
|
|
||||||
110 GetHttpRequest
|
110 GetHttpRequest
|
||||||
111 SetHttpRespponse
|
111 SetHttpRespponse
|
||||||
112 Needregistration
|
112 Needregistration
|
||||||
114 GetMarlinState
|
114 GetMarlinState
|
||||||
|
|
||||||
200 ReqDiwStart
|
200 ReqDiwStart
|
||||||
201 SetDiwPersonalkey
|
201 SetDiwPersonalkey
|
||||||
202 GetDiwPersonalkey
|
202 GetDiwPersonalkey
|
||||||
@ -269,8 +262,7 @@ class Command(TransferBuffer):
|
|||||||
213 ReqDiwFactoryinitialize
|
213 ReqDiwFactoryinitialize
|
||||||
214 GetDiwMacaddress
|
214 GetDiwMacaddress
|
||||||
215 ReqDiwTest
|
215 ReqDiwTest
|
||||||
216 ReqDiwDeletekey
|
216 ReqDiwDeletekey
|
||||||
|
|
||||||
300 UpdateChangemode
|
300 UpdateChangemode
|
||||||
301 UpdateDeletePartition
|
301 UpdateDeletePartition
|
||||||
302 UpdateCreatePartition
|
302 UpdateCreatePartition
|
||||||
@ -308,7 +300,37 @@ class Command(TransferBuffer):
|
|||||||
raise PacketError(str(self.__class__)[7:-2] + " packets must have length atleast 16")
|
raise PacketError(str(self.__class__)[7:-2] + " packets must have length atleast 16")
|
||||||
TransferBuffer.__init__(self, packet)
|
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):
|
class ShortCommand(Command):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user