Subversion Repositories freemyipod

Rev

Rev 522 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 522 Rev 532
Line 34... Line 34...
34
 
34
 
35
from functools import wraps
35
from functools import wraps
36
 
36
 
37
import libemcore
37
import libemcore
38
import libemcoredata
38
import libemcoredata
39
from misc import Error, Logger, getfuncdoc, gethwname
39
from misc import Error, ArgumentError, ArgumentTypeError, Logger, getfuncdoc, gethwname, to_bool, to_int
40
 
-
 
41
 
-
 
42
class NotImplementedError(Error):
-
 
43
    pass
-
 
44
 
-
 
45
class ArgumentError(Error):
-
 
46
    pass
-
 
47
 
-
 
48
class ArgumentTypeError(Error):
-
 
49
    def __init__(self, expected, seen=False):
-
 
50
        self.expected = expected
-
 
51
        self.seen = seen
-
 
52
    def __str__(self):
-
 
53
        if self.seen:
-
 
54
            return "Expected %s but got %s" % (self.expected, self.seen)
-
 
55
        else:
-
 
56
            return "Expected %s, but saw something else" % self.expected
-
 
57
 
40
 
58
 
41
 
59
def usage(errormsg=None, specific=False, docstring=True):
42
def usage(errormsg=None, specific=False, docstring=True):
60
    """
43
    """
61
        Prints the usage information.
44
        Prints the usage information.
Line 160... Line 143...
160
                    raise
143
                    raise
161
            except libemcore.usb.core.USBError:
144
            except libemcore.usb.core.USBError:
162
                self.logger.error("There is a problem with the USB connection.\n")
145
                self.logger.error("There is a problem with the USB connection.\n")
163
        else:
146
        else:
164
            usage("No such command!", docstring = False)
147
            usage("No such command!", docstring = False)
165
    
148
 
166
    @staticmethod
-
 
167
    def _bool(something):
-
 
168
        """
-
 
169
            Converts quite everything into bool.
-
 
170
        """
-
 
171
        if type(something) == bool:
-
 
172
            return something
-
 
173
        if something is None:
-
 
174
            return False
-
 
175
        elif type(something) == int or type(something) == long:
-
 
176
            return bool(something)
-
 
177
        elif type(something == str):
-
 
178
            truelist = ['true', '1', 't', 'y', 'yes']
-
 
179
            falselist = ['false', '0', 'f', 'n', 'no']
-
 
180
            if something.lower() in truelist:
-
 
181
                return True
-
 
182
            elif something.lower() in falselist:
-
 
183
                return False
-
 
184
        raise ArgumentTypeError("bool", "'%s'" % something)
-
 
185
    
-
 
186
    @staticmethod
-
 
187
    def _hexint(something):
-
 
188
        """
-
 
189
            Converts quite everything to a hexadecimal represented integer.
-
 
190
            This works for default arguments too, because it returns
-
 
191
            None when it found that it got a NoneType object.
-
 
192
        """
-
 
193
        if type(something) == int or type(something) == long:
-
 
194
            return something
-
 
195
        elif type(something) == str:
-
 
196
            try:
-
 
197
                return int(something, 16)
-
 
198
            except ValueError:
-
 
199
                raise ArgumentTypeError("hexadecimal coded integer", "'%s'" % something)
-
 
200
        elif something is None:
-
 
201
            return None
-
 
202
        else:
-
 
203
            raise ArgumentTypeError("hexadecimal coded integer", "'%s'" % something)
-
 
204
    
149
    
205
    @command
150
    @command
206
    def help(self):
151
    def help(self):
207
        """ Displays this help """
152
        """ Displays this help """
208
        usage(docstring = True)
153
        usage(docstring = True)
Line 244... Line 189...
244
        """
189
        """
245
            Resets the device"
190
            Resets the device"
246
            If [force] is 1, the reset will be forced, otherwise it will be gracefully,
191
            If [force] is 1, the reset will be forced, otherwise it will be gracefully,
247
            which may take some time.
192
            which may take some time.
248
        """
193
        """
249
        force = self._bool(force)
194
        force = to_bool(force)
250
        if force: self.logger.info("Resetting forcefully...\n")
195
        if force: self.logger.info("Resetting forcefully...\n")
251
        else: self.logger.info("Resetting...\n")
196
        else: self.logger.info("Resetting...\n")
252
        self.emcore.reset(force)
197
        self.emcore.reset(force)
253
    
198
    
254
    @command
199
    @command
Line 256... Line 201...
256
        """
201
        """
257
            Powers the device off
202
            Powers the device off
258
            If [force] is 1, the poweroff will be forced, otherwise it will be gracefully,
203
            If [force] is 1, the poweroff will be forced, otherwise it will be gracefully,
259
            which may take some time.
204
            which may take some time.
260
        """
205
        """
261
        force = self._bool(force)
206
        force = to_bool(force)
262
        if force: self.logger.info("Powering off forcefully...\n")
207
        if force: self.logger.info("Powering off forcefully...\n")
263
        else: self.logger.info("Powering off...\n")
208
        else: self.logger.info("Powering off...\n")
264
        self.emcore.poweroff(force)
209
        self.emcore.poweroff(force)
265
    
210
    
266
    @command
211
    @command
