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