Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
82 benedikt93 1
#!/usr/bin/env python
64 benedikt93 2
#
3
#
171 farthen 4
#    Copyright 2010 TheSeven, benedikt93, Farthen
64 benedikt93 5
#
6
#
82 benedikt93 7
#    This file is part of emBIOS.
64 benedikt93 8
#
82 benedikt93 9
#    emBIOS is free software: you can redistribute it and/or
64 benedikt93 10
#    modify it under the terms of the GNU General Public License as
11
#    published by the Free Software Foundation, either version 2 of the
12
#    License, or (at your option) any later version.
13
#
82 benedikt93 14
#    emBIOS is distributed in the hope that it will be useful,
64 benedikt93 15
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
#    See the GNU General Public License for more details.
18
#
82 benedikt93 19
#    You should have received a copy of the GNU General Public License
20
#    along with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
64 benedikt93 21
#
22
#
23
 
171 farthen 24
import sys
25
import os
26
import inspect
27
import re
176 farthen 28
import time
215 theseven 29
import struct
64 benedikt93 30
 
176 farthen 31
from functools import wraps
32
 
64 benedikt93 33
import libembios
171 farthen 34
from libembios import Error
35
import libembiosdata
64 benedikt93 36
 
171 farthen 37
class NotImplementedError(Error):
38
    pass
64 benedikt93 39
 
171 farthen 40
class ArgumentError(Error):
41
    pass
64 benedikt93 42
 
171 farthen 43
class ArgumentTypeError(Error):
44
    def __init__(self, expected, seen=False):
45
        self.expected = expected
46
        self.seen = seen
47
    def __str__(self):
48
        if self.seen:
49
            return "Expected " + str(self.expected) + " but saw " + str(self.seen)
50
        else:
51
            return "Expected " + str(self.expected) + ", but saw something else"
64 benedikt93 52
 
53
 
171 farthen 54
def usage(errormsg=None, specific=False):
55
    """
56
        Prints the usage information.
57
        It is auto generated from various places.
58
    """
59
    logger = Logger()
60
    cmddict= Commandline.cmddict
61
    doc = {}
62
    # This sorts the output of various internal functions
63
    # and puts everything in easy readable form
64
    for function in cmddict:
65
        function = cmddict[function].func
66
        docinfo = {}
67
        name = function.__name__
68
        args = inspect.getargspec(function)[0]
69
        docinfo['varargs'] = False
70
        if inspect.getargspec(function)[1]:
71
            docinfo['varargs'] = True
72
        kwargvalues = inspect.getargspec(function)[3]
73
        kwargs = {}
74
        if args:
75
            if kwargvalues:
76
                argnum = len(args) - len(kwargvalues)
77
                kwargnum = len(kwargvalues)
78
                kwargs = dict(zip(args[argnum:], kwargvalues))
79
            else:
80
                argnum = len(args)
81
        else:
82
            argnum = 0
83
        docinfo['args'] = args[1:argnum]
84
        docinfo['kwargs'] = kwargs
85
        if function.__doc__:
86
            # strip unneccessary whitespace
87
            docinfo['documentation'] = re.sub(r'\n        ', '\n', function.__doc__)
88
        else:
89
            docinfo['documentation'] = None
90
        doc[name] = docinfo
64 benedikt93 91
 
171 farthen 92
    if not specific:
93
        logger.log("Please provide a command and (if needed) parameters as command line arguments\n\n")
94
        logger.log("Available commands:\n\n")
82 benedikt93 95
    else:
171 farthen 96
        logger.log("\n")
97
    for function in sorted(doc.items()):
98
        function = function[0]
99
        if specific == False or specific == function:
100
            logger.log("  " + function + " ")
101
            for arg in doc[function]['args']:
102
                logger.log("<" + arg + "> ")
103
            if doc[function]['kwargs']:
104
                for kwarg in doc[function]['kwargs']:
105
                    logger.log("[" + kwarg + "] ")
106
            if doc[function]['varargs']:
107
                logger.log("<db1> ... <dbN>")
108
            if doc[function]['documentation']:
109
                logger.log(doc[function]['documentation']+"\n")
64 benedikt93 110
 
171 farthen 111
    logger.log("\n")
112
 
113
    if errormsg:
114
        logger.error(str(errormsg)+"\n")
115
    exit(2)
