mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-07 09:01:38 -04:00
e-implemented prstypes using descriptors, making the types even more struct like and reducing the code size by half. It is now very easy to define new types.
This commit is contained in:
parent
df077ebfbe
commit
7e1ca9880b
@ -209,7 +209,7 @@ class PRS500Device(object):
|
|||||||
packet = self._bulk_read_packet(data_type=data_type, size=packet_size)
|
packet = self._bulk_read_packet(data_type=data_type, size=packet_size)
|
||||||
bytes_left -= len(packet)
|
bytes_left -= len(packet)
|
||||||
packets.append(packet)
|
packets.append(packet)
|
||||||
self._send_validated_command(AcknowledgeBulkRead(packets[0].id), cnumber=command_number)
|
self._send_validated_command(AcknowledgeBulkRead(packets[0].number), cnumber=command_number)
|
||||||
return packets
|
return packets
|
||||||
|
|
||||||
def _test_bulk_reads(self):
|
def _test_bulk_reads(self):
|
||||||
|
@ -40,8 +40,6 @@ Answers are organized as follows: G{classtree Answer}
|
|||||||
import struct
|
import struct
|
||||||
from errors import PacketError
|
from errors import PacketError
|
||||||
|
|
||||||
BYTE = "<B" #: Unsigned char little endian encoded in 1 byte
|
|
||||||
WORD = "<H" #: Unsigned short little endian encoded in 2 bytes
|
|
||||||
DWORD = "<I" #: Unsigned integer little endian encoded in 4 bytes
|
DWORD = "<I" #: Unsigned integer little endian encoded in 4 bytes
|
||||||
DDWORD = "<Q" #: Unsigned long long little endian encoded in 8 bytes
|
DDWORD = "<Q" #: Unsigned long long little endian encoded in 8 bytes
|
||||||
|
|
||||||
@ -120,7 +118,7 @@ class TransferBuffer(list):
|
|||||||
@param start: Position in buffer at which to write encoded data
|
@param start: Position in buffer at which to write encoded data
|
||||||
"""
|
"""
|
||||||
self[start:start+struct.calcsize(fmt)] = [ ord(i) for i in struct.pack(fmt, val) ]
|
self[start:start+struct.calcsize(fmt)] = [ ord(i) for i in struct.pack(fmt, val) ]
|
||||||
|
|
||||||
def _normalize(self):
|
def _normalize(self):
|
||||||
""" Replace negative bytes in C{self} by 256 + byte """
|
""" Replace negative bytes in C{self} by 256 + byte """
|
||||||
for i in range(len(self)):
|
for i in range(len(self)):
|
||||||
@ -143,84 +141,136 @@ class TransferBuffer(list):
|
|||||||
return sign + h
|
return sign + h
|
||||||
|
|
||||||
|
|
||||||
|
class field(object):
|
||||||
|
""" A U{Descriptor<http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html>}, that implements access
|
||||||
|
to protocol packets in a human readable way.
|
||||||
|
"""
|
||||||
|
def __init__(self, start=16, fmt=DWORD):
|
||||||
|
"""
|
||||||
|
@param start: The byte at which this field is stored in the buffer
|
||||||
|
@param fmt: The packing format for this field. See U{struct<http://docs.python.org/lib/module-struct.html>}.
|
||||||
|
"""
|
||||||
|
self._fmt, self._start = fmt, start
|
||||||
|
|
||||||
|
def __get__(self, obj, typ=None):
|
||||||
|
return obj.unpack(start=self._start, fmt=self._fmt)[0]
|
||||||
|
|
||||||
|
def __set__(self, obj, val):
|
||||||
|
obj.pack(val, start=self._start, fmt=self._fmt)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self._fmt == DWORD: typ = "unsigned int"
|
||||||
|
if self._fmt == DDWORD: typ = "unsigned long long"
|
||||||
|
return "An " + typ + " stored in " + str(struct.calcsize(self._fmt)) + " bytes starting at byte " + str(self._start)
|
||||||
|
|
||||||
|
class stringfield(object):
|
||||||
|
""" A field storing a variable length string. """
|
||||||
|
def __init__(self, length_field, start=16):
|
||||||
|
"""
|
||||||
|
@param length_field: A U{Descriptor<http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html>}
|
||||||
|
that returns the length of the string.
|
||||||
|
@param start: The byte at which this field is stored in the buffer
|
||||||
|
"""
|
||||||
|
self._length_field = length_field
|
||||||
|
self._start = start
|
||||||
|
|
||||||
|
def __get__(self, obj, typ=None):
|
||||||
|
length = str(self._length_field.__get__(obj))
|
||||||
|
return obj.unpack(start=self._start, fmt="<"+length+"s")[0]
|
||||||
|
|
||||||
|
def __set__(self, obj, val):
|
||||||
|
obj.pack(val, start=self._start, fmt="<"+str(len(val))+"s")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "A string starting at byte " + str(self._start)
|
||||||
|
|
||||||
class Command(TransferBuffer):
|
class Command(TransferBuffer):
|
||||||
|
|
||||||
""" Defines the structure of command packets sent to the device. """
|
""" Defines the structure of command packets sent to the device. """
|
||||||
|
|
||||||
|
number = field(start=0, fmt=DWORD)
|
||||||
|
"""
|
||||||
|
Command number. C{unsigned int} stored in 4 bytes at byte 0.
|
||||||
|
|
||||||
def __init__(self, packet):
|
Command numbers are:
|
||||||
"""
|
0 GetUsbProtocolVersion
|
||||||
@param packet: len(packet) > 15 or packet > 15
|
1 ReqUsbConnect
|
||||||
"""
|
|
||||||
if ("__len__" in dir(packet) and len(packet) < 16) or ("__len__" not in dir(packet) and packet < 16):
|
10 FskFileOpen
|
||||||
raise PacketError(str(self.__class__)[7:-2] + " packets must have length atleast 16")
|
11 FskFileClose
|
||||||
TransferBuffer.__init__(self, packet)
|
12 FskGetSize
|
||||||
|
13 FskSetSize
|
||||||
|
14 FskFileSetPosition
|
||||||
|
15 FskGetPosition
|
||||||
|
16 FskFileRead
|
||||||
|
17 FskFileWrite
|
||||||
|
18 FskFileGetFileInfo
|
||||||
|
19 FskFileSetFileInfo
|
||||||
|
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
|
||||||
|
103 GetFreeSpace
|
||||||
|
104 SetTime
|
||||||
|
105 DeviceBeginEnd
|
||||||
|
106 UnlockDevice
|
||||||
|
107 SetBulkSize
|
||||||
|
|
||||||
|
110 GetHttpRequest
|
||||||
|
111 SetHttpRespponse
|
||||||
|
112 Needregistration
|
||||||
|
114 GetMarlinState
|
||||||
|
|
||||||
@apply
|
200 ReqDiwStart
|
||||||
def number():
|
201 SetDiwPersonalkey
|
||||||
doc =\
|
202 GetDiwPersonalkey
|
||||||
"""
|
203 SetDiwDhkey
|
||||||
Command number. C{unsigned int} stored in 4 bytes at byte 0.
|
204 GetDiwDhkey
|
||||||
|
205 SetDiwChallengeserver
|
||||||
|
206 GetDiwChallengeserver
|
||||||
|
207 GetDiwChallengeclient
|
||||||
|
208 SetDiwChallengeclient
|
||||||
|
209 GetDiwVersion
|
||||||
|
20A SetDiwWriteid
|
||||||
|
20B GetDiwWriteid
|
||||||
|
20C SetDiwSerial
|
||||||
|
20D GetDiwModel
|
||||||
|
20C SetDiwSerial
|
||||||
|
20E GetDiwDeviceid
|
||||||
|
20F GetDiwSerial
|
||||||
|
210 ReqDiwCheckservicedata
|
||||||
|
211 ReqDiwCheckiddata
|
||||||
|
212 ReqDiwCheckserialdata
|
||||||
|
213 ReqDiwFactoryinitialize
|
||||||
|
214 GetDiwMacaddress
|
||||||
|
215 ReqDiwTest
|
||||||
|
216 ReqDiwDeletekey
|
||||||
|
|
||||||
Observed command numbers are:
|
300 UpdateChangemode
|
||||||
1. 0x00
|
301 UpdateDeletePartition
|
||||||
Test bulk read
|
302 UpdateCreatePartition
|
||||||
2. 0x01
|
303 UpdateCreatePartitionWithImage
|
||||||
End session
|
304 UpdateGetPartitionSize
|
||||||
3. 0x0101
|
"""
|
||||||
Ask for device information
|
|
||||||
4. 0x1000
|
type = field(start=4, fmt=DDWORD) #: Known types are 0x00 and 0x01. Acknowledge commands are always type 0x00
|
||||||
Acknowledge
|
|
||||||
5. 0x107
|
length = field(start=12, fmt=DWORD) #: Length of the data part of this packet
|
||||||
Purpose unknown, occurs in the beginning of sessions duing command testing. Best guess is some sort of OK packet
|
|
||||||
6. 0x106
|
|
||||||
Purpose unknown, occurs in the beginning of sessions duing command testing. Best guess is some sort of OK packet
|
|
||||||
7. 0x18
|
|
||||||
Ask for information about a file
|
|
||||||
8. 0x33
|
|
||||||
Open directory for reading
|
|
||||||
9. 0x34
|
|
||||||
Close directory
|
|
||||||
10. 0x35
|
|
||||||
Ask for next item in the directory
|
|
||||||
11. 0x10
|
|
||||||
File open command
|
|
||||||
12. 0x11
|
|
||||||
File close command
|
|
||||||
13. 0x16
|
|
||||||
File read command
|
|
||||||
"""
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=0, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=0, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def type():
|
|
||||||
doc =\
|
|
||||||
""" Command type. C{unsigned long long} stored in 8 bytes at byte 4. Known types 0x00, 0x01. Not sure what the type means. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=4, fmt=DDWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=4, fmt=DDWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def length():
|
|
||||||
doc =\
|
|
||||||
""" Length in bytes of the data part of the query. C{unsigned int} stored in 4 bytes at byte 12. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=12, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=12, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def data():
|
def data():
|
||||||
@ -239,13 +289,23 @@ class Command(TransferBuffer):
|
|||||||
self.length = len(buffer)
|
self.length = len(buffer)
|
||||||
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
|
|
||||||
class ShortCommand(Command):
|
def __init__(self, packet):
|
||||||
|
"""
|
||||||
|
@param packet: len(packet) > 15 or packet > 15
|
||||||
|
"""
|
||||||
|
if ("__len__" in dir(packet) and len(packet) < 16) or ("__len__" not in dir(packet) and packet < 16):
|
||||||
|
raise PacketError(str(self.__class__)[7:-2] + " packets must have length atleast 16")
|
||||||
|
TransferBuffer.__init__(self, packet)
|
||||||
|
|
||||||
""" A L{Command} whoose data section is 4 bytes long """
|
|
||||||
|
|
||||||
|
class ShortCommand(Command):
|
||||||
|
|
||||||
|
""" A L{Command} whoose data section is 4 bytes long """
|
||||||
|
|
||||||
SIZE = 20 #: Packet size in bytes
|
SIZE = 20 #: Packet size in bytes
|
||||||
|
command = field(start=16, fmt=DWORD) #: Usually carries additional information
|
||||||
|
|
||||||
def __init__(self, number=0x00, type=0x00, command=0x00):
|
def __init__(self, number=0x00, type=0x00, command=0x00):
|
||||||
"""
|
"""
|
||||||
@ -259,93 +319,6 @@ class ShortCommand(Command):
|
|||||||
self.length = 4
|
self.length = 4
|
||||||
self.command = command
|
self.command = command
|
||||||
|
|
||||||
@apply
|
|
||||||
def command():
|
|
||||||
doc =\
|
|
||||||
""" The command. Not sure why this is needed in addition to Command.number. C{unsigned int} 4 bytes long at byte 16. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
class FreeSpaceQuery(Command):
|
|
||||||
""" Query the free space available """
|
|
||||||
NUMBER = 0x53 #; Command number
|
|
||||||
def __init__(self, path):
|
|
||||||
Command.__init__(self, 20 + len(path))
|
|
||||||
self.number=FreeSpaceQuery.NUMBER
|
|
||||||
self.type=0x01
|
|
||||||
self.length = 4 + len(path)
|
|
||||||
self.path_length = len(path)
|
|
||||||
self.path = path
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path_length():
|
|
||||||
doc =\
|
|
||||||
""" The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path():
|
|
||||||
doc =\
|
|
||||||
""" The path. Stored as a string at byte 20. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt="<"+str(self.path_length)+"s")
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
|
|
||||||
class DirOpen(Command):
|
|
||||||
|
|
||||||
""" Open a directory for reading its contents """
|
|
||||||
NUMBER = 0x33 #: Command number
|
|
||||||
|
|
||||||
def __init__(self, path):
|
|
||||||
Command.__init__(self, 20 + len(path))
|
|
||||||
self.number=DirOpen.NUMBER
|
|
||||||
self.type = 0x01
|
|
||||||
self.length = 4 + len(path)
|
|
||||||
self.path_length = len(path)
|
|
||||||
self.path = path
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path_length():
|
|
||||||
doc =\
|
|
||||||
""" The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path():
|
|
||||||
doc =\
|
|
||||||
""" The path. Stored as a string at byte 20. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt="<"+str(self.path_length)+"s")
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
class DirRead(ShortCommand):
|
class DirRead(ShortCommand):
|
||||||
""" The command that asks the device to send the next item in the list """
|
""" The command that asks the device to send the next item in the list """
|
||||||
NUMBER = 0x35 #: Command number
|
NUMBER = 0x35 #: Command number
|
||||||
@ -383,7 +356,7 @@ class LongCommand(Command):
|
|||||||
def command():
|
def command():
|
||||||
doc =\
|
doc =\
|
||||||
"""
|
"""
|
||||||
The command. Not sure why it is needed in addition to L{Command.number}.
|
Usually carries extra information needed for the command
|
||||||
It is a list of C{unsigned integers} of length between 1 and 4. 4 C{unsigned int} stored in 16 bytes at byte 16.
|
It is a list of C{unsigned integers} of length between 1 and 4. 4 C{unsigned int} stored in 16 bytes at byte 16.
|
||||||
"""
|
"""
|
||||||
def fget(self):
|
def fget(self):
|
||||||
@ -398,11 +371,34 @@ class LongCommand(Command):
|
|||||||
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
|
class PathCommand(Command):
|
||||||
|
""" Abstract class that defines structure common to all path related commands. """
|
||||||
|
|
||||||
|
path_length = field(start=16, fmt=DWORD) #: Length of the path to follow
|
||||||
|
path = stringfield(path_length, start=20) #: The path this query is about
|
||||||
|
def __init__(self, path, number, path_len_at_byte=16):
|
||||||
|
Command.__init__(self, path_len_at_byte+4+len(path))
|
||||||
|
self.path_length = len(path)
|
||||||
|
self.path = path
|
||||||
|
self.type = 0x01
|
||||||
|
self.length = len(self)-16
|
||||||
|
self.number = number
|
||||||
|
|
||||||
|
class FreeSpaceQuery(PathCommand):
|
||||||
|
""" Query the free space available """
|
||||||
|
NUMBER = 0x53 #; Command number
|
||||||
|
def __init__(self, path):
|
||||||
|
PathCommand.__init__(self, path, FreeSpaceQuery.NUMBER)
|
||||||
|
|
||||||
|
class DirOpen(PathCommand):
|
||||||
|
""" Open a directory for reading its contents """
|
||||||
|
NUMBER = 0x33 #: Command number
|
||||||
|
def __init__(self, path):
|
||||||
|
PathCommand.__init__(self, path, DirOpen.NUMBER)
|
||||||
|
|
||||||
|
|
||||||
class AcknowledgeBulkRead(LongCommand):
|
class AcknowledgeBulkRead(LongCommand):
|
||||||
|
|
||||||
""" Must be sent to device after a bulk read """
|
""" Must be sent to device after a bulk read """
|
||||||
|
|
||||||
def __init__(self, bulk_read_id):
|
def __init__(self, bulk_read_id):
|
||||||
""" bulk_read_id is an integer, the id of the bulk read we are acknowledging. See L{Answer.id} """
|
""" bulk_read_id is an integer, the id of the bulk read we are acknowledging. See L{Answer.id} """
|
||||||
LongCommand.__init__(self, number=0x1000, type=0x00, command=bulk_read_id)
|
LongCommand.__init__(self, number=0x1000, type=0x00, command=bulk_read_id)
|
||||||
@ -421,19 +417,17 @@ class FileClose(ShortCommand):
|
|||||||
def __init__(self, id):
|
def __init__(self, id):
|
||||||
ShortCommand.__init__(self, number=FileClose.NUMBER, type=0x01, command=id)
|
ShortCommand.__init__(self, number=FileClose.NUMBER, type=0x01, command=id)
|
||||||
|
|
||||||
class FileOpen(Command):
|
class FileOpen(PathCommand):
|
||||||
""" File open command """
|
""" File open command """
|
||||||
NUMBER = 0x10
|
NUMBER = 0x10 #: Command number
|
||||||
READ = 0x00
|
READ = 0x00 #: Open file in read mode
|
||||||
WRITE = 0x01
|
WRITE = 0x01 #: Open file in write mode
|
||||||
|
path_length = field(start=20, fmt=DWORD)
|
||||||
|
path = stringfield(path_length, start=24)
|
||||||
|
|
||||||
def __init__(self, path, mode=0x00):
|
def __init__(self, path, mode=0x00):
|
||||||
Command.__init__(self, 24 + len(path))
|
PathCommand.__init__(self, path, FileOpen.NUMBER, path_len_at_byte=20)
|
||||||
self.number=FileOpen.NUMBER
|
|
||||||
self.type = 0x01
|
|
||||||
self.length = 8 + len(path)
|
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.path_length = len(path)
|
|
||||||
self.path = path
|
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def mode():
|
def mode():
|
||||||
@ -447,34 +441,13 @@ class FileOpen(Command):
|
|||||||
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
@apply
|
|
||||||
def path_length():
|
|
||||||
doc =\
|
|
||||||
""" The length in bytes of the path to follow. C{unsigned int} stored at byte 20. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path():
|
|
||||||
doc =\
|
|
||||||
""" The path. Stored as a string at byte 24. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=24, fmt="<"+str(self.path_length)+"s")[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=24, fmt="<"+str(self.path_length)+"s")
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
class FileRead(Command):
|
class FileRead(Command):
|
||||||
""" Command to read from an open file """
|
""" Command to read from an open file """
|
||||||
NUMBER = 0x16 #: Command number to read from a file
|
NUMBER = 0x16 #: Command number to read from a file
|
||||||
|
id = field(start=16, fmt=DWORD) #: The file ID returned by a FileOpen command
|
||||||
|
offset = field(start=20, fmt=DDWORD) #: offset in the file at which to read
|
||||||
|
size = field(start=28, fmt=DWORD) #: The number of bytes to reead from file.
|
||||||
def __init__(self, id, offset, size):
|
def __init__(self, id, offset, size):
|
||||||
"""
|
"""
|
||||||
@param id: File identifier returned by a L{FileOpen} command
|
@param id: File identifier returned by a L{FileOpen} command
|
||||||
@ -487,93 +460,17 @@ class FileRead(Command):
|
|||||||
Command.__init__(self, 32)
|
Command.__init__(self, 32)
|
||||||
self.number=FileRead.NUMBER
|
self.number=FileRead.NUMBER
|
||||||
self.type = 0x01
|
self.type = 0x01
|
||||||
self.length = 32
|
self.length = 16
|
||||||
self.id = id
|
self.id = id
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.size = size
|
self.size = size
|
||||||
|
|
||||||
@apply
|
|
||||||
def id():
|
|
||||||
doc =\
|
|
||||||
""" The file ID returned by a FileOpen command. C{unsigned int} stored in 4 bytes at byte 16. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def offset():
|
|
||||||
doc =\
|
|
||||||
""" offset in the file at which to read. C{unsigned long long} stored in 8 bytes at byte 20. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt=DDWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt=DDWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def size():
|
|
||||||
doc =\
|
|
||||||
""" The number of bytes to read. C{unsigned int} stored in 4 bytes at byte 28. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=28, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=28, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PathQuery(Command):
|
|
||||||
|
class PathQuery(PathCommand):
|
||||||
"""
|
""" Defines structure of command that requests information about a path """
|
||||||
Defines structure of command that requests information about a path
|
NUMBER = 0x18 #: Command number
|
||||||
|
|
||||||
>>> print prstypes.PathQuery("/test/path/", number=prstypes.PathQuery.PROPERTIES)
|
|
||||||
1800 0000 0100 0000 0000 0000 0f00 0000 ................
|
|
||||||
0b00 0000 2f74 6573 742f 7061 7468 2f ..../test/path/
|
|
||||||
"""
|
|
||||||
NUMBER = 0x18 #: Command number
|
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
Command.__init__(self, 20 + len(path))
|
PathCommand.__init__(self, path, PathQuery.NUMBER)
|
||||||
self.number=PathQuery.NUMBER
|
|
||||||
self.type = 0x01
|
|
||||||
self.length = 4 + len(path)
|
|
||||||
self.path_length = len(path)
|
|
||||||
self.path = path
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path_length():
|
|
||||||
doc =\
|
|
||||||
""" The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def path():
|
|
||||||
doc =\
|
|
||||||
""" The path. Stored as a string at byte 20. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt="<"+str(self.path_length)+"s")
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
|
|
||||||
class Response(Command):
|
class Response(Command):
|
||||||
@ -584,6 +481,7 @@ class Response(Command):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
SIZE = 32 #: Size of response packets in the SONY protocol
|
SIZE = 32 #: Size of response packets in the SONY protocol
|
||||||
|
rnumber = field(start=16, fmt=DWORD) #: Response number, the command number of a command packet sent sometime before this packet was received
|
||||||
|
|
||||||
def __init__(self, packet):
|
def __init__(self, packet):
|
||||||
""" C{len(packet) == Response.SIZE} """
|
""" C{len(packet) == Response.SIZE} """
|
||||||
@ -593,22 +491,6 @@ class Response(Command):
|
|||||||
if self.number != 0x00001000:
|
if self.number != 0x00001000:
|
||||||
raise PacketError("Response packets must have their number set to " + hex(0x00001000))
|
raise PacketError("Response packets must have their number set to " + hex(0x00001000))
|
||||||
|
|
||||||
@apply
|
|
||||||
def rnumber():
|
|
||||||
doc =\
|
|
||||||
"""
|
|
||||||
The response number. C{unsigned int} stored in 4 bytes at byte 16.
|
|
||||||
|
|
||||||
It will be the command number from a command that was sent to the device sometime before this response.
|
|
||||||
"""
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def data():
|
def data():
|
||||||
doc =\
|
doc =\
|
||||||
@ -631,18 +513,8 @@ class ListResponse(Response):
|
|||||||
IS_EOL = 0xfffffffa #: There are no more entries in the list
|
IS_EOL = 0xfffffffa #: There are no more entries in the list
|
||||||
PATH_NOT_FOUND = 0xffffffd7 #: Queried path is not found
|
PATH_NOT_FOUND = 0xffffffd7 #: Queried path is not found
|
||||||
|
|
||||||
@apply
|
code = field(start=20, fmt=DWORD) #: Used to indicate conditions like EOL/Error/IsFile etc.
|
||||||
def code():
|
|
||||||
doc =\
|
|
||||||
""" The response code. Used to indicate conditions like EOL/Error/IsFile etc. C{unsigned int} stored in 4 bytes at byte 20. """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt=DDWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt=DDWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def is_file():
|
def is_file():
|
||||||
""" True iff queried path is a file """
|
""" True iff queried path is a file """
|
||||||
@ -681,40 +553,21 @@ class ListResponse(Response):
|
|||||||
class Answer(TransferBuffer):
|
class Answer(TransferBuffer):
|
||||||
""" Defines the structure of packets sent to host via a bulk transfer (i.e., bulk reads) """
|
""" Defines the structure of packets sent to host via a bulk transfer (i.e., bulk reads) """
|
||||||
|
|
||||||
|
number = field(start=0, fmt=DWORD) #: Answer identifier, should be sent in an acknowledgement packet
|
||||||
|
|
||||||
def __init__(self, packet):
|
def __init__(self, packet):
|
||||||
""" @param packet: C{len(packet)} S{>=} C{16} """
|
""" @param packet: C{len(packet)} S{>=} C{16} """
|
||||||
if len(packet) < 16 : raise PacketError(str(self.__class__)[7:-2] + " packets must have a length of atleast 16 bytes")
|
if len(packet) < 16 : raise PacketError(str(self.__class__)[7:-2] + " packets must have a length of atleast 16 bytes")
|
||||||
TransferBuffer.__init__(self, packet)
|
TransferBuffer.__init__(self, packet)
|
||||||
|
|
||||||
@apply
|
|
||||||
def id():
|
|
||||||
doc =\
|
|
||||||
""" The id of this bulk transfer packet. C{unsigned int} stored in 4 bytes at byte 0. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=0, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=0, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
class FileProperties(Answer):
|
class FileProperties(Answer):
|
||||||
|
|
||||||
""" Defines the structure of packets that contain size, date and permissions information about files/directories. """
|
""" Defines the structure of packets that contain size, date and permissions information about files/directories. """
|
||||||
|
|
||||||
@apply
|
file_size = field(start=16, fmt=DDWORD)
|
||||||
def file_size():
|
ctime = field(start=28, fmt=DDWORD) #: Creation time
|
||||||
doc =\
|
wtime = field(start=16, fmt=DDWORD) #: Modification time
|
||||||
""" The file size. C{unsigned long long} stored in 8 bytes at byte 16. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=16, fmt=DDWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=16, fmt=DDWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def is_dir():
|
def is_dir():
|
||||||
@ -735,31 +588,6 @@ class FileProperties(Answer):
|
|||||||
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
@apply
|
|
||||||
def ctime():
|
|
||||||
doc =\
|
|
||||||
""" The creation time of this file/dir as an epoch (seconds since Jan 1970). C{unsigned int} stored in 4 bytes at byte 28. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=28, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=28, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def wtime():
|
|
||||||
doc =\
|
|
||||||
""" The modification time of this file/dir as an epoch (seconds since Jan 1970). C{unsigned int} stored in 4 bytes at byte 32"""
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=32, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=32, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def is_readonly():
|
def is_readonly():
|
||||||
@ -799,67 +627,21 @@ class IdAnswer(Answer):
|
|||||||
|
|
||||||
class DeviceInfo(Answer):
|
class DeviceInfo(Answer):
|
||||||
""" Defines the structure of the packet containing information about the device """
|
""" Defines the structure of the packet containing information about the device """
|
||||||
|
device_name = field(start=16, fmt="<32s")
|
||||||
|
device_version = field(start=48, fmt="<32s")
|
||||||
|
software_version = field(start=80, fmt="<24s")
|
||||||
|
mime_type = field(start=104, fmt="<32s")
|
||||||
|
|
||||||
@apply
|
|
||||||
def device_name():
|
|
||||||
""" The name of the device. Stored as a string in 32 bytes starting at byte 16. """
|
|
||||||
def fget(self):
|
|
||||||
src = self.unpack(start=16, fmt="<32s")[0]
|
|
||||||
return src[0:src.find('\x00')]
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def device_version():
|
|
||||||
""" The device version. Stored as a string in 32 bytes starting at byte 48. """
|
|
||||||
def fget(self):
|
|
||||||
src = self.unpack(start=48, fmt="<32s")[0]
|
|
||||||
return src[0:src.find('\x00')]
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def software_version():
|
|
||||||
""" Version of the software on the device. Stored as a string in 26 bytes starting at byte 80. """
|
|
||||||
def fget(self):
|
|
||||||
src = self.unpack(start=80, fmt="<26s")[0]
|
|
||||||
return src[0:src.find('\x00')]
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def mime_type():
|
|
||||||
""" Mime type served by tinyhttp?. Stored as a string in 32 bytes starting at byte 104. """
|
|
||||||
def fget(self):
|
|
||||||
src = self.unpack(start=104, fmt="<32s")[0]
|
|
||||||
return src[0:src.find('\x00')]
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
class FreeSpaceAnswer(Answer):
|
class FreeSpaceAnswer(Answer):
|
||||||
@apply
|
total = field(start=24, fmt=DDWORD)
|
||||||
def total():
|
free_space = field(start=32, fmt=DDWORD)
|
||||||
doc =\
|
|
||||||
""" The total space in bytes. C{unsigned long long} stored in 8 bytes at byte 24 """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=24, fmt=DDWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=24, fmt=DDWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def free_space():
|
|
||||||
doc =\
|
|
||||||
""" The free space in bytes. C{unsigned long long} stored in 8 bytes at byte 32 """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=32, fmt=DDWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=32, fmt=DDWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
class ListAnswer(Answer):
|
class ListAnswer(Answer):
|
||||||
|
|
||||||
""" Defines the structure of packets that contain items in a list. """
|
""" Defines the structure of packets that contain items in a list. """
|
||||||
|
name_length = field(start=20, fmt=DWORD)
|
||||||
|
name = stringfield(name_length, start=24)
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def is_dir():
|
def is_dir():
|
||||||
@ -876,27 +658,4 @@ class ListAnswer(Answer):
|
|||||||
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
@apply
|
|
||||||
def name_length():
|
|
||||||
doc =\
|
|
||||||
""" The length in bytes of the list item to follow. C{unsigned int} stored in 4 bytes at byte 20 """
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=20, fmt=DWORD)[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=20, fmt=DWORD)
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
|
||||||
@apply
|
|
||||||
def name():
|
|
||||||
doc =\
|
|
||||||
""" The name of the list item. Stored as an (ascii?) string at byte 24. """
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return self.unpack(start=24, fmt="<"+str(self.name_length)+"s")[0]
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
self.pack(val, start=24, fmt="<"+str(self.name_length)+"s")
|
|
||||||
|
|
||||||
return property(**locals())
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user