Line 268... Line 213...
268
        """
213
        """
269
            Uploads a file to the device
214
            Uploads a file to the device
270
            <filename>: The path to the file
215
            <filename>: The path to the file
271
            [addr]: The address to upload the file to. Allocates a chunk of memory if not given.
216
            [addr]: The address to upload the file to. Allocates a chunk of memory if not given.
272
        """
217
        """
273
        addr = self._hexint(addr)
218
        addr = to_int(addr)
274
        try:
219
        try:
275
            f = open(filename, 'rb')
220
            f = open(filename, 'rb')
276
        except IOError:
221
        except IOError:
277
            raise ArgumentError("File not readable. Does it exist?")
222
            raise ArgumentError("File not readable. Does it exist?")
278
        if addr is not None:
223
        if addr is not None:
Line 295... Line 240...
295
            Uploads a file to the device
240
            Uploads a file to the device
296
            <offset>: the address to upload the file to
241
            <offset>: the address to upload the file to
297
            <size>: the number of bytes to be read
242
            <size>: the number of bytes to be read
298
            <filename>: the path to the file
243
            <filename>: the path to the file
299
        """
244
        """
300
        addr = self._hexint(addr)
245
        addr = to_int(addr)
301
        size = self._hexint(size)
246
        size = to_int(size)
302
        try:
247
        try:
303
            f = open(filename, 'wb')
248
            f = open(filename, 'wb')
304
        except IOError:
249
        except IOError:
305
            raise ArgumentError("Can not open file for write!")
250
            raise ArgumentError("Can not open file for write!")