116
 
117
 
118
class Logger(object):
119
    """
120
        Simple stdout logger.
121
        Loglevel 4 is most verbose, Loglevel 0 only say something if there is an error.
122
    """
123
    def __init__(self):
124
        # Possible values: 0 (only errors), 1 (warnings), 2 (info, recommended for production use), 3 and more (debug)
125
        self.loglevel = 3
126
 
127
    def log(self, text):
128
        sys.stdout.write(text)
67 benedikt93 129
 
171 farthen 130
    def debug(self, text):
131
        if self.loglevel >= 3:
132
            self.log(text)
119 benedikt93 133
 
171 farthen 134
    def info(self, text):
135
        if self.loglevel >= 2:
136
            self.log(text)
82 benedikt93 137
 
171 farthen 138
    def warning(self, text):
139
        if self.loglevel >= 1:
140
            self.log("WARNING: " + text)
119 benedikt93 141
 
171 farthen 142
    def error(self, text):
143
        self.log("ERROR: " + text)
144
 
145
 
146
def command(func):
147
    """
148
        Decorator for all commands.
149
        The decorated function is called with (self, all, other, arguments, ...)
150
    """
176 farthen 151
    @wraps(func)
172 farthen 152
    def decorator(*args):
171 farthen 153
        return func(args[0], *args[1:])
154
    func._command = True
155
    decorator.func = func
156
    return decorator
157
 
158
 
159
def commandClass(cls):
160
    """
161
        Decorator for the class. Sets the self.cmddict of the class
162
        to all functions decorated with @command
163
    """
164
    cls.cmddict = {}
165
    for attr, value in cls.__dict__.iteritems():
166
        if getattr(value, 'func', False):
167
            if getattr(value.func, '_command', False):
168
                cls.cmddict[value.func.__name__] = value
169
    return cls
170
 
171
 
172
@commandClass
173
class Commandline(object):
174
    """
175
        If you want to create a new commandline function you just need to
176
        create a function with the name of it in this class and decorate
177
        it with the decorator @command. If you don't want to call the desired
178
        function (wrong arguments etc) just raise ArgumentError with or
179
        without an error message or raise ArgumentCountError
180
    """
181
    def __init__(self):
182
        self.logger = Logger()
183
        try:
184
            self.embios = libembios.Embios()
185
        except libembios.DeviceNotFoundError:
186
            self.logger.error("No emBIOS device found!")
176 farthen 187
            exit(1)
188
        self.getinfo("version")
171 farthen 189
 
190
    def _parsecommand(self, func, args):
191
        # adds self to the commandline args.
192
        # this is needed because the functions need access to their class.
193
        args.insert(0, self)
194
        if func in self.cmddict:
195
            try:
172 farthen 196
                self.cmddict[func](*args)
171 farthen 197
            except ArgumentError, e:
176 farthen 198
                usage(e, specific=func)
171 farthen 199
            except ArgumentError:
176 farthen 200
                usage("Syntax Error in function '" + func + "'", specific=func)
171 farthen 201
            except ArgumentTypeError, e:
176 farthen 202
                usage(e, specific=func)
171 farthen 203
            except NotImplementedError:
204
                self.logger.error("This function is not implemented yet!")
205
            except libembios.DeviceError, e:
206
                self.logger.error(str(e))
176 farthen 207
            except ValueError:
208
                usage(specific=func)
171 farthen 209
            except TypeError, e:
210
                if str(e).split(" ", 1)[0] == func + "()":
211
                    self.logger.error(usage("Argument Error in '" + func + "': Wrong argument count", specific=func))
212
                else:
213
                    raise
176 farthen 214
            except libembios.usb.core.USBError:
215
                self.logger.error("Problem with USB connection.")
171 farthen 216
        else:
217
            usage("No such command")
67 benedikt93 218
 
171 farthen 219
    @staticmethod
220
    def _bool(something):
221
        """
222
            Converts quite everything into bool.
223
        """
224
        if type(something) == bool:
225
            return something
226
        elif type(something) == int or type(something) == long:
227
            return bool(something)
228
        elif type(something == str):
229
            truelist = ['true', '1', 't', 'y', 'yes']
230
            falselist = ['false', '0', 'f', 'n', 'no']
231
            if something.lower() in truelist:
232
                return True
233
            elif something.lower() in falselist:
234
                return False
235
        raise ArgumentTypeError("bool", "'"+str(something)+"'")
236
 
237
    @staticmethod
238
    def _hexint(something):
239
        """
240
            Converts quite everything to a hexadecimal represented integer.
241
            This works for default arguments too, because it returns
242
            None when it found that it got a NoneType object.
243
        """
244
        if type(something) == int or type(something) == long:
245
            return something
246
        elif type(something) == str:
247
            try:
248
                return int(something, 16)
249
            except ValueError:
250
                raise ArgumentTypeError("hexadecimal coded integer", "'"+str(something)+"'")
251
        elif type(something) == NoneType:
252
            return None
253
        else:
254
            raise ArgumentTypeError("hexadecimal coded integer", "'"+str(something)+"'")
255
 
256
    @staticmethod
257
    def _strcheck(string, values):
258
        if string in values:
259
            return string
260
        else:
261
            expected = ""
262
            for item in values:
263
                expected += "'" + item + "', "
264
            expected = expected[:-2]
265
            raise ArgumentTypeError("one out of " + expected, "'" + string + "'")
64 benedikt93 266
 
173 farthen 267
    @staticmethod
268
    def _hex(integer):
269
        return "0x%x" % integer
64 benedikt93 270
 
171 farthen 271
    @command
272
    def getinfo(self, infotype):
273
        """
274
            Get info on the running emBIOS.
275
            <infotype> may be either of 'version', 'packetsize', 'usermemrange'.
276
        """
277
        if infotype == "version":
278
            resp = self.embios.getversioninfo()
172 farthen 279
            self.logger.info("Connected to "+libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) +
171 farthen 280
                             "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
281
        elif infotype == "packetsize":
282
            resp = self.embios.getpacketsizeinfo()
283
            self.logger.info("Maximum packet sizes: "+str(resp))
284
        elif infotype == "usermemrange":
285
            resp = self.embios.getusermemrange()
173 farthen 286
            self.logger.info("The user memory range is "+self._hex(resp.lower)+" - "+self._hex(resp.upper-1))
171 farthen 287
        else:
288
            raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", infotype)
64 benedikt93 289
 
171 farthen 290
    @command
291
    def reset(self, force=False):
292
        """
293
            Resets the device"
294
            If <force> is 1, the reset will be forced, otherwise it will be gracefully,
295
            which may take some time.
296
        """
297
        force = self._bool(force)
298
        if force: self.logger.info("Resetting forcefully...\n")
299
        else: self.logger.info("Resetting...\n")
300
        self.embios.reset(force)
64 benedikt93 301
 
171 farthen 302
    @command
303
    def poweroff(self, force=False):
304
        """
305
            Powers the device off
306
            If <force> is 1, the poweroff will be forced, otherwise it will be gracefully,
307
            which may take some time.
308
        """
309
        force = self._bool(force)
310
        if force: self.logger.info("Resetting forcefully...\n")
311
        else: self.logger.info("Resetting...\n")
312
        self.embios.reset(force)
64 benedikt93 313
 
171 farthen 314
    @command
315
    def uploadfile(self, addr, filename):
316
        """
317
            Uploads a file to the device
318
            <offset>: the address to upload the file to
319
            <filename>: the path to the file
320
        """
321
        addr = self._hexint(addr)
322
        try:
323
            f = open(filename, 'rb')
324
        except IOError:
325
            raise ArgumentError("File not readable. Does it exist?")
173 farthen 326
        self.logger.info("Writing file '"+filename+"' to memory at "+self._hex(addr)+"...")
171 farthen 327
        with f:
328
            self.embios.write(addr, f.read())
178 farthen 329
        f.close()
171 farthen 330
        self.logger.info("done\n")
176 farthen 331
 
171 farthen 332
    @command
333
    def downloadfile(self, addr, size, filename):
334
        """
335
            Uploads a file to the device
336
            <offset>: the address to upload the file to
337
            <size>: the number of bytes to be read
338
            <filename>: the path to the file
339
        """
340
        addr = self._hexint(addr)
341
        size = self._hexint(size)
342
        try:
343
            f = open(filename, 'wb')
344
        except IOError:
345
            raise ArgumentError("Can not open file for write!")
173 farthen 346
        self.logger.info("Reading data from address "+self._hex(addr)+" with the size "+self._hex(size)+" to '"+filename+"'...")
