mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05: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