306
        self.logger.info("Reading data from address 0x%X with the size 0x%X to '%s'..." %
251
        self.logger.info("Reading data from address 0x%X with the size 0x%X to '%s'..." %
Line 315... Line 260...
315
        """
260
        """
316
            Uploads a single integer to the device
261
            Uploads a single integer to the device
317
            <addr>: the address to upload the integer to
262
            <addr>: the address to upload the integer to
318
            <integer>: the integer to upload
263
            <integer>: the integer to upload
319
        """
264
        """
320
        addr = self._hexint(addr)
265
        addr = to_int(addr)
321
        integer = self._hexint(integer)
266
        integer = to_int(integer)
322
        if integer > 0xFFFFFFFF:
267
        if integer > 0xFFFFFFFF:
323
            raise ArgumentError("Specified integer too long")
268
            raise ArgumentError("Specified integer too long")
324
        data = struct.pack("I", integer)
269
        data = struct.pack("I", integer)
325
        self.emcore.write(addr, data)
270
        self.emcore.write(addr, data)
326
        self.logger.info("Integer '0x%X' written successfully to 0x%X\n" % (integer, addr))
271
        self.logger.info("Integer '0x%X' written successfully to 0x%X\n" % (integer, addr))
Line 329... Line 274...
329
    def downloadint(self, addr):
274
    def downloadint(self, addr):
330
        """
275
        """
331
            Downloads a single integer from the device and prints it to the console window
276
            Downloads a single integer from the device and prints it to the console window
332
            <addr>: the address to download the integer from
277
            <addr>: the address to download the integer from
333
        """
278
        """
334
        addr = self._hexint(addr)
279
        addr = to_int(addr)
335
        data = self.emcore.read(addr, 4)
280
        data = self.emcore.read(addr, 4)
336
        integer = struct.unpack("I", data)[0]
281
        integer = struct.unpack("I", data)[0]
337
        self.logger.info("Read '0x%X' from address 0x%X\n" % (integer, addr))
282
        self.logger.info("Read '0x%X' from address 0x%X\n" % (integer, addr))
338
    
283
    
339
    @command
284
    @command
Line 343... Line 288...
343
            <bus>: the bus index
288
            <bus>: the bus index
344
            <slave>: the slave address
289
            <slave>: the slave address
345
            <addr>: the start address on the I2C device
290
            <addr>: the start address on the I2C device
346
            <size>: the number of bytes to read
291
            <size>: the number of bytes to read
347
        """
292
        """
348
        bus = self._hexint(bus)
293
        bus = to_int(bus)
349
        slave = self._hexint(slave)
294
        slave = to_int(slave)
350
        addr = self._hexint(addr)
295
        addr = to_int(addr)
351
        size = self._hexint(size)
296
        size = to_int(size)
352
        data = self.emcore.i2cread(bus, slave, addr, size)
297
        data = self.emcore.i2cread(bus, slave, addr, size)
353
        bytes = struct.unpack("%dB" % len(data), data)
298
        bytes = struct.unpack("%dB" % len(data), data)
354
        self.logger.info("Data read from I2C:\n")
299
        self.logger.info("Data read from I2C:\n")
355
        for index, byte in enumerate(bytes):
300
        for index, byte in enumerate(bytes):
356
            self.logger.info("%02X: %02X\n" % (index, byte))
301
            self.logger.info("%02X: %02X\n" % (index, byte))
Line 360... Line 305...
360
        """
305
        """
361
            Writes data to an I2C device
306
            Writes data to an I2C device
362
            <bus>: the bus index
307
            <bus>: the bus index
363
            <slave>: the slave address
308
            <slave>: the slave address
364
            <addr>: the start address on the I2C device
309
            <addr>: the start address on the I2C device
365
            <db1> ... <dbN>: the data in single bytes, encoded in hex,
310
            <db1> ... <dbN>: the data in single bytes,
366
                seperated by whitespaces, eg. 37 5A 4F EB
311
                seperated by whitespaces, eg. 37 5A 4F EB
367
        """
312
        """
368
        bus = self._hexint(bus)
313
        bus = to_int(bus)
369
        slave = self._hexint(slave)
314
        slave = to_int(slave)
370
        addr = self._hexint(addr)
315
        addr = to_int(addr)
371
        data = ""
316
        data = ""
372
        for arg in args:
317
        for arg in args:
373
            data += chr(self._hexint(arg))
318
            data += chr(to_int(arg))
374
        self.logger.info("Writing data to I2C...\n")
319
        self.logger.info("Writing data to I2C...\n")
375
        self.emcore.i2cwrite(bus, slave, addr, data)
320
        self.emcore.i2cwrite(bus, slave, addr, data)
376
        self.logger.info("done\n")
321
        self.logger.info("done\n")
377
    
322
    
378
    @command
323
    @command
Line 401... Line 346...
401
    def readdevconsole(self, bitmask):
346
    def readdevconsole(self, bitmask):
402
        """
347
        """
403
            Reads data continuously from one or more of the device's consoles.
348
            Reads data continuously from one or more of the device's consoles.
404
            <bitmask>: the bitmask of the consoles to read from.
349
            <bitmask>: the bitmask of the consoles to read from.
405
        """
350
        """
406
        bitmask = self._hexint(bitmask)
351
        bitmask = to_int(bitmask)
407
        while True:
352
        while True:
408
            resp = self.emcore.cread()
353
            resp = self.emcore.cread()
409
            self.logger.write(resp.data)
354
            self.logger.write(resp.data)
410
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
355
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
411
    
356
    
Line 413... Line 358...
413
    def writedevconsole(self, bitmask, *args):
358
    def writedevconsole(self, bitmask, *args):
414
        """
359
        """
415
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
360
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
416
            <bitmask>: the bitmask of the consoles to write to
361
            <bitmask>: the bitmask of the consoles to write to
417
        """
362
        """
418
        bitmask = self._hexint(bitmask)
363
        bitmask = to_int(bitmask)
419
        text = ""
364
        text = ""
420
        for word in args:
365
        for word in args:
421
            text += word + " "
366
            text += word + " "
422
        text = text[:-1]
367
        text = text[:-1]
423
        self.logger.info("Writing '%s' to the device consoles identified with 0x%X\n" % (text, bitmask))
368
        self.logger.info("Writing '%s' to the device consoles identified with 0x%X\n" % (text, bitmask))
Line 427... Line 372...
427
    def flushconsolebuffers(self, bitmask):
372
    def flushconsolebuffers(self, bitmask):
428
        """
373
        """
429
            flushes one or more of the device consoles' buffers.
374
            flushes one or more of the device consoles' buffers.
430
            <bitmask>: the bitmask of the consoles to be flushed
375
            <bitmask>: the bitmask of the consoles to be flushed
431
        """
376
        """
432
        bitmask = self._hexint(bitmask)
377
        bitmask = to_int(bitmask)
433
        self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
378
        self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
434
        self.emcore.cflush(bitmask)
379
        self.emcore.cflush(bitmask)
435
    
380
    
436
    @command
381
    @command
437
    def getprocinfo(self):
382
    def getprocinfo(self):
Line 492... Line 437...
492
    @command
437
    @command
493
    def suspendthread(self, threadaddr):
438
    def suspendthread(self, threadaddr):
494
        """
439
        """
495
            Suspends the thread with the thread address <threadaddr>
440
            Suspends the thread with the thread address <threadaddr>
496
        """
441
        """
497
        threadaddr = self._hexint(threadaddr)
442
        threadaddr = to_int(threadaddr)
498
        self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
443
        self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
499
        self.emcore.suspendthread(threadaddr)
444
        self.emcore.suspendthread(threadaddr)
500
    
445
    
501
    @command
446
    @command
502
    def resumethread(self, threadaddr):
447
    def resumethread(self, threadaddr):
503
        """
448
        """
504
            Resumes the thread with the thread address <threadaddr>
449
            Resumes the thread with the thread address <threadaddr>
505
        """
450
        """
506
        threadaddr = self._hexint(threadaddr)
451
        threadaddr = to_int(threadaddr)
507
        self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
452
        self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
508
        self.emcore.resumethread(threadaddr)
453
        self.emcore.resumethread(threadaddr)
509
    
454
    
510
    @command
455
    @command
511
    def killthread(self, threadaddr):
456
    def killthread(self, threadaddr):
512
        """
457
        """
513
            Kills the thread with the thread address <threadaddr>
458
            Kills the thread with the thread address <threadaddr>
514
        """
459
        """
515
        threadaddr = self._hexint(threadaddr)
460
        threadaddr = to_int(threadaddr)
516
        self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
461
        self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
517
        self.emcore.killthread(threadaddr)
462
        self.emcore.killthread(threadaddr)
518
    
463
    
519
    @command
464
    @command
520
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
465
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
Line 526... Line 471...
526
            <stacksize>: the size of the thread's stack
471
            <stacksize>: the size of the thread's stack
527
            <threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
472
            <threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
528
            <priority>: the priority of the thread, from 1 to 255
473
            <priority>: the priority of the thread, from 1 to 255
529
            <state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
474
            <state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
530
        """
475
        """
531
        nameptr = self._hexint(nameptr)
476
        nameptr = to_int(nameptr)
532
        entrypoint = self._hexint(entrypoint)
477
        entrypoint = to_int(entrypoint)
533
        stackptr = self._hexint(stackptr)
478
        stackptr = to_int(stackptr)
534
        stacksize = self._hexint(stacksize)
479
        stacksize = to_int(stacksize)
535
        priority = self._hexint(priority)
480
        priority = to_int(priority)
536
        data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
481
        data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
537
        name = self.emcore.readstring(nameptr)
482
        name = self.emcore.readstring(nameptr)
538
        self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
483
        self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
539
                         "the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
484
                         "the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
540
                        (data.threadptr, name, entrypoint, stackptr, stacksize, priority))
485
                        (data.threadptr, name, entrypoint, stackptr, stacksize, priority))
