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)
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))
@ -582,7 +586,7 @@ class PRS500Device(object):
def card(self, end_session=True):
card = None
if self._exists("a:/")[0]: card = "a:"
if self._exists("b:/")[0]: card = "b:"
if self._exists("b:/")[0]: card = "b:"
return card
@safe
@ -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
@ -204,8 +204,7 @@ class Command(TransferBuffer):
Command numbers are:
0 GetUsbProtocolVersion
1 ReqEndSession
1 ReqEndSession
10 FskFileOpen
11 FskFileClose
12 FskGetSize
@ -218,20 +217,16 @@ class Command(TransferBuffer):
19 FskFileSetFileInfo
1A FskFileCreate
1B FskFileDelete
1C FskFileRename
1C FskFileRename
30 FskFileCreateDirectory
31 FskFileDeleteDirectory
32 FskFileRenameDirectory
33 FskDirectoryIteratorNew
34 FskDirectoryIteratorDispose
35 FskDirectoryIteratorGetNext
35 FskDirectoryIteratorGetNext
52 FskVolumeGetInfo
53 FskVolumeGetInfoFromPath
80 FskFileTerminate
53 FskVolumeGetInfoFromPath
80 FskFileTerminate
100 ConnectDevice
101 GetProperty
102 GetMediaInfo
@ -239,13 +234,11 @@ class Command(TransferBuffer):
104 SetTime
105 DeviceBeginEnd
106 UnlockDevice
107 SetBulkSize
107 SetBulkSize
110 GetHttpRequest
111 SetHttpRespponse
112 Needregistration
114 GetMarlinState
114 GetMarlinState
200 ReqDiwStart
201 SetDiwPersonalkey
202 GetDiwPersonalkey
@ -269,8 +262,7 @@ class Command(TransferBuffer):
213 ReqDiwFactoryinitialize
214 GetDiwMacaddress
215 ReqDiwTest
216 ReqDiwDeletekey
216 ReqDiwDeletekey
300 UpdateChangemode
301 UpdateDeletePartition
302 UpdateCreatePartition
@ -308,7 +300,37 @@ class Command(TransferBuffer):
raise PacketError(str(self.__class__)[7:-2] + " packets must have length atleast 16")
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):