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:
Kovid Goyal 2006-12-12 01:31:51 +00:00
parent 3b21f2c4dd
commit fc5b8a22e6
2 changed files with 82 additions and 38 deletions

View File

@ -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()

View File

@ -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):