Line 556... Line 501...
556
    @command
501
    @command
557
    def execimage(self, addr):
502
    def execimage(self, addr):
558
        """
503
        """
559
            Executes the emCORE application at <addr>.
504
            Executes the emCORE application at <addr>.
560
        """
505
        """
561
        addr = self._hexint(addr)
506
        addr = to_int(addr)
562
        self.logger.info("Starting emCORE app at 0x%X\n" % addr)
507
        self.logger.info("Starting emCORE app at 0x%X\n" % addr)
563
        self.emcore.execimage(addr)
508
        self.emcore.execimage(addr)
564
    
509
    
565
    @command
510
    @command
566
    def flushcaches(self):
511
    def flushcaches(self):
Line 576... Line 521...
576
        """
521
        """
577
            Reads <size> bytes from bootflash to memory.
522
            Reads <size> bytes from bootflash to memory.
578
            <addr_bootflsh>: the address in bootflash to read from
523
            <addr_bootflsh>: the address in bootflash to read from
579
            <addr_mem>: the address in memory to copy the data to
524
            <addr_mem>: the address in memory to copy the data to
580
        """
525
        """
581
        addr_flash = self._hexint(addr_flash)
526
        addr_flash = to_int(addr_flash)
582
        addr_mem = self._hexint(addr_mem)
527
        addr_mem = to_int(addr_mem)
583
        size = self._hexint(size)
528
        size = to_int(size)
584
        self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
529
        self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
585
                        (addr_flash, addr_flash + size, addr_mem, addr_mem + size))
530
                        (addr_flash, addr_flash + size, addr_mem, addr_mem + size))
586
        self.emcore.bootflashread(addr_mem, addr_flash, size)
531
        self.emcore.bootflashread(addr_mem, addr_flash, size)
587
    
532
    
588
    @command
533
    @command
Line 593... Line 538...
593
            This may BRICK your device (unless it has a good recovery option)
538
            This may BRICK your device (unless it has a good recovery option)
594
            <addr_mem>: the address in memory to copy the data from
539
            <addr_mem>: the address in memory to copy the data from
595
            <addr_bootflsh>: the address in bootflash to write to
540
            <addr_bootflsh>: the address in bootflash to write to
596
            [force]: Use this flag to suppress the 5 seconds delay
541
            [force]: Use this flag to suppress the 5 seconds delay
597
        """
542
        """
598
        addr_flash = self._hexint(addr_flash)
543
        addr_flash = to_int(addr_flash)
599
        addr_mem = self._hexint(addr_mem)
544
        addr_mem = to_int(addr_mem)
600
        size = self._hexint(size)
545
        size = to_int(size)
601
        force = self._bool(force)
546
        force = to_bool(force)
602
        self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
547
        self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
603
                        (addr_mem, addr_mem + size, addr_flash, addr_flash + size))
548
                        (addr_mem, addr_mem + size, addr_flash, addr_flash + size))
604
        if force == False:
549
        if force == False:
605
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
550
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
606
            for i in range(10):
551
            for i in range(10):
Line 613... Line 558...
613
    def runfirmware(self, targetaddr, filename):
558
    def runfirmware(self, targetaddr, filename):
614
        """
559
        """
615
            Uploads the firmware in <filename>
560
            Uploads the firmware in <filename>
616
            to an allocated buffer and executes it at <targetaddr>.
561
            to an allocated buffer and executes it at <targetaddr>.
617
        """
562
        """
618
        targetaddr = self._hexint(targetaddr)
563
        targetaddr = to_int(targetaddr)
619
        addr, size = self.uploadfile(filename)
564
        addr, size = self.uploadfile(filename)
620
        self.execfirmware(targetaddr, addr, size)
565
        self.execfirmware(targetaddr, addr, size)
621
    
566
    
622
    @command
567
    @command
623
    def execfirmware(self, targetaddr, addr, size):
568
    def execfirmware(self, targetaddr, addr, size):
624
        """
569
        """
625
            Moves the firmware at <addr> with <size> to <targetaddr> and executes it
570
            Moves the firmware at <addr> with <size> to <targetaddr> and executes it
626
        """
571
        """
627
        targetaddr = self._hexint(targetaddr)
