Package libprs500 :: Module prstypes
[hide private]
[frames] | no frames]

Source Code for Module libprs500.prstypes

  1  ##    Copyright (C) 2006 Kovid Goyal kovid@kovidgoyal.net 
  2  ##    This program is free software; you can redistribute it and/or modify 
  3  ##    it under the terms of the GNU General Public License as published by 
  4  ##    the Free Software Foundation; either version 2 of the License, or 
  5  ##    (at your option) any later version. 
  6  ## 
  7  ##    This program is distributed in the hope that it will be useful, 
  8  ##    but WITHOUT ANY WARRANTY; without even the implied warranty of 
  9  ##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 10  ##    GNU General Public License for more details. 
 11  ## 
 12  ##    You should have received a copy of the GNU General Public License along 
 13  ##    with this program; if not, write to the Free Software Foundation, Inc., 
 14  ##    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 15   
 16  """ 
 17  Defines the structure of packets that are sent to/received from the device.  
 18   
 19  Packet structure is defined using classes and inheritance. Each class is a view that imposes 
 20  structure on the underlying data buffer. The data buffer is encoded in little-endian format, but you don't 
 21  have to worry about that if you are using the classes. The classes have instance variables with getter/setter functions defined 
 22  to take care of the encoding/decoding. The classes are intended to mimic C structs.  
 23   
 24  There are three kinds of packets. L{Commands<Command>}, L{Responses<Response>}, and L{Answers<Answer>}.  
 25  C{Commands} are sent to the device on the control bus, C{Responses} are received from the device,  
 26  also on the control bus. C{Answers} and their sub-classes represent data packets sent to/received from 
 27  the device via bulk transfers.  
 28   
 29  Commands are organized as follows: G{classtree Command} 
 30   
 31  You will typically only use sub-classes of Command.  
 32   
 33  Responses are organized as follows: G{classtree Response} 
 34   
 35  Responses inherit Command as they share header structure. 
 36   
 37  Answers are organized as follows: G{classtree Answer} 
 38  """ 
 39   
 40  import struct 
 41  from errors import PacketError 
 42   
 43  BYTE      = "<B"    #: Unsigned char little endian encoded in 1 byte 
 44  WORD      = "<H"    #: Unsigned short little endian encoded in 2 bytes 
 45  DWORD     = "<I"    #: Unsigned integer little endian encoded in 4 bytes 
 46  DDWORD    = "<Q"    #: Unsigned long long little endian encoded in 8 bytes 
 47   
 48   