171 farthen 347
        with f:
348
            f.write(self.embios.read(addr, size))
178 farthen 349
        f.close()
171 farthen 350
        self.logger.info("done\n")
351
 
352
    @command
353
    def uploadint(self, addr, integer):
354
        """
355
            Uploads a single integer to the device
356
            <offset>: the address to upload the integer to
357
            <data>: the integer to upload
358
        """
359
        addr = self._hexint(addr)
360
        integer = self._hexint(integer)
361
        if integer > 0xFFFFFFFF:
362
            raise ArgumentError("Specified integer too long")
363
        data = chr(integer)
178 farthen 364
        self.embios.write(addr, data)
173 farthen 365
        self.logger.info("Integer '"+self._hex(integer)+"' written successfully to "+self._hex(addr))
171 farthen 366
 
367
    @command
368
    def downloadint(self, addr):
369
        """
370
            Downloads a single integer from the device and prints it to the console window
371
            <offset>: the address to download the integer from
372
        """
373
        addr = self._hexint(addr)
178 farthen 374
        data = self.embios.read(addr, 1)
171 farthen 375
        integer = ord(data)
173 farthen 376
        self.logger.info("Integer '"+self._hex(integer)+"' read from address "+self._hex(addr))
171 farthen 377
 
378
    @command
176 farthen 379
    def i2cread(self, bus, slave, addr, size):
171 farthen 380
        """
381
            Reads data from an I2C device
382
            <bus> the bus index
383
            <slave> the slave address
384
            <addr> the start address on the I2C device
385
            <size> the number of bytes to read
386
        """
387
        bus = self._hexint(bus)
388
        slave = self._hexint(slave)
389
        addr = self._hexint(addr)
390
        size = self._hexint(size)
215 theseven 391
        for i in range(size):
392
            print("%02X: %02X" % (addr + i, struct.unpack("B", self.embios.i2cread(bus, slave, addr + i, 1))[0]))
171 farthen 393
 
394
    @command
176 farthen 395
    def i2cwrite(self, bus, slave, addr, *args):
171 farthen 396
        """
397
            Writes data to an I2C device
398
            <bus> the bus index
399
            <slave> the slave address
400
            <addr> the start address on the I2C device
176 farthen 401
            <db1> ... <dbN> the data in single bytes, encoded in hex,
402
                seperated by whitespaces, eg. 37 56 45 12
171 farthen 403
        """
404
        bus = self._hexint(bus)
405
        slave = self._hexint(slave)
406
        addr = self._hexint(addr)
176 farthen 407
        data = ""
171 farthen 408
        for arg in args:
176 farthen 409
            data += chr(self._hexint(arg))
410
        self.embios.i2cwrite(bus, slave, addr, data)
171 farthen 411
 
412
    @command
176 farthen 413
    def console(self):
171 farthen 414
        """
176 farthen 415
            Reads data from the USB console continuously
171 farthen 416
        """
176 farthen 417
        while True:
418
            resp = self.embios.usbcread()
419
            self.logger.log(resp.data)
420
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
171 farthen 421
 
422
    @command
176 farthen 423
    def writeusbconsole(self, *args):
171 farthen 424
        """
176 farthen 425
            Writes the string <db1> ... <dbN> to the USB console.
171 farthen 426
        """
176 farthen 427
        text = ""
428
        for word in args:
429
            text += word + " "
430
        text = text[:-1]
431
        self.logger.info("Writing '"+text+"' to the usb console\n")
432
        self.embios.usbcwrite(text)
171 farthen 433
 
434
    @command
176 farthen 435
    def readdevconsole(self, bitmask):
171 farthen 436
        """
176 farthen 437
            Reads data continuously from one or more of the device's consoles.
438
            <bitmask>: the bitmask of the consoles to read from.
171 farthen 439
        """
440
        bitmask = self._hexint(bitmask)
176 farthen 441
        while True:
442
            resp = self.embios.cread()
443
            self.logger.log(resp.data)
444
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
445
 
171 farthen 446
    @command
176 farthen 447
    def writedevconsole(self, bitmask, *args):
171 farthen 448
        """
176 farthen 449
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
450
            <bitmask>: the bitmask of the consoles to write to
171 farthen 451
        """