572
        targetaddr = to_int(targetaddr)
628
        addr = self._hexint(addr)
573
        addr = to_int(addr)
629
        size = self._hexint(size)
574
        size = self._hexint(size)
630
        self.logger.info("Running firmware at "+self._hex(targetaddr)+". Bye.\n")
575
        self.logger.info("Running firmware at "+self._hex(targetaddr)+". Bye.\n")
631
        self.emcore.execfirmware(targetaddr, addr, size)
576
        self.emcore.execfirmware(targetaddr, addr, size)
632
    
577
    
633
    @command
578
    @command
Line 636... Line 581...
636
            Encrypts a buffer using a hardware key
581
            Encrypts a buffer using a hardware key
637
            <addr>: the starting address of the buffer
582
            <addr>: the starting address of the buffer
638
            <size>: the size of the buffer
583
            <size>: the size of the buffer
639
            <keyindex>: the index of the key in the crypto unit
584
            <keyindex>: the index of the key in the crypto unit
640
        """
585
        """
641
        addr = self._hexint(addr)
586
        addr = to_int(addr)
642
        size = self._hexint(size)
587
        size = to_int(size)
643
        keyindex = self._hexint(keyindex)
588
        keyindex = to_int(keyindex)
644
        self.emcore.aesencrypt(addr, size, keyindex)
589
        self.emcore.aesencrypt(addr, size, keyindex)
645
    
590
    
646
    @command
591
    @command
647
    def aesdecrypt(self, addr, size, keyindex):
592
    def aesdecrypt(self, addr, size, keyindex):
648
        """
593
        """
649
            Decrypts a buffer using a hardware key
594
            Decrypts a buffer using a hardware key
650
            <addr>: the starting address of the buffer
595
            <addr>: the starting address of the buffer
651
            <size>: the size of the buffer
596
            <size>: the size of the buffer
652
            <keyindex>: the index of the key in the crypto unit
597
            <keyindex>: the index of the key in the crypto unit
653
        """
598
        """
654
        addr = self._hexint(addr)
599
        addr = to_int(addr)
655
        size = self._hexint(size)
600
        size = to_int(size)
656
        keyindex = self._hexint(keyindex)
601
        keyindex = to_int(keyindex)
657
        self.emcore.aesdecrypt(addr, size, keyindex)
602
        self.emcore.aesdecrypt(addr, size, keyindex)
658
    
603
    
659
    @command
604
    @command
660
    def hmac_sha1(self, addr, size, destination):
605
    def hmac_sha1(self, addr, size, destination):
661
        """
606
        """
662
            Generates a HMAC-SHA1 hash of the buffer
607
            Generates a HMAC-SHA1 hash of the buffer
663
            <addr>: the starting address of the buffer
608
            <addr>: the starting address of the buffer
664
            <size>: the size of the buffer
609
            <size>: the size of the buffer
665
            <destination>: the location where the key will be stored
610
            <destination>: the location where the key will be stored
666
        """
611
        """
667
        addr = self._hexint(addr)
612
        addr = to_int(addr)
668
        size = self._hexint(size)
613
        size = to_int(size)
669
        destination = self._hexint(destination)
614
        destination = to_int(destination)
670
        sha1size = 0x14
615
        sha1size = 0x14
671
        self.logger.info("Generating hmac-sha1 hash from the buffer at 0x%X with the size 0x%X and saving it to 0x%X - 0x%X\n" %
616
        self.logger.info("Generating hmac-sha1 hash from the buffer at 0x%X with the size 0x%X and saving it to 0x%X - 0x%X\n" %
672
                        (addr, size, destination, destination + sha1size))
617
                        (addr, size, destination, destination + sha1size))
673
        self.emcore.hmac_sha1(addr, size, destination)
618
        self.emcore.hmac_sha1(addr, size, destination)
674
        self.logger.info("done\n")
619
        self.logger.info("done\n")
Line 698... Line 643...
698
            <start>: start block
643
            <start>: start block
699
            <count>: block count
644
            <count>: block count
700
            [doecc]: use ecc error correction data
645
            [doecc]: use ecc error correction data
701
            [checkempty]: set statusflags if pages are empty
646
            [checkempty]: set statusflags if pages are empty
702
        """
647
        """
703
        addr = self._hexint(addr)
648
        addr = to_int(addr)
704
        start = self._hexint(start)
649
        start = to_int(start)
705
        count = self._hexint(count)
650
        count = to_int(count)
706
        doecc = self._bool(doecc)
651
        doecc = to_bool(doecc)
707
        checkempty = self._bool(checkempty)
652
        checkempty = to_bool(checkempty)
708
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
653
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
709
                        (count, start, addr))
654
                        (count, start, addr))
710
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
655
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
711
        self.logger.info("done\n")
656
        self.logger.info("done\n")
712
    
657
    
Line 718... Line 663...
718
            <addr>: the memory location where the data is read from
663
            <addr>: the memory location where the data is read from
719
            <start>: start block
664
            <start>: start block
720
            <count>: block count
665
            <count>: block count
721
            [doecc]: create ecc error correction data
666
            [doecc]: create ecc error correction data
722
        """
667
        """
723
        addr = self._hexint(addr)
668
        addr = to_int(addr)
724
        start = self._hexint(start)