49 -class TransferBuffer(list):
50 51 """ 52 Represents raw (unstructured) data packets sent over the usb bus. 53 54 C{TransferBuffer} is a wrapper around the tuples used by L{PyUSB<usb>} for communication. 55 It has convenience methods to read and write data from the underlying buffer. See 56 L{TransferBuffer.pack} and L{TransferBuffer.unpack}. 57 """ 58
59 - def __init__(self, packet):
60 """ 61 Create a L{TransferBuffer} from C{packet} or an empty buffer. 62 63 @type packet: integer or listable object 64 @param packet: If packet is a list, it is copied into the C{TransferBuffer} and then normalized (see L{TransferBuffer._normalize}). 65 If it is an integer, a zero buffer of that length is created. 66 """ 67 if "__len__" in dir(packet): 68 list.__init__(self, list(packet)) 69 self._normalize() 70 else: list.__init__(self, [0 for i in range(packet)])
71
72 - def __add__(self, tb):
73 """ Return a TransferBuffer rather than a list as the sum """ 74 return TransferBuffer(list.__add__(self, tb))
75
76 - def __getslice__(self, start, end):
77 """ Return a TransferBuffer rather than a list as the slice """ 78 return TransferBuffer(list.__getslice__(self, start, end))
79
80 - def __str__(self):
81 """ 82 Return a string representation of this buffer. 83 84 Packets are represented as hex strings, in 2-byte pairs, S{<=} 16 bytes to a line. An ASCII representation is included. For example:: 85 0700 0100 0000 0000 0000 0000 0c00 0000 ................ 86 0200 0000 0400 0000 4461 7461 ........Data 87 """ 88 ans, ascii = ": ".rjust(10,"0"), "" 89 for i in range(0, len(self), 2): 90 for b in range(2): 91 try: 92 ans += TransferBuffer.phex(self[i+b]) 93 ascii += chr(self[i+b]) if self[i+b] > 31 and self[i+b] < 127 else "." 94 except IndexError: break 95 ans = ans + " " 96 if (i+2)%16 == 0: 97 if i+2 < len(self): 98 ans += " " + ascii + "\n" + (TransferBuffer.phex(i+2)+": ").rjust(10, "0") 99 ascii = "" 100 last_line = ans[ans.rfind("\n")+1:] 101 padding = 50 - len(last_line) 102 ans += "".ljust(padding) + " " + ascii 103 return ans.strip()
104
105 - def unpack(self, fmt=DWORD, start=0):
106 """ 107 Return decoded data from buffer. 108 109 @param fmt: See U{struct<http://docs.python.org/lib/module-struct.html>} 110 @param start: Position in buffer from which to decode 111 """ 112 end = start + struct.calcsize(fmt) 113 return struct.unpack(fmt, "".join([ chr(i) for i in list.__getslice__(self, start, end) ]))
114
115 - def pack(self, val, fmt=DWORD, start=0):
116 """ 117 Encode C{val} and write it to buffer. 118 119 @param fmt: See U{struct<http://docs.python.org/lib/module-struct.html>} 120 @param start: Position in buffer at which to write encoded data 121 """ 122 self[start:start+struct.calcsize(fmt)] = [ ord(i) for i in struct.pack(fmt, val) ]
123
124 - def _normalize(self):
125 """ Replace negative bytes in C{self} by 256 + byte """ 126 for i in range(len(self)): 127 if self[i] < 0: 128 self[i] = 256 + self[i]
129 130 @classmethod
131 - def phex(cls, num):
132 """ 133 Return the hex representation of num without the 0x prefix. 134 135 If the hex representation is only 1 digit it is padded to the left with a zero. Used in L{TransferBuffer.__str__}. 136 """ 137 index, sign = 2, "" 138 if num < 0: 139 index, sign = 3, "-" 140 h=hex(num)[index:] 141 if len(h) < 2: 142 h = "0"+h 143 return sign + h
144 145 146
147 -class Command(TransferBuffer):
148 149 """ Defines the structure of command packets sent to the device. """ 150
151 - def __init__(self, packet):
152 """ 153 @param packet: len(packet) > 15 or packet > 15 154 """ 155 if ("__len__" in dir(packet) and len(packet) < 16) or ("__len__" not in dir(packet) and packet < 16): 156 raise PacketError(str(self.__class__)[7:-2] + " packets must have length atleast 16") 157 TransferBuffer.__init__(self, packet)
158 159 @apply
160 - def number():
161 doc =\ 162 """ 163 Command number. C{unsigned int} stored in 4 bytes at byte 0. 164 165 Observed command numbers are: 166 1. 0x00 167 Test bulk read 168 2. 0x01 169 End session 170 3. 0x0101 171 Ask for device information 172 4. 0x1000 173 Acknowledge 174 5. 0x107 175 Purpose unknown, occurs in the beginning of sessions duing command testing. Best guess is some sort of OK packet 176 6. 0x106 177 Purpose unknown, occurs in the beginning of sessions duing command testing. Best guess is some sort of OK packet 178 7. 0x18 179 Ask for information about a file 180 8. 0x33 181 Open directory for reading 182 9. 0x34 183 Close directory 184 10. 0x35 185 Ask for next item in the directory 186 11. 0x10 187 File open command 188 12. 0x11 189 File close command 190 13. 0x16 191 File read command 192 """ 193 def fget(self): 194 return self.unpack(start=0, fmt=DWORD)[0]
195 196 def fset(self, val): 197 self.pack(val, start=0, fmt=DWORD)
198 199 return property(**locals()) 200 201 @apply
202 - def type():
203 doc =\ 204 """ Command type. C{unsigned long long} stored in 8 bytes at byte 4. Known types 0x00, 0x01. Not sure what the type means. """ 205 def fget(self): 206 return self.unpack(start=4, fmt=DDWORD)[0]
207 208 def fset(self, val): 209 self.pack(val, start=4, fmt=DDWORD) 210 211 return property(**locals()) 212 213 @apply
214 - def length():
215 doc =\ 216 """ Length in bytes of the data part of the query. C{unsigned int} stored in 4 bytes at byte 12. """ 217 def fget(self): 218 return self.unpack(start=12, fmt=DWORD)[0]
219 220 def fset(self, val): 221 self.pack(val, start=12, fmt=DWORD) 222 223 return property(**locals()) 224 225 @apply
226 - def data():
227 doc =\ 228 """ 229 The data part of this command. Returned/set as/by a TransferBuffer. Stored at byte 16. 230 231 Setting it by default changes self.length to the length of the new buffer. You may have to reset it to 232 the significant part of the buffer. You would normally use the C{command} property of L{ShortCommand} or L{LongCommand} instead. 233 """ 234 def fget(self): 235 return self[16:]
236 237 def fset(self, buffer): 238 self[16:] = buffer 239 self.length = len(buffer) 240 241 return property(**locals()) 242 243
244 -class ShortCommand(Command):
245 246 """ A L{Command} whoose data section is 4 bytes long """ 247 248 SIZE = 20 #: Packet size in bytes 249
250 - def __init__(self, number=0x00, type=0x00, command=0x00):
251 """ 252 @param number: L{Command.number} 253 @param type: L{Command.type} 254 @param command: L{ShortCommand.command} 255 """ 256 Command.__init__(self, ShortCommand.SIZE) 257 self.number = number 258 self.type = type 259 self.length = 4 260 self.command = command
261 262 @apply
263 - def command():
264 doc =\ 265 """ The command. Not sure why this is needed in addition to Command.number. C{unsigned int} 4 bytes long at byte 16. """ 266 def fget(self): 267 return self.unpack(start=16, fmt=DWORD)[0]
268 269 def fset(self, val): 270 self.pack(val, start=16, fmt=DWORD)
271 272 return property(**locals()) 273
274 -class FreeSpaceQuery(Command):
275 """ Query the free space available """ 276 NUMBER = 0x53 #; Command number
277 - def __init__(self, path):
278 Command.__init__(self, 20 + len(path)) 279 self.number=FreeSpaceQuery.NUMBER 280 self.type=0x01 281 self.length = 4 + len(path) 282 self.path_length = len(path) 283 self.path = path
284 285 @apply
286 - def path_length():
287 doc =\ 288 """ The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """ 289 def fget(self): 290 return self.unpack(start=16, fmt=DWORD)[0]
291 292 def fset(self, val): 293 self.pack(val, start=16, fmt=DWORD)
294 295 return property(**locals()) 296 297 @apply
298 - def path():
299 doc =\ 300 """ The path. Stored as a string at byte 20. """ 301 302 def fget(self): 303 return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
304 305 def fset(self, val): 306 self.pack(val, start=20, fmt="<"+str(self.path_length)+"s") 307 308 return property(**locals()) 309 310
311 -class DirOpen(Command):
312 313 """ Open a directory for reading its contents """ 314 NUMBER = 0x33 #: Command number 315
316 - def __init__(self, path):
317 Command.__init__(self, 20 + len(path)) 318 self.number=DirOpen.NUMBER 319 self.type = 0x01 320 self.length = 4 + len(path) 321 self.path_length = len(path) 322 self.path = path
323 324 @apply
325 - def path_length():
326 doc =\ 327 """ The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """ 328 def fget(self): 329 return self.unpack(start=16, fmt=DWORD)[0]
330 331 def fset(self, val): 332 self.pack(val, start=16, fmt=DWORD) 333 334 return property(**locals()) 335 336 @apply
337 - def path():
338 doc =\ 339 """ The path. Stored as a string at byte 20. """ 340 341 def fget(self): 342 return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
343 344 def fset(self, val): 345 self.pack(val, start=20, fmt="<"+str(self.path_length)+"s") 346 347 return property(**locals()) 348
349 -class DirRead(ShortCommand):
350 """ The command that asks the device to send the next item in the list """ 351 NUMBER = 0x35 #: Command number
352 - def __init__(self, id):
353 """ @param id: The identifier returned as a result of a L{DirOpen} command """ 354 ShortCommand.__init__(self, number=DirRead.NUMBER, type=0x01, command=id)
355
356 -class DirClose(ShortCommand):
357 """ Close a previously opened directory """ 358 NUMBER = 0x34 #: Command number
359 - def __init__(self, id):
360 """ @param id: The identifier returned as a result of a L{DirOpen} command """ 361 ShortCommand.__init__(self, number=DirClose.NUMBER, type=0x01, command=id)
362 363
364 -class LongCommand(Command):
365 366 """ A L{Command} whoose data section is 16 bytes long """ 367 368 SIZE = 32 #: Size in bytes of C{LongCommand} packets 369
370 - def __init__(self, number=0x00, type=0x00, command=0x00):
371 """ 372 @param number: L{Command.number} 373 @param type: L{Command.type} 374 @param command: L{LongCommand.command} 375 """ 376 Command.__init__(self, LongCommand.SIZE) 377 self.number = number 378 self.type = type 379 self.length = 16 380 self.command = command
381 382 @apply
383 - def command():
384 doc =\ 385 """ 386 The command. Not sure why it is needed in addition to L{Command.number}. 387 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. 388 """ 389 def fget(self): 390 return self.unpack(start=16, fmt="<"+str(self.length/4)+"I")
391 392 def fset(self, val): 393 if "__len__" not in dir(val): val = (val,) 394 start = 16 395 for command in val: 396 self.pack(command, start=start, fmt=DWORD) 397 start += struct.calcsize(DWORD)
398 399 return property(**locals()) 400 401
402 -class AcknowledgeBulkRead(LongCommand):
403 404 """ Must be sent to device after a bulk read """ 405
406 - def __init__(self, bulk_read_id):
407 """ bulk_read_id is an integer, the id of the bulk read we are acknowledging. See L{Answer.id} """ 408 LongCommand.__init__(self, number=0x1000, type=0x00, command=bulk_read_id)
409
410 -class DeviceInfoQuery(Command):
411 """ The command used to ask for device information """ 412 NUMBER=0x0101 #: Command number
413 - def __init__(self):
414 Command.__init__(self, 16) 415 self.number=DeviceInfoQuery.NUMBER 416 self.type=0x01
417
418 -class FileClose(ShortCommand):
419 """ File close command """ 420 NUMBER = 0x11 #: Command number
421 - def __init__(self, id):
423
424 -class FileOpen(Command):
425 """ File open command """ 426 NUMBER = 0x10 427 READ = 0x00 428 WRITE = 0x01
429 - def __init__(self, path, mode=0x00):
430 Command.__init__(self, 24 + len(path)) 431 self.number=FileOpen.NUMBER 432 self.type = 0x01 433 self.length = 8 + len(path) 434 self.mode = mode 435 self.path_length = len(path) 436 self.path = path
437 438 @apply
439 - def mode():
440 doc =\ 441 """ The file open mode. Is either L{FileOpen.READ} or L{FileOpen.WRITE}. C{unsigned int} stored at byte 16. """ 442 def fget(self): 443 return self.unpack(start=16, fmt=DWORD)[0]
444 445 def fset(self, val): 446 self.pack(val, start=16, fmt=DWORD)
447 448 return property(**locals()) 449 450 @apply
451 - def path_length():
452 doc =\ 453 """ The length in bytes of the path to follow. C{unsigned int} stored at byte 20. """ 454 def fget(self): 455 return self.unpack(start=20, fmt=DWORD)[0]
456 457 def fset(self, val): 458 self.pack(val, start=20, fmt=DWORD) 459 460 return property(**locals()) 461 462 @apply
463 - def path():
464 doc =\ 465 """ The path. Stored as a string at byte 24. """ 466 467 def fget(self): 468 return self.unpack(start=24, fmt="<"+str(self.path_length)+"s")[0]
469 470 def fset(self, val): 471 self.pack(val, start=24, fmt="<"+str(self.path_length)+"s") 472 473 return property(**locals()) 474
475 -class FileRead(Command):
476 """ Command to read from an open file """ 477 NUMBER = 0x16 #: Command number to read from a file
478 - def __init__(self, id, offset, size):
479 """ 480 @param id: File identifier returned by a L{FileOpen} command 481 @type id: C{unsigned int} 482 @param offset: Position in file at which to read 483 @type offset: C{unsigned long long} 484 @param size: number of bytes to read 485 @type size: C{unsigned int} 486 """ 487 Command.__init__(self, 32) 488 self.number=FileRead.NUMBER 489 self.type = 0x01 490 self.length = 32 491 self.id = id 492 self.offset = offset 493 self.size = size
494 495 @apply
496 - def id():
497 doc =\ 498 """ The file ID returned by a FileOpen command. C{unsigned int} stored in 4 bytes at byte 16. """ 499 def fget(self): 500 return self.unpack(start=16, fmt=DWORD)[0]
501 502 def fset(self, val): 503 self.pack(val, start=16, fmt=DWORD)
504 505 return property(**locals()) 506 507 @apply
508 - def offset():
509 doc =\ 510 """ offset in the file at which to read. C{unsigned long long} stored in 8 bytes at byte 20. """ 511 def fget(self): 512 return self.unpack(start=20, fmt=DDWORD)[0]
513 514 def fset(self, val): 515 self.pack(val, start=20, fmt=DDWORD) 516 517 return property(**locals()) 518 519 @apply
520 - def size():
521 doc =\ 522 """ The number of bytes to read. C{unsigned int} stored in 4 bytes at byte 28. """ 523 def fget(self): 524 return self.unpack(start=28, fmt=DWORD)[0]
525 526 def fset(self, val): 527 self.pack(val, start=28, fmt=DWORD) 528 529 return property(**locals()) 530 531 532 533
534 -class PathQuery(Command):
535 536 """ 537 Defines structure of command that requests information about a path 538 539 >>> print prstypes.PathQuery("/test/path/", number=prstypes.PathQuery.PROPERTIES) 540 1800 0000 0100 0000 0000 0000 0f00 0000 ................ 541 0b00 0000 2f74 6573 742f 7061 7468 2f ..../test/path/ 542 """ 543 NUMBER = 0x18 #: Command number 544
545 - def __init__(self, path):
546 Command.__init__(self, 20 + len(path)) 547 self.number=PathQuery.NUMBER 548 self.type = 0x01 549 self.length = 4 + len(path) 550 self.path_length = len(path) 551 self.path = path
552 553 @apply
554 - def path_length():
555 doc =\ 556 """ The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """ 557 def fget(self): 558 return self.unpack(start=16, fmt=DWORD)[0]
559 560 def fset(self, val): 561 self.pack(val, start=16, fmt=DWORD) 562 563 return property(**locals()) 564 565 @apply
566 - def path():
567 doc =\ 568 """ The path. Stored as a string at byte 20. """ 569 570 def fget(self): 571 return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
572 573 def fset(self, val): 574 self.pack(val, start=20, fmt="<"+str(self.path_length)+"s") 575 576 return property(**locals()) 577 578
579 -class Response(Command):
580 """ 581 Defines the structure of response packets received from the device. 582 583 C{Response} inherits from C{Command} as the first 16 bytes have the same structure. 584 """ 585 586 SIZE = 32 #: Size of response packets in the SONY protocol 587
588 - def __init__(self, packet):
589 """ C{len(packet) == Response.SIZE} """ 590 if len(packet) != Response.SIZE: 591 raise PacketError(str(self.__class__)[7:-2] + " packets must have exactly " + str(Response.SIZE) + " bytes not " + str(len(packet))) 592 Command.__init__(self, packet) 593 if self.number != 0x00001000: 594 raise PacketError("Response packets must have their number set to " + hex(0x00001000))
595 596 @apply
597 - def rnumber():
598 doc =\ 599 """ 600 The response number. C{unsigned int} stored in 4 bytes at byte 16. 601 602 It will be the command number from a command that was sent to the device sometime before this response. 603 """ 604 def fget(self): 605 return self.unpack(start=16, fmt=DWORD)[0]
606 607 def fset(self, val): 608 self.pack(val, start=16, fmt=DWORD)
609 610 return property(**locals()) 611 612 @apply
613 - def data():
614 doc =\ 615 """ The last 3 DWORDs (12 bytes) of data in this response packet. Returned as a list of unsigned integers. """ 616 def fget(self): 617 return self.unpack(start=20, fmt="<III")
618 619 def fset(self, val): 620 self.pack(val, start=20, fmt="<III") 621 622 return property(**locals()) 623
624 -class ListResponse(Response):
625 626 """ Defines the structure of response packets received during list (ll) queries. See L{PathQuery}. """ 627 628 IS_FILE = 0xffffffd2 #: Queried path is a file 629 IS_INVALID = 0xfffffff9 #: Queried path is malformed/invalid 630 IS_UNMOUNTED = 0xffffffc8 #: Queried path is not mounted (i.e. a removed storage card/stick) 631 IS_EOL = 0xfffffffa #: There are no more entries in the list 632 PATH_NOT_FOUND = 0xffffffd7 #: Queried path is not found 633 634 @apply
635 - def code():
636 doc =\ 637 """ The response code. Used to indicate conditions like EOL/Error/IsFile etc. C{unsigned int} stored in 4 bytes at byte 20. """ 638 def fget(self): 639 return self.unpack(start=20, fmt=DDWORD)[0]
640 641 def fset(self, val): 642 self.pack(val, start=20, fmt=DDWORD)
643 644 return property(**locals()) 645 646 @apply
647 - def is_file():
648 """ True iff queried path is a file """ 649 def fget(self): 650 return self.code == ListResponse.IS_FILE
651 return property(**locals()) 652 653 @apply
654 - def is_invalid():
655 """ True iff queried path is invalid """ 656 def fget(self): 657 return self.code == ListResponse.IS_INVALID
658 return property(**locals()) 659 660 @apply
661 - def path_not_found():
662 """ True iff queried path is not found """ 663 def fget(self): 664 return self.code == ListResponse.PATH_NOT_FOUND
665 return property(**locals()) 666 667 @apply
668 - def is_unmounted():
669 """ True iff queried path is unmounted (i.e. removed storage card) """ 670 def fget(self): 671 return self.code == ListResponse.IS_UNMOUNTED
672 return property(**locals()) 673 674 @apply
675 - def is_eol():
676 """ True iff there are no more items in the list """ 677 def fget(self): 678 return self.code == ListResponse.IS_EOL
679 return property(**locals()) 680
681 -class Answer(TransferBuffer):
682 """ Defines the structure of packets sent to host via a bulk transfer (i.e., bulk reads) """ 683
684 - def __init__(self, packet):
685 """ @param packet: C{len(packet)} S{>=} C{16} """ 686 if len(packet) < 16 : raise PacketError(str(self.__class__)[7:-2] + " packets must have a length of atleast 16 bytes") 687 TransferBuffer.__init__(self, packet)
688 689 @apply
690 - def id():
691 doc =\ 692 """ The id of this bulk transfer packet. C{unsigned int} stored in 4 bytes at byte 0. """ 693 694 def fget(self): 695 return self.unpack(start=0, fmt=DWORD)[0]
696 697 def fset(self, val): 698 self.pack(val, start=0, fmt=DWORD)
699 700 return property(**locals()) 701
702 -class FileProperties(Answer):
703 704 """ Defines the structure of packets that contain size, date and permissions information about files/directories. """ 705 706 @apply
707 - def file_size():
708 doc =\ 709 """ The file size. C{unsigned long long} stored in 8 bytes at byte 16. """ 710 711 def fget(self): 712 return self.unpack(start=16, fmt=DDWORD)[0]
713 714 def fset(self, val): 715 self.pack(val, start=16, fmt=DDWORD)
716 717 return property(**locals()) 718 719 @apply
720 - def is_dir():
721 doc =\ 722 """ 723 True if path points to a directory, False if it points to a file. C{unsigned int} stored in 4 bytes at byte 24. 724 725 Value of 1 == file and 2 == dir 726 """ 727 728 def fget(self): 729 return (self.unpack(start=24, fmt=DWORD)[0] == 2)
730 731 def fset(self, val): 732 if val: val = 2 733 else: val = 1 734 self.pack(val, start=24, fmt=DWORD) 735 736 return property(**locals()) 737 738 @apply
739 - def ctime():
740 doc =\ 741 """ The creation time of this file/dir as an epoch (seconds since Jan 1970). C{unsigned int} stored in 4 bytes at byte 28. """ 742 743 def fget(self): 744 return self.unpack(start=28, fmt=DWORD)[0]
745 746 def fset(self, val): 747 self.pack(val, start=28, fmt=DWORD) 748 749 return property(**locals()) 750 751 @apply
752 - def wtime():
753 doc =\ 754 """ The modification time of this file/dir as an epoch (seconds since Jan 1970). C{unsigned int} stored in 4 bytes at byte 32""" 755 756 def fget(self): 757 return self.unpack(start=32, fmt=DWORD)[0]
758 759 def fset(self, val): 760 self.pack(val, start=32, fmt=DWORD) 761 762 return property(**locals()) 763 764 @apply
765 - def is_readonly():
766 doc =\ 767 """ 768 Whether this file is readonly. C{unsigned int} stored in 4 bytes at byte 36. 769 770 A value of 0 corresponds to read/write and 4 corresponds to read-only. The device doesn't send full permissions information. 771 """ 772 773 def fget(self): 774 return self.unpack(start=36, fmt=DWORD)[0] != 0
775 776 def fset(self, val): 777 if val: val = 4 778 else: val = 0 779 self.pack(val, start=36, fmt=DWORD) 780 781 return property(**locals()) 782
783 -class IdAnswer(Answer):
784 785 """ Defines the structure of packets that contain identifiers for queries. """ 786 787 @apply
788 - def id():
789 doc =\ 790 """ The identifier. C{unsigned int} stored in 4 bytes at byte 16. Should be sent in commands asking for the next item in the list. """ 791 792 def fget(self): 793 return self.unpack(start=16, fmt=DWORD)[0]
794 795 def fset(self, val): 796 self.pack(val, start=16, fmt=DWORD)
797 798 return property(**locals()) 799
800 -class DeviceInfo(Answer):
801 """ Defines the structure of the packet containing information about the device """ 802 803 @apply
804 - def device_name():
805 """ The name of the device. Stored as a string in 32 bytes starting at byte 16. """ 806 def fget(self): 807 src = self.unpack(start=16, fmt="<32s")[0] 808 return src[0:src.find('\x00')]
809 return property(**locals())
810 811 @apply
812 - def device_version():
813 """ The device version. Stored as a string in 32 bytes starting at byte 48. """ 814 def fget(self): 815 src = self.unpack(start=48, fmt="<32s")[0] 816 return src[0:src.find('\x00')]
817 return property(**locals()) 818 819 @apply
820 - def software_version():
821 """ Version of the software on the device. Stored as a string in 26 bytes starting at byte 80. """ 822 def fget(self): 823 src = self.unpack(start=80, fmt="<26s")[0] 824 return src[0:src.find('\x00')]
825 return property(**locals()) 826 827 @apply
828 - def mime_type():
829 """ Mime type served by tinyhttp?. Stored as a string in 32 bytes starting at byte 104. """ 830 def fget(self): 831 src = self.unpack(start=104, fmt="<32s")[0] 832 return src[0:src.find('\x00')]
833 return property(**locals()) 834
835 -class FreeSpaceAnswer(Answer):
836 @apply
837 - def total():
838 doc =\ 839 """ The total space in bytes. C{unsigned long long} stored in 8 bytes at byte 24 """ 840 def fget(self): 841 return self.unpack(start=24, fmt=DDWORD)[0]
842 843 def fset(self, val): 844 self.pack(val, start=24, fmt=DDWORD)
845 846 return property(**locals()) 847 848 @apply
849 - def free_space():
850 doc =\ 851 """ The free space in bytes. C{unsigned long long} stored in 8 bytes at byte 32 """ 852 def fget(self): 853 return self.unpack(start=32, fmt=DDWORD)[0]
854 855 def fset(self, val): 856 self.pack(val, start=32, fmt=DDWORD) 857 858 return property(**locals()) 859
860 -class ListAnswer(Answer):
861 862 """ Defines the structure of packets that contain items in a list. """ 863 864 @apply
865 - def is_dir():
866 doc =\ 867 """ True if list item points to a directory, False if it points to a file. C{unsigned int} stored in 4 bytes at byte 16. """ 868 869 def fget(self): 870 return (self.unpack(start=16, fmt=DWORD)[0] == 2)
871 872 def fset(self, val): 873 if val: val = 2 874 else: val = 1 875 self.pack(val, start=16, fmt=DWORD)
876 877 return property(**locals()) 878 879 @apply
880 - def name_length():
881 doc =\ 882 """ The length in bytes of the list item to follow. C{unsigned int} stored in 4 bytes at byte 20 """ 883 def fget(self): 884 return self.unpack(start=20, fmt=DWORD)[0]
885 886 def fset(self, val): 887 self.pack(val, start=20, fmt=DWORD) 888 889 return property(**locals()) 890 891 @apply
892 - def name():
893 doc =\ 894 """ The name of the list item. Stored as an (ascii?) string at byte 24. """ 895 896 def fget(self): 897 return self.unpack(start=24, fmt="<"+str(self.name_length)+"s")[0]
898 899 def fset(self, val): 900 self.pack(val, start=24, fmt="<"+str(self.name_length)+"s") 901 902 return property(**locals()) 903