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
341 farthen 180
        without an error message.
171 farthen 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)
341 farthen 198
            except (ArgumentError, libembios.ArgumentError), e:
176 farthen 199
                usage(e, specific=func)
341 farthen 200
            except (ArgumentError, libembios.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))
208
            except TypeError, e:
341 farthen 209
                # Only act on TypeErrors for the function we called, not on TypeErrors raised by another function.
171 farthen 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:
341 farthen 215
                self.logger.error("There is a problem with the 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)+"'")
64 benedikt93 255
 
173 farthen 256
    @staticmethod
257
    def _hex(integer):
258
        return "0x%x" % integer
64 benedikt93 259
 
171 farthen 260
    @command
261
    def getinfo(self, infotype):
262
        """
263
            Get info on the running emBIOS.
264
            <infotype> may be either of 'version', 'packetsize', 'usermemrange'.
265
        """
266
        if infotype == "version":
267
            resp = self.embios.getversioninfo()
271 farthen 268
            try:
269
                hwtype = libembiosdata.hwtypes[resp.hwtypeid]
270
            except KeyError:
271
                hwtype = "UNKNOWN (ID = " + self._hex(resp.hwtypeid) + ")"
172 farthen 272
            self.logger.info("Connected to "+libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) +
271 farthen 273
                             "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + hwtype + "\n")
171 farthen 274
        elif infotype == "packetsize":
275
            resp = self.embios.getpacketsizeinfo()
276
            self.logger.info("Maximum packet sizes: "+str(resp))
277
        elif infotype == "usermemrange":
278
            resp = self.embios.getusermemrange()
173 farthen 279
            self.logger.info("The user memory range is "+self._hex(resp.lower)+" - "+self._hex(resp.upper-1))
171 farthen 280
        else:
281
            raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", infotype)
64 benedikt93 282
 
171 farthen 283
    @command
284
    def reset(self, force=False):
285
        """
286
            Resets the device"
287
            If <force> is 1, the reset will be forced, otherwise it will be gracefully,
288
            which may take some time.
289
        """
290
        force = self._bool(force)
291
        if force: self.logger.info("Resetting forcefully...\n")
292
        else: self.logger.info("Resetting...\n")
293
        self.embios.reset(force)
64 benedikt93 294
 
171 farthen 295
    @command
296
    def poweroff(self, force=False):
297
        """
298
            Powers the device off
299
            If <force> is 1, the poweroff will be forced, otherwise it will be gracefully,
300
            which may take some time.
301
        """
302
        force = self._bool(force)
281 farthen 303
        if force: self.logger.info("Powering off forcefully...\n")
304
        else: self.logger.info("Powering off...\n")
305
        self.embios.poweroff(force)
64 benedikt93 306
 
171 farthen 307
    @command
308
    def uploadfile(self, addr, filename):
309
        """
310
            Uploads a file to the device
311
            <offset>: the address to upload the file to
312
            <filename>: the path to the file
313
        """
314
        addr = self._hexint(addr)
315
        try:
316
            f = open(filename, 'rb')
317
        except IOError:
318
            raise ArgumentError("File not readable. Does it exist?")
173 farthen 319
        self.logger.info("Writing file '"+filename+"' to memory at "+self._hex(addr)+"...")
171 farthen 320
        with f:
321
            self.embios.write(addr, f.read())
178 farthen 322
        f.close()
171 farthen 323
        self.logger.info("done\n")
176 farthen 324
 
171 farthen 325
    @command
326
    def downloadfile(self, addr, size, filename):
327
        """
328
            Uploads a file to the device
329
            <offset>: the address to upload the file to
330
            <size>: the number of bytes to be read
331
            <filename>: the path to the file
332
        """
333
        addr = self._hexint(addr)
334
        size = self._hexint(size)
335
        try:
336
            f = open(filename, 'wb')
337
        except IOError:
338
            raise ArgumentError("Can not open file for write!")
173 farthen 339
        self.logger.info("Reading data from address "+self._hex(addr)+" with the size "+self._hex(size)+" to '"+filename+"'...")
171 farthen 340
        with f:
341
            f.write(self.embios.read(addr, size))
178 farthen 342
        f.close()
171 farthen 343
        self.logger.info("done\n")
344
 
345
    @command
346
    def uploadint(self, addr, integer):
347
        """
348
            Uploads a single integer to the device
260 theseven 349
            <addr>: the address to upload the integer to
350
            <integer>: the integer to upload
171 farthen 351
        """
352
        addr = self._hexint(addr)
353
        integer = self._hexint(integer)
354
        if integer > 0xFFFFFFFF:
355
            raise ArgumentError("Specified integer too long")
260 theseven 356
        data = struct.pack("I", integer)
178 farthen 357
        self.embios.write(addr, data)
236 farthen 358
        self.logger.info("Integer '"+self._hex(integer)+"' written successfully to "+self._hex(addr)+"\n")
171 farthen 359
 
360
    @command
361
    def downloadint(self, addr):
362
        """
363
            Downloads a single integer from the device and prints it to the console window
236 farthen 364
            <addr>: the address to download the integer from
171 farthen 365
        """
366
        addr = self._hexint(addr)
260 theseven 367
        data = self.embios.read(addr, 4)
368
        integer = struct.unpack("I", data)[0]
236 farthen 369
        self.logger.info("Integer '"+self._hex(integer)+"' read from address "+self._hex(addr)+"\n")
171 farthen 370
 
371
    @command
176 farthen 372
    def i2cread(self, bus, slave, addr, size):
171 farthen 373
        """
374
            Reads data from an I2C device
375
            <bus> the bus index
376
            <slave> the slave address
377
            <addr> the start address on the I2C device
378
            <size> the number of bytes to read
379
        """
380
        bus = self._hexint(bus)
381
        slave = self._hexint(slave)
382
        addr = self._hexint(addr)
383
        size = self._hexint(size)
236 farthen 384
        data = self.embios.i2cread(bus, slave, addr, size)
385
        bytes = struct.unpack("%dB" % len(data), data)
386
        self.logger.info("Data read from I2C:\n")
387
        for index, byte in enumerate(bytes):
388
            self.logger.info("%02X: %02X\n" % (index, byte))
171 farthen 389
 
390
    @command
176 farthen 391
    def i2cwrite(self, bus, slave, addr, *args):
171 farthen 392
        """
393
            Writes data to an I2C device
394
            <bus> the bus index
395
            <slave> the slave address
396
            <addr> the start address on the I2C device
176 farthen 397
            <db1> ... <dbN> the data in single bytes, encoded in hex,
236 farthen 398
                seperated by whitespaces, eg. 37 5A 4F EB
171 farthen 399
        """
400
        bus = self._hexint(bus)
401
        slave = self._hexint(slave)
402
        addr = self._hexint(addr)
176 farthen 403
        data = ""
171 farthen 404
        for arg in args:
176 farthen 405
            data += chr(self._hexint(arg))
236 farthen 406
        self.logger.info("Writing data to I2C...\n")
176 farthen 407
        self.embios.i2cwrite(bus, slave, addr, data)
236 farthen 408
        self.logger.info("done\n")
171 farthen 409
 
410
    @command
176 farthen 411
    def console(self):
171 farthen 412
        """
176 farthen 413
            Reads data from the USB console continuously
171 farthen 414
        """
176 farthen 415
        while True:
416
            resp = self.embios.usbcread()
417
            self.logger.log(resp.data)
418
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
171 farthen 419
 
420
    @command
176 farthen 421
    def writeusbconsole(self, *args):
171 farthen 422
        """
176 farthen 423
            Writes the string <db1> ... <dbN> to the USB console.
171 farthen 424
        """
176 farthen 425
        text = ""
426
        for word in args:
427
            text += word + " "
428
        text = text[:-1]
236 farthen 429
        self.logger.info("Writing '"+ text +"' to the usb console\n")
176 farthen 430
        self.embios.usbcwrite(text)
171 farthen 431
 
432
    @command
176 farthen 433
    def readdevconsole(self, bitmask):
171 farthen 434
        """
176 farthen 435
            Reads data continuously from one or more of the device's consoles.
436
            <bitmask>: the bitmask of the consoles to read from.
171 farthen 437
        """
438
        bitmask = self._hexint(bitmask)
176 farthen 439
        while True:
440
            resp = self.embios.cread()
441
            self.logger.log(resp.data)
442
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
443
 
171 farthen 444
    @command
176 farthen 445
    def writedevconsole(self, bitmask, *args):
171 farthen 446
        """
176 farthen 447
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
448
            <bitmask>: the bitmask of the consoles to write to
171 farthen 449
        """
450
        bitmask = self._hexint(bitmask)
176 farthen 451
        text = ""
452
        for word in args:
453
            text += word + " "
454
        text = text[:-1]
455
        self.logger.info("Writing '"+text+"' to the device consoles identified with "+self._hex(bitmask)+"\n")
456
        self.embios.cwrite(text, bitmask)
171 farthen 457
 
458
    @command
459
    def flushconsolebuffers(self, bitmask):
460
        """
461
            flushes one or more of the device consoles' buffers.
462
            <bitmask>: the bitmask of the consoles to be flushed
463
        """
464
        bitmask = self._hexint(bitmask)
236 farthen 465
        self.logger.info("Flushing consoles identified with the bitmask "+self._hex(bitmask)+"\n")
466
        self.embios.cflush(bitmask)
171 farthen 467
 
468
    @command
469
    def getprocinfo(self):
470
        """
471
            Fetches data on the currently running processes
472
        """
173 farthen 473
        import datetime
474
        threads = self.embios.getprocinfo()
475
        self.logger.info("The device has "+str(len(threads))+" running threads:\n\n")
476
        for thread in threads:
477
            self.logger.info("  "+thread.name+":\n")
478
            self.logger.info("    Thread id: "+str(thread.id)+"\n")
479
            self.logger.info("    Thread type: "+thread.type+"\n")
480
            self.logger.info("    Thread state: "+thread.state+"\n")
481
            self.logger.info("    Priority: "+str(thread.priority)+"/256\n")
324 theseven 482
            self.logger.info("    Current CPU load: "+str((thread.cpuload*100)/255)+"%\n")
173 farthen 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)
318 theseven 490
                    self.logger.info("{0:3s}: 0x{1:08X}   ".format(registerrepr, thread.regs["r"+str(register)]))