669
        start = to_int(start)
725
        count = self._hexint(count)
670
        count = to_int(count)
726
        doecc = self._bool(doecc)
671
        doecc = to_bool(doecc)
727
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
672
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
728
                        (count, start, addr))
673
                        (count, start, addr))
729
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
674
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
730
        self.logger.info("done\n")
675
        self.logger.info("done\n")
731
    
676
    
Line 736... Line 681...
736
            Erases blocks on the NAND chip and stores the results to memory
681
            Erases blocks on the NAND chip and stores the results to memory
737
            <addr>: the memory location where the results are stored
682
            <addr>: the memory location where the results are stored
738
            <start>: start block
683
            <start>: start block
739
            <count>: block count
684
            <count>: block count
740
        """
685
        """
741
        addr = self._hexint(addr)
686
        addr = to_int(addr)
742
        start = self._hexint(start)
687
        start = to_int(start)
743
        count = self._hexint(count)
688
        count = to_int(count)
744
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
689
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
745
                        (count, start, addr))
690
                        (count, start, addr))
746
        self.emcore.ipodnano2g_nanderase(addr, start, count)
691
        self.emcore.ipodnano2g_nanderase(addr, start, count)
747
        self.logger.info("done\n")
692
        self.logger.info("done\n")
748
    
693
    
Line 812... Line 757...
812
        """
757
        """
813
            Target-specific function: ipodclassic
758
            Target-specific function: ipodclassic
814
            Uploads the bad block table <filename> to
759
            Uploads the bad block table <filename> to
815
            memory at <tempaddr> and writes it to the hard disk
760
            memory at <tempaddr> and writes it to the hard disk
816
        """
761
        """
817
        tempaddr = self._hexint(tempaddr)
762
        tempaddr = to_int(tempaddr)
818
        try:
763
        try:
819
            f = open(filename, 'rb')
764
            f = open(filename, 'rb')
820
        except IOError:
765
        except IOError:
821
            raise ArgumentError("File not readable. Does it exist?")
766
            raise ArgumentError("File not readable. Does it exist?")
822
        self.logger.info("Writing bad block table to disk...")
767
        self.logger.info("Writing bad block table to disk...")
Line 828... Line 773...
828
    def getvolumeinfo(self, volume):
773
    def getvolumeinfo(self, volume):
829
        """
774
        """
830
            Gathers some information about a storage volume used
775
            Gathers some information about a storage volume used
831
            <volume>: volume id
776
            <volume>: volume id
832
        """
777
        """
833
        volume = self._hexint(volume)
778
        volume = to_int(volume)
834
        data = self.emcore.storage_get_info(volume)
779
        data = self.emcore.storage_get_info(volume)
835
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
780
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
836
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
781
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
837
        self.logger.info("Vendor: %s\n" % data["vendor"])
782
        self.logger.info("Vendor: %s\n" % data["vendor"])
838
        self.logger.info("Product: %s\n" % data["product"])
783
        self.logger.info("Product: %s\n" % data["product"])
Line 841... Line 786...
841
    @command
786
    @command
842
    def readrawstorage(self, volume, sector, count, addr):
787
    def readrawstorage(self, volume, sector, count, addr):
843
        """
788
        """
844
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
789
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
845
        """
790
        """
846
        volume = self._hexint(volume)
791
        volume = to_int(volume)
847
        sector = self._hexint(sector)
792
        sector = to_int(sector)
848
        count = self._hexint(count)
793
        count = to_int(count)
849
        addr = self._hexint(addr)
794
        addr = to_int(addr)
850
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
795
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
851
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
796
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
852
        self.logger.info("done\n")
797
        self.logger.info("done\n")
853
    
798
    
854
    @command
799
    @command
855
    def writerawstorage(self, volume, sector, count, addr):
800
    def writerawstorage(self, volume, sector, count, addr):
856
        """
801
        """
857
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
802
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
858
        """
803
        """
859
        volume = self._hexint(volume)
804
        volume = to_int(volume)
860
        sector = self._hexint(sector)
805
        sector = to_int(sector)
861
        count = self._hexint(count)
806
        count = to_int(count)
862
        addr = self._hexint(addr)
807
        addr = to_int(addr)
863
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
808
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
864
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
809
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
865
        self.logger.info("done\n")
810
        self.logger.info("done\n")
866
    
811
    
867
    @command
812
    @command
868
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
813
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
869
        """
814
        """
870
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
815
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
871
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
816
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
872
        """
817
        """
873
        volume = self._hexint(volume)
818
        volume = to_int(volume)
874
        sector = self._hexint(sector)
819
        sector = to_int(sector)
875
        count = self._hexint(count)
820
        count = to_int(count)
876
        buffsize = self._hexint(buffsize)
821
        buffsize = to_int(buffsize)
877
        try:
822
        try:
878
            f = open(file, 'wb')
823
            f = open(file, 'wb')
879
        except IOError:
824
        except IOError:
880
            raise ArgumentError("Could not open local file for writing.")
825
            raise ArgumentError("Could not open local file for writing.")
881
        try:
826
        try:
Line 883... Line 828...
883
            buffsize = min(buffsize, storageinfo.sectorsize * count)
828
            buffsize = min(buffsize, storageinfo.sectorsize * count)
884
            if buffer is None:
829
            if buffer is None:
885
                buffer = self.emcore.malloc(buffsize)
830
                buffer = self.emcore.malloc(buffsize)
886
                malloc = True
831
                malloc = True
887
            else:
832
            else:
888
                buffer = self._hexint(buffer)
833
                buffer = to_int(buffer)
889
                malloc = False
834
                malloc = False
890
            try:
835
            try:
891
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
836
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
892
                while count > 0:
837
                while count > 0:
893
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
838
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
Line 906... Line 851...
906
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
851
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
907
        """
852
        """
908
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
853
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
909
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
854
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
910
        """
855
        """
911
        volume = self._hexint(volume)
856
        volume = to_int(volume)
912
        sector = self._hexint(sector)
857
        sector = to_int(sector)
913
        count = self._hexint(count)
858
        count = to_int(count)
914
        buffsize = self._hexint(buffsize)
859
        buffsize = to_int(buffsize)
915
        try:
860
        try:
916
            f = open(file, 'rb')
861
            f = open(file, 'rb')
917
        except IOError:
862
        except IOError:
918
            raise ArgumentError("Could not open local file for reading.")
863
            raise ArgumentError("Could not open local file for reading.")
919
        try:
864
        try:
Line 921... Line 866...
921
            buffsize = min(buffsize, storageinfo.sectorsize * count)
866
            buffsize = min(buffsize, storageinfo.sectorsize * count)
922
            if buffer is None:
867
            if buffer is None:
923
                buffer = self.emcore.malloc(buffsize)
868
                buffer = self.emcore.malloc(buffsize)
924
                malloc = True
869
                malloc = True
925
            else:
870
            else:
926
                buffer = self._hexint(buffer)
871
                buffer = to_int(buffer)
927
                malloc = False
872
                malloc = False
928
            try:
873
            try:
929
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
874
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
930
                while count > 0:
875
                while count > 0:
931
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
876
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
Line 1005... Line 950...
1005
            <remotename>: filename on the device
950
            <remotename>: filename on the device
1006
            <localname>: filename on the computer
951
            <localname>: filename on the computer
1007
            [buffsize]: buffer size (optional)
952
            [buffsize]: buffer size (optional)
1008
            [buffer]: buffer address (optional)
953
            [buffer]: buffer address (optional)
1009
        """
954
        """
1010
        buffsize = self._hexint(buffsize)
955
        buffsize = to_int(buffsize)
1011
        try:
956
        try:
1012
            f = open(localname, 'wb')
957
            f = open(localname, 'wb')
1013
        except IOError:
958
        except IOError:
1014
            raise ArgumentError("Could not open local file for writing.")
959
            raise ArgumentError("Could not open local file for writing.")
1015
        try:
960
        try:
Line 1019... Line 964...
1019
                buffsize = min(buffsize, size)
964
                buffsize = min(buffsize, size)
1020
                if buffer is None:
965
                if buffer is None:
1021
                    buffer = self.emcore.malloc(buffsize)
966
                    buffer = self.emcore.malloc(buffsize)
1022
                    malloc = True
967
                    malloc = True
1023
                else:
968
                else:
1024
                    buffer = self._hexint(buffer)
969
                    buffer = to_int(buffer)
1025
                    malloc = False
970
                    malloc = False
1026
                try:
971
                try:
1027
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
972
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
1028
                    while size > 0:
973
                    while size > 0:
1029
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
974
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
Line 1045... Line 990...
1045
            <remotepath>: path on the device
990
            <remotepath>: path on the device
1046
            <localpath>: path on the computer
991
            <localpath>: path on the computer
1047
            [buffsize]: buffer size (optional)
992
            [buffsize]: buffer size (optional)
1048
            [buffer]: buffer address (optional)
993
            [buffer]: buffer address (optional)
1049
        """
994
        """
1050
        buffsize = self._hexint(buffsize)
995
        buffsize = to_int(buffsize)
1051
        handle = self.emcore.dir_open(remotepath)
996
        handle = self.emcore.dir_open(remotepath)
1052
        try:
997
        try:
1053
            if buffer is None:
998
            if buffer is None:
1054
                buffer = self.emcore.malloc(buffsize)
999
                buffer = self.emcore.malloc(buffsize)
1055
                malloc = True
1000
                malloc = True
1056
            else:
1001
            else:
1057
                buffer = self._hexint(buffer)
1002
                buffer = to_int(buffer)
1058
                malloc = False
1003
                malloc = False
1059
            try:
1004
            try:
1060
                try: os.mkdir(localpath)
1005
                try: os.mkdir(localpath)
1061
                except: pass
1006
                except: pass
1062
                while True:
1007
                while True:
Line 1080... Line 1025...
1080
            <localname>: filename on the computer
1025
            <localname>: filename on the computer
1081
            <remotename>: filename on the device
1026
            <remotename>: filename on the device
1082
            [buffsize]: buffer size (optional)
1027
            [buffsize]: buffer size (optional)
1083
            [buffer]: buffer address (optional)
1028
            [buffer]: buffer address (optional)
1084
        """
1029
        """
1085
        buffsize = self._hexint(buffsize)
1030
        buffsize = to_int(buffsize)
1086
        try:
1031
        try:
1087
            f = open(localname, 'rb')