452
        bitmask = self._hexint(bitmask)
176 farthen 453
        text = ""
454
        for word in args:
455
            text += word + " "
456
        text = text[:-1]
457
        self.logger.info("Writing '"+text+"' to the device consoles identified with "+self._hex(bitmask)+"\n")
458
        self.embios.cwrite(text, bitmask)
171 farthen 459
 
460
    @command
461
    def flushconsolebuffers(self, bitmask):
462
        """
463
            flushes one or more of the device consoles' buffers.
464
            <bitmask>: the bitmask of the consoles to be flushed
465
        """
466
        bitmask = self._hexint(bitmask)
467
        raise NotImplementedError
468
 
469
    @command
470
    def getprocinfo(self):
471
        """
472
            Fetches data on the currently running processes
473
        """
173 farthen 474
        import datetime
475
        threads = self.embios.getprocinfo()
476
        self.logger.info("The device has "+str(len(threads))+" running threads:\n\n")
477
        for thread in threads:
478
            self.logger.info("  "+thread.name+":\n")
479
            self.logger.info("    Thread id: "+str(thread.id)+"\n")
480
            self.logger.info("    Thread type: "+thread.type+"\n")
481
            self.logger.info("    Thread state: "+thread.state+"\n")
482
            self.logger.info("    Priority: "+str(thread.priority)+"/256\n")
483
            self.logger.info("    CPU time (total): "+str(datetime.timedelta(microseconds=thread.cputime_total))+"\n")
484
            self.logger.info("    Stack address: "+self._hex(thread.stackaddr)+"\n")
485
            self.logger.info("    Registers:\n")
177 farthen 486
            for registerrange in range(4):
487
                self.logger.info("      ")
488
                for register in range(registerrange, 16, 4):
489
                    registerrepr = "r"+str(register)
490
                    self.logger.info("{:3s}: 0x{:08X}    ".format(registerrepr, thread.regs["r"+str(register)]))
491
                self.logger.info("\n")
492
            self.logger.info("      cpsr: 0x{:08X}".format(thread.regs.cpsr))
173 farthen 493
            self.logger.info("\n")
494
 
171 farthen 495
    @command
496
    def lockscheduler(self):
497
        """
498
            Locks (freezes) the scheduler
499
        """
176 farthen 500
        self.logger.info("Will now lock scheduler\n")
173 farthen 501
        self.embios.lockscheduler()
178 farthen 502
 
171 farthen 503
    @command
504
    def unlockscheduler(self):
505
        """
506
            Unlocks (unfreezes) the scheduler
507
        """
176 farthen 508
        self.logger.info("Will now unlock scheduler\n")
173 farthen 509
        self.embios.unlockscheduler()
178 farthen 510
 
171 farthen 511
    @command
512
    def suspendthread(self, threadid):
513
        """
514
            Suspends/resumes the thread with thread ID <threadid>
515
        """
516
        threadid = self._hexint(threadid)
173 farthen 517
        self.embios.resumethread(threadid)
171 farthen 518
 
519
    @command
520
    def resumethread(self, threadid):
521
        """
522
            Resumes the thread with thread ID <threadid>
523
        """
524
        threadid = self._hexint(threadid)
173 farthen 525
        self.embios.resumethread(threadid)
171 farthen 526
 
527
    @command
528
    def killthread(self, threadid):
529
        """
530
            Kills the thread with thread ID <threadid>
531
        """
532
        threadid = self._hexint(threadid)
173 farthen 533
        self.embios.killthread(threadid)
171 farthen 534
 
535
    @command
536
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
537
        """
538
            Creates a new thread and returns its thread ID
539
            <namepointer> a pointer to the thread's name
540
            <entrypoint> a pointer to the entrypoint of the thread
541
            <stackpointer> a pointer to the stack of the thread
542
            <stacksize> the size of the thread's stack
543
            <type> the thread type, vaild are: 0 => user thread, 1 => system thread
544
            <priority> the priority of the thread, from 1 to 255
545
            <state> the thread's initial state, valid are: 1 => ready, 0 => suspended
546
        """
547
        nameptr = self._hexint(nameptr)
548
        entrypoint = self._hexint(entrypoint)
549
        stackpointer = self._hexint(stackpointer)
550
        stacksize = self._hexint(stacksize)
551
        priority = self._hexint(priority)