177 farthen 491
                self.logger.info("\n")
318 theseven 492
            self.logger.info("     cpsr: 0x{0: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)
236 farthen 517
        self.logger.info("Suspending the thread with the threadid "+self._hex(threadid)+"\n")
518
        self.embios.suspendthread(threadid)
171 farthen 519
 
520
    @command
521
    def resumethread(self, threadid):
522
        """
523
            Resumes the thread with thread ID <threadid>
524
        """
525
        threadid = self._hexint(threadid)
236 farthen 526
        self.logger.info("Resuming the thread with the threadid "+self._hex(threadid)+"\n")
173 farthen 527
        self.embios.resumethread(threadid)
171 farthen 528
 
529
    @command
530
    def killthread(self, threadid):
531
        """
532
            Kills the thread with thread ID <threadid>
533
        """
534
        threadid = self._hexint(threadid)
236 farthen 535
        self.logger.info("Killing the thread with the threadid " + self._hex(threadid) + "\n")
173 farthen 536
        self.embios.killthread(threadid)
171 farthen 537
 
538
    @command
539
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
540
        """
541
            Creates a new thread and returns its thread ID
542
            <namepointer> a pointer to the thread's name
543
            <entrypoint> a pointer to the entrypoint of the thread
544
            <stackpointer> a pointer to the stack of the thread
545
            <stacksize> the size of the thread's stack
546
            <type> the thread type, vaild are: 0 => user thread, 1 => system thread
547
            <priority> the priority of the thread, from 1 to 255
548
            <state> the thread's initial state, valid are: 1 => ready, 0 => suspended
549
        """
550
        nameptr = self._hexint(nameptr)
551
        entrypoint = self._hexint(entrypoint)
552
        stackpointer = self._hexint(stackpointer)
553
        stacksize = self._hexint(stacksize)
554
        priority = self._hexint(priority)
236 farthen 555
        data = self.embios.createthread(nameptr, entrypoint, stackptr, stacksize, type, priority, state)
556
        name = self.embios.readstring(nameptr)
557
        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 558
 
559
    @command
560
    def run(self, filename):
561
        """
173 farthen 562
            Uploads the emBIOS application <filename> to
236 farthen 563
            the memory and executes it
172 farthen 564
        """
236 farthen 565
        try:
566
            f = open(filename, 'rb')
567
        except IOError:
568
            raise ArgumentError("File not readable. Does it exist?")
238 farthen 569
        with f:
570
            data = self.embios.run(f.read())
571
        self.logger.info("Executed emBIOS application \"" + data.name + "\" at address " + self._hex(data.baseaddr))
171 farthen 572
 
573
    @command
173 farthen 574
    def execimage(self, addr):
171 farthen 575
        """
173 farthen 576
            Executes the emBIOS application at <addr>.
171 farthen 577
        """
172 farthen 578
        addr = self._hexint(addr)
173 farthen 579
        self.logger.info("Starting emBIOS app at "+self._hex(addr)+"\n")
172 farthen 580
        self.embios.execimage(addr)
176 farthen 581
 
171 farthen 582
    @command
176 farthen 583
    def flushcaches(self):
171 farthen 584
        """
176 farthen 585
            Flushes the CPUs data and instruction caches.
586
        """
587
        self.logger.info("Flushing CPU data and instruction caches...")
588
        self.embios.flushcaches()
589
        self.logger.info("done\n")
590
 
591
    @command
592
    def readbootflash(self, addr_flash, addr_mem, size):
593
        """
171 farthen 594
            Reads <size> bytes from bootflash to memory.
595
            <addr_bootflsh>: the address in bootflash to read from
596
            <addr_mem>: the address in memory to copy the data to
597
        """
598
        addr_flash = self._hexint(addr_flash)
599
        addr_mem = self._hexint(addr_mem)
600
        size = self._hexint(size)
174 farthen 601
        self.logger.info("Dumping boot flash addresses "+self._hex(addr_flash)+" - "+
602
                         hex(addr_flash+size)+" to "+self._hex(addr_mem)+" - "+self._hex(addr_mem+size)+"\n")
276 theseven 603
        self.embios.lib.dev.timeout = 5000
604
        self.embios.bootflashread(addr_mem, addr_flash, size)
176 farthen 605
 
171 farthen 606
    @command
176 farthen 607
    def writebootflash(self, addr_flash, addr_mem, size, force=False):
171 farthen 608
        """
609
            Writes <size> bytes from memory to bootflash.
610
            ATTENTION: Don't call this unless you really know what you're doing!
611
            This may BRICK your device (unless it has a good recovery option)
612
            <addr_mem>: the address in memory to copy the data from
613
            <addr_bootflsh>: the address in bootflash to write to
174 farthen 614
            <force>: Use this flag to suppress the 5 seconds delay
171 farthen 615
        """
616
        addr_flash = self._hexint(addr_flash)
617
        addr_mem = self._hexint(addr_mem)
618
        size = self._hexint(size)
174 farthen 619
        force = self._bool(force)
620
        self.logger.info("Writing boot flash from the memory in "+self._hex(addr_mem)+" - "+
621
                         hex(addr_mem+size)+" to "+self._hex(addr_flash)+" - "+self._hex(addr_flash+size)+"\n")
622
        if force == False:
623
            self.logger.info("If this was not what you intended press Ctrl-C NOW")
176 farthen 624
            for i in range(10):
174 farthen 625
                self.logger.info(".")
626
                time.sleep(1)
627
            self.logger.info("\n")
276 theseven 628
        self.embios.lib.dev.timeout = 30000
629
        self.embios.bootflashwrite(addr_mem, addr_flash, size)
176 farthen 630
 
171 farthen 631
    @command
176 farthen 632
    def runfirmware(self, addr, filename):
171 farthen 633
        """
176 farthen 634
            Uploads the firmware in 'filename' to the beginning of the
635
            user memory and executes it
171 farthen 636
        """
176 farthen 637
        addr = self._hexint(addr)
638
        self.uploadfile(addr, filename)
639
        self.execfirmware(addr)
64 benedikt93 640
 
171 farthen 641
    @command
176 farthen 642
    def execfirmware(self, addr):
643
        """
644
            Executes the firmware at addr
645
        """
646
        addr = self._hexint(addr)
647
        self.logger.info("Running firmware at "+self._hex(addr)+". Bye.")
648
        self.embios.execfirmware(addr)
649
 
650
    @command
171 farthen 651
    def aesencrypt(self, addr, size, keyindex):
652
        """
172 farthen 653
            Encrypts a buffer using a hardware key
171 farthen 654
        """
655
        addr = self._hexint(addr)
656
        size = self._hexint(size)
657
        keyindex = self._hexint(keyindex)
658
        self.embios.aesencrypt(addr, size, keyindex)
82 benedikt93 659
 
171 farthen 660
    @command
661
    def aesdecrypt(self, addr, size, keyindex):
662
        """
172 farthen 663
            Decrypts a buffer using a hardware key
171 farthen 664
        """
665
        addr = self._hexint(addr)
666
        size = self._hexint(size)
667
        keyindex = self._hexint(keyindex)
668
        self.embios.aesdecrypt(addr, size, keyindex)
172 farthen 669
 
670
    @command
671
    def hmac_sha1(self, addr, size, destination):
672
        """
673
            Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination'
674
        """
675
        addr = self._hexint(addr)
676
        size = self._hexint(size)
677
        destination = self._hexint(destination)
678
        sha1size = 0x14
173 farthen 679
        self.logger.info("Generating hmac-sha1 hash from the buffer at "+self._hex(addr)+" with the size "+self._hex(size)+
680
                         " and saving it to "+self._hex(destination)+" - "+self._hex(destination+sha1size)+"...")
172 farthen 681
        self.embios.hmac_sha1(addr, size, destination)
682
        self.logger.info("done\n")
178 farthen 683
        data = self.embios.read(destination, sha1size)
172 farthen 684
        hash = ord(data)
173 farthen 685
        self.logger.info("The generated hash is "+self._hex(hash))
64 benedikt93 686
 
227 theseven 687
    @command
688
    def ipodnano2g_getnandinfo(self):
689
        """
690
            Target-specific function: ipodnano2g
691
            Gathers some information about the NAND chip used
692
        """
693
        data = self.embios.ipodnano2g_getnandinfo()
694
        self.logger.info("NAND chip type: "+self._hex(data["type"])+"\n")
695
        self.logger.info("Number of banks: "+str(data["banks"])+"\n")
696
        self.logger.info("Number of blocks: "+str(data["blocks"])+"\n")
697
        self.logger.info("Number of user blocks: "+str(data["userblocks"])+"\n")
698
        self.logger.info("Pages per block: "+str(data["pagesperblock"]))
699
 
700
    @command
701
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
702
        """
703
            Target-specific function: ipodnano2g
704
            Reads data from the NAND chip into memory
705
        """
706
        addr = self._hexint(addr)
707
        start = self._hexint(start)
708
        count = self._hexint(count)
709
        doecc = int(doecc)
710
        checkempty = int(checkempty)
711
        self.logger.info("Reading "+self._hex(count)+" NAND pages starting at "+self._hex(start)+" to "+self._hex(addr)+"...")
228 theseven 712
        self.embios.lib.dev.timeout = 30000
227 theseven 713
        self.embios.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
714
        self.logger.info("done\n")
715
 
716
    @command
717
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
718
        """
719
            Target-specific function: ipodnano2g
720
            Writes data to the NAND chip
721
        """
722
        addr = self._hexint(addr)
723
        start = self._hexint(start)
724
        count = self._hexint(count)
725
        doecc = int(doecc)
726
        self.logger.info("Writing "+self._hex(count)+" NAND pages starting at "+self._hex(start)+" from "+self._hex(addr)+"...")
228 theseven 727
        self.embios.lib.dev.timeout = 30000
227 theseven 728
        self.embios.ipodnano2g_nandwrite(addr, start, count, doecc)
729
        self.logger.info("done\n")
730
 
731
    @command
732
    def ipodnano2g_nanderase(self, addr, start, count):
733
        """
734
            Target-specific function: ipodnano2g
735
            Erases blocks on the NAND chip and stores the results to memory
736
        """
737
        addr = self._hexint(addr)
738
        start = self._hexint(start)
739
        count = self._hexint(count)
740
        self.logger.info("Erasing "+self._hex(count)+" NAND blocks starting at "+self._hex(start)+" and logging to "+self._hex(addr)+"...")
228 theseven 741
        self.embios.lib.dev.timeout = 30000
227 theseven 742
        self.embios.ipodnano2g_nanderase(addr, start, count)
743
        self.logger.info("done\n")
744
 
228 theseven 745
    @command
746
    def ipodnano2g_dumpnand(self, filenameprefix):
747
        """
748
            Target-specific function: ipodnano2g
749
            Dumps the whole NAND chip to four files
750
        """
751
        info = self.embios.ipodnano2g_getnandinfo()
752
        self.logger.info("Dumping NAND contents...")
753
        try:
754
            infofile = open(filenameprefix+"_info.txt", 'wb')
755
            datafile = open(filenameprefix+"_data.bin", 'wb')
756
            sparefile = open(filenameprefix+"_spare.bin", 'wb')
757
            statusfile = open(filenameprefix+"_status.bin", 'wb')
758
        except IOError:
759
            raise ArgumentError("Can not open file for writing!")
760
        infofile.write("NAND chip type: "+self._hex(info["type"])+"\r\n")
761
        infofile.write("Number of banks: "+str(info["banks"])+"\r\n")
762
        infofile.write("Number of blocks: "+str(info["blocks"])+"\r\n")
763
        infofile.write("Number of user blocks: "+str(info["userblocks"])+"\r\n")
764
        infofile.write("Pages per block: "+str(info["pagesperblock"])+"\r\n")
765
        self.embios.lib.dev.timeout = 30000
766
        for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
767
            self.logger.info(".")
768
            self.embios.ipodnano2g_nandread(0x08000000, i * 8192, 8192, 1, 1)
769
            datafile.write(self.embios.read(0x08000000, 0x01000000))
770
            sparefile.write(self.embios.read(0x09000000, 0x00080000))
771
            statusfile.write(self.embios.read(0x09080000, 0x00008000))
772
        infofile.close()
773
        datafile.close()
774
        sparefile.close()
775
        statusfile.close()
776
        self.logger.info("done\n")
777
 
778
    @command
779
    def ipodnano2g_wipenand(self, filename, force=False):
780
        """
781
            Target-specific function: ipodnano2g
782
            Wipes the whole NAND chip and logs the result to a file
783
            <force>: Use this flag to suppress the 5 seconds delay
784
        """
785
        self.logger.info("Wiping the whole NAND chip!\n")
786
        if force == False:
787
            self.logger.info("If this was not what you intended press Ctrl-C NOW")
788
            for i in range(10):
789
                self.logger.info(".")
790
                time.sleep(1)
791
            self.logger.info("\n")
792
        info = self.embios.ipodnano2g_getnandinfo()
793
        self.logger.info("Wiping NAND contents...")
794
        try:
795
            statusfile = open(filename, 'wb')
796
        except IOError:
797
            raise ArgumentError("Can not open file for writing!")
798
        self.embios.lib.dev.timeout = 30000
799
        for i in range(info["banks"] * info["blocks"] / 64):
800
            self.logger.info(".")
230 theseven 801
            self.embios.ipodnano2g_nanderase(0x08000000, i * 64, 64)
228 theseven 802
            statusfile.write(self.embios.read(0x08000000, 0x00000100))
803
        statusfile.close()
804
        self.logger.info("done\n")
805
 
171 farthen 806
if __name__ == "__main__":
807
    if len(sys.argv) < 2:
808
        usage("No command specified")
809
    interface = Commandline()
810
    interface._parsecommand(sys.argv[1], sys.argv[2:])