1032
            f = open(localname, 'rb')
1088
        except IOError:
1033
        except IOError:
1089
            raise ArgumentError("Could not open local file for reading.")
1034
            raise ArgumentError("Could not open local file for reading.")
1090
        try:
1035
        try:
1091
            buffsize = min(buffsize, os.path.getsize(localname))
1036
            buffsize = min(buffsize, os.path.getsize(localname))
1092
            if buffer is None:
1037
            if buffer is None:
1093
                buffer = self.emcore.malloc(buffsize)
1038
                buffer = self.emcore.malloc(buffsize)
1094
                malloc = True
1039
                malloc = True
1095
            else:
1040
            else:
1096
                buffer = self._hexint(buffer)
1041
                buffer = to_int(buffer)
1097
                malloc = False
1042
                malloc = False
1098
            try:
1043
            try:
1099
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
1044
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
1100
                fd = self.emcore.file_open(remotename, 0x15)
1045
                fd = self.emcore.file_open(remotename, 0x15)
1101
                try:
1046
                try:
Line 1122... Line 1067...
1122
            <localpath>: path on the computer
1067
            <localpath>: path on the computer
1123
            <remotepath>: path on the device
1068
            <remotepath>: path on the device
1124
            [buffsize]: buffer size (optional)
1069
            [buffsize]: buffer size (optional)
1125
            [buffer]: buffer address (optional)
1070
            [buffer]: buffer address (optional)
1126
        """
1071
        """
1127
        buffsize = self._hexint(buffsize)
1072
        buffsize = to_int(buffsize)
1128
        if buffer is None:
1073
        if buffer is None:
1129
            buffer = self.emcore.malloc(buffsize)
1074
            buffer = self.emcore.malloc(buffsize)
1130
            malloc = True
1075
            malloc = True
1131
        else:
1076
        else:
1132
            buffer = self._hexint(buffer)
1077
            buffer = to_int(buffer)
1133
            malloc = False
1078
            malloc = False
1134
        try:
1079
        try:
1135
            try: self.mkdir(remotepath)
1080
            try: self.mkdir(remotepath)
1136
            except: self.logger.info(" failed\n")
1081
            except: self.logger.info(" failed\n")
1137
            pathlen = len(localpath)
1082
            pathlen = len(localpath)
Line 1183... Line 1128...
1183
        self.emcore.dir_close(handle)
1128
        self.emcore.dir_close(handle)
1184
    
1129
    
1185
    @command
1130
    @command
1186
    def malloc(self, size):
1131
    def malloc(self, size):
1187
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
1132
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
1188
        size = self._hexint(size)
1133
        size = to_int(size)
1189
        self.logger.info("Allocating %d bytes of memory\n" % size)
1134
        self.logger.info("Allocating %d bytes of memory\n" % size)
1190
        addr = self.emcore.malloc(size)
1135
        addr = self.emcore.malloc(size)
1191
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
1136
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
1192
    
1137
    
1193
    @command
1138
    @command
1194
    def memalign(self, align, size):
1139
    def memalign(self, align, size):
1195
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
1140
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
1196
        align = self._hexint(align)
1141
        align = to_int(align)
1197
        size = self._hexint(size)
1142
        size = to_int(size)
1198
        self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
1143
        self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
1199
        addr = self.emcore.memalign(align, size)
1144
        addr = self.emcore.memalign(align, size)
1200
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
1145
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
1201
    
1146
    
1202
    @command
1147
    @command
1203
    def realloc(self, ptr, size):
1148
    def realloc(self, ptr, size):
1204
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1149
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1205
            expanding or reducing the amount of memory available in the block.
1150
            expanding or reducing the amount of memory available in the block.
1206
            Returns a pointer to the reallocated memory.
1151
            Returns a pointer to the reallocated memory.
1207
        """
1152
        """
1208
        ptr = self._hexint(ptr)
1153
        ptr = to_int(ptr)
1209
        size = self._hexint(size)
1154
        size = to_int(size)
1210
        self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
1155
        self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
1211
        addr = self.emcore.realloc(ptr, size)
1156
        addr = self.emcore.realloc(ptr, size)
1212
        self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
1157
        self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
1213
    
1158
    
1214
    @command
1159
    @command
1215
    def reownalloc(self, ptr, owner):
1160
    def reownalloc(self, ptr, owner):
1216
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
1161
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
1217
        ptr = self._hexint(ptr)
1162
        ptr = to_int(ptr)
1218
        owner = self._hexint(owner)
1163
        owner = to_int(owner)
1219
        self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
1164
        self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
1220
        self.emcore.reownalloc(ptr, owner)
1165
        self.emcore.reownalloc(ptr, owner)
1221
        self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
1166
        self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
1222
    
1167
    
1223
    @command
1168
    @command
1224
    def free(self, ptr):
1169
    def free(self, ptr):
1225
        """ Frees the memory space pointed to by 'ptr' """
1170
        """ Frees the memory space pointed to by 'ptr' """
1226
        ptr = self._hexint(ptr)
1171
        ptr = to_int(ptr)
1227
        self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
1172
        self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
1228
        self.emcore.free(ptr)
1173
        self.emcore.free(ptr)
1229
        self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
1174
        self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
1230
    
1175
    
1231
    @command
1176
    @command