552
        self.embios.createthread(nameptr, entrypoint, stackptr, stacksize, type, priority, state)
172 farthen 553
 
554
    @command
555
    def run(self, filename):
556
        """
173 farthen 557
            Uploads the emBIOS application <filename> to
558
            the beginning of the user memory and executes it
172 farthen 559
        """
176 farthen 560
        #self.execimage(addr)
561
        raise NotImplementedError
171 farthen 562
 
563
    @command
173 farthen 564
    def execimage(self, addr):
171 farthen 565
        """
173 farthen 566
            Executes the emBIOS application at <addr>.
171 farthen 567
        """
172 farthen 568
        addr = self._hexint(addr)
173 farthen 569
        self.logger.info("Starting emBIOS app at "+self._hex(addr)+"\n")
172 farthen 570
        self.embios.execimage(addr)
176 farthen 571
 
171 farthen 572
    @command
176 farthen 573
    def flushcaches(self):
171 farthen 574
        """
176 farthen 575
            Flushes the CPUs data and instruction caches.
576
        """
577
        self.logger.info("Flushing CPU data and instruction caches...")
578
        self.embios.flushcaches()
579
        self.logger.info("done\n")
580
 
581
    @command
582
    def readbootflash(self, addr_flash, addr_mem, size):
583
        """
171 farthen 584
            Reads <size> bytes from bootflash to memory.
585
            <addr_bootflsh>: the address in bootflash to read from
586
            <addr_mem>: the address in memory to copy the data to
587
        """
588
        addr_flash = self._hexint(addr_flash)
589
        addr_mem = self._hexint(addr_mem)
590
        size = self._hexint(size)
174 farthen 591
        self.logger.info("Dumping boot flash addresses "+self._hex(addr_flash)+" - "+
592
                         hex(addr_flash+size)+" to "+self._hex(addr_mem)+" - "+self._hex(addr_mem+size)+"\n")
593
        self.embios.bootflashread(addr_flash, addr_mem, size)
176 farthen 594
 
171 farthen 595
    @command
176 farthen 596
    def writebootflash(self, addr_flash, addr_mem, size, force=False):
171 farthen 597
        """
598
            Writes <size> bytes from memory to bootflash.
599
            ATTENTION: Don't call this unless you really know what you're doing!
600
            This may BRICK your device (unless it has a good recovery option)
601
            <addr_mem>: the address in memory to copy the data from
602
            <addr_bootflsh>: the address in bootflash to write to
174 farthen 603
            <force>: Use this flag to suppress the 5 seconds delay
171 farthen 604
        """
605
        addr_flash = self._hexint(addr_flash)
606
        addr_mem = self._hexint(addr_mem)
607
        size = self._hexint(size)
174 farthen 608
        force = self._bool(force)
609
        self.logger.info("Writing boot flash from the memory in "+self._hex(addr_mem)+" - "+
610
                         hex(addr_mem+size)+" to "+self._hex(addr_flash)+" - "+self._hex(addr_flash+size)+"\n")
611
        if force == False:
612
            self.logger.info("If this was not what you intended press Ctrl-C NOW")
176 farthen 613
            for i in range(10):
174 farthen 614
                self.logger.info(".")
615
                time.sleep(1)
616
            self.logger.info("\n")
617
        self.embios.bootflashwrite(addr_flash, addr_mem, size)
176 farthen 618
 
171 farthen 619
    @command
176 farthen 620
    def runfirmware(self, addr, filename):
171 farthen 621
        """
176 farthen 622
            Uploads the firmware in 'filename' to the beginning of the
623
            user memory and executes it
171 farthen 624
        """
176 farthen 625
        addr = self._hexint(addr)
626
        self.uploadfile(addr, filename)
627
        self.execfirmware(addr)
64 benedikt93 628
 
171 farthen 629
    @command
176 farthen 630
    def execfirmware(self, addr):
631
        """
632
            Executes the firmware at addr
633
        """
634
        addr = self._hexint(addr)
635
        self.logger.info("Running firmware at "+self._hex(addr)+". Bye.")
636
        self.embios.execfirmware(addr)
637
 
638
    @command
171 farthen 639
    def aesencrypt(self, addr, size, keyindex):
640
        """
172 farthen 641
            Encrypts a buffer using a hardware key
171 farthen 642
        """
643
        addr = self._hexint(addr)
644
        size = self._hexint(size)
645
        keyindex = self._hexint(keyindex)
646
        self.embios.aesencrypt(addr, size, keyindex)
82 benedikt93 647
 
171 farthen 648
    @command
649
    def aesdecrypt(self, addr, size, keyindex):
650
        """
172 farthen 651
            Decrypts a buffer using a hardware key
171 farthen 652
        """
653
        addr = self._hexint(addr)
654
        size = self._hexint(size)
655
        keyindex = self._hexint(keyindex)
656
        self.embios.aesdecrypt(addr, size, keyindex)
172 farthen 657
 
658
    @command
659
    def hmac_sha1(self, addr, size, destination):
660
        """
661
            Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination'
662
        """
663
        addr = self._hexint(addr)
664
        size = self._hexint(size)
665
        destination = self._hexint(destination)
666
        sha1size = 0x14
173 farthen 667
        self.logger.info("Generating hmac-sha1 hash from the buffer at "+self._hex(addr)+" with the size "+self._hex(size)+
668
                         " and saving it to "+self._hex(destination)+" - "+self._hex(destination+sha1size)+"...")
172 farthen 669
        self.embios.hmac_sha1(addr, size, destination)
670
        self.logger.info("done\n")
178 farthen 671
        data = self.embios.read(destination, sha1size)
172 farthen 672
        hash = ord(data)
173 farthen 673
        self.logger.info("The generated hash is "+self._hex(hash))
64 benedikt93 674
 
227 theseven 675
    @command
676
    def ipodnano2g_getnandinfo(self):
677
        """
678
            Target-specific function: ipodnano2g
679
            Gathers some information about the NAND chip used
680
        """
681
        data = self.embios.ipodnano2g_getnandinfo()
682
        self.logger.info("NAND chip type: "+self._hex(data["type"])+"\n")
683
        self.logger.info("Number of banks: "+str(data["banks"])+"\n")
684
        self.logger.info("Number of blocks: "+str(data["blocks"])+"\n")
685
        self.logger.info("Number of user blocks: "+str(data["userblocks"])+"\n")
686
        self.logger.info("Pages per block: "+str(data["pagesperblock"]))
687
 
688
    @command
689
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
690
        """
691
            Target-specific function: ipodnano2g
692
            Reads data from the NAND chip into memory
693
        """
694
        addr = self._hexint(addr)
695
        start = self._hexint(start)
696
        count = self._hexint(count)
697
        doecc = int(doecc)
698
        checkempty = int(checkempty)
699
        self.logger.info("Reading "+self._hex(count)+" NAND pages starting at "+self._hex(start)+" to "+self._hex(addr)+"...")
700
        self.embios.lib.dev.timeout = 20000
701
        self.embios.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
702
        self.logger.info("done\n")
703
 
704
    @command
705
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
706
        """
707
            Target-specific function: ipodnano2g
708
            Writes data to the NAND chip
709
        """
710
        addr = self._hexint(addr)
711
        start = self._hexint(start)
712
        count = self._hexint(count)
713
        doecc = int(doecc)
714
        self.logger.info("Writing "+self._hex(count)+" NAND pages starting at "+self._hex(start)+" from "+self._hex(addr)+"...")
715
        self.embios.lib.dev.timeout = 20000
716
        self.embios.ipodnano2g_nandwrite(addr, start, count, doecc)
717
        self.logger.info("done\n")
718
 
719
    @command
720
    def ipodnano2g_nanderase(self, addr, start, count):
721
        """
722
            Target-specific function: ipodnano2g
723
            Erases blocks on the NAND chip and stores the results to memory
724
        """
725
        addr = self._hexint(addr)
726
        start = self._hexint(start)
727
        count = self._hexint(count)
728
        self.logger.info("Erasing "+self._hex(count)+" NAND blocks starting at "+self._hex(start)+" and logging to "+self._hex(addr)+"...")
729
        self.embios.lib.dev.timeout = 20000
730
        self.embios.ipodnano2g_nanderase(addr, start, count)
731
        self.logger.info("done\n")
732
 
171 farthen 733
if __name__ == "__main__":
734
    if len(sys.argv) < 2:
735
        usage("No command specified")
736
    interface = Commandline()
737
    interface._parsecommand(sys.argv[1], sys.argv[2:])