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
#
427 farthen 7
#    This file is part of emCORE.
64 benedikt93 8
#
427 farthen 9
#    emCORE 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
#
427 farthen 14
#    emCORE 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
427 farthen 20
#    along with emCORE.  If not, see <http://www.gnu.org/licenses/>.
64 benedikt93 21
#
787 theseven 22
#
64 benedikt93 23
 
402 farthen 24
"""
427 farthen 25
    Command line interface to communicate with emCORE devices.
402 farthen 26
    Run it without arguments to see usage information.
27
"""
28
 
171 farthen 29
import sys
30
import os
176 farthen 31
import time
215 theseven 32
import struct
346 theseven 33
import locale
64 benedikt93 34
 
176 farthen 35
from functools import wraps
36
 
427 farthen 37
import libemcore
38
import libemcoredata
532 farthen 39
from misc import Error, ArgumentError, ArgumentTypeError, Logger, getfuncdoc, gethwname, to_bool, to_int
64 benedikt93 40
 
236 farthen 41
 
444 farthen 42
def usage(errormsg=None, specific=False, docstring=True):
171 farthen 43
    """
44
        Prints the usage information.
45
        It is auto generated from various places.
46
    """
47
    logger = Logger()
396 farthen 48
    cmddict = Commandline.cmddict
49
    doc = getfuncdoc(cmddict)
171 farthen 50
    if not specific:
501 farthen 51
        logger.write("Please provide a command and (if needed) parameters as command line arguments\n\n")
52
        logger.write("Available commands:\n\n")
82 benedikt93 53
    else:
501 farthen 54
        logger.write("\n")
171 farthen 55
    for function in sorted(doc.items()):
56
        function = function[0]
57
        if specific == False or specific == function:
501 farthen 58
            logger.write(function + " ", 2)
171 farthen 59
            for arg in doc[function]['args']:
501 farthen 60
                logger.write("<" + arg + "> ")
171 farthen 61
            if doc[function]['kwargs']:
579 farthen 62
                for kwarg, kwvalue in doc[function]['kwargs']:
501 farthen 63
                    logger.write("[" + kwarg + " = " + str(kwvalue) + "] ")
171 farthen 64
            if doc[function]['varargs']:
501 farthen 65
                logger.write("<db1> ... <dbN>")
444 farthen 66
            if docstring and doc[function]['documentation']:
501 farthen 67
                logger.write("\n")
68
                logger.write(doc[function]['documentation']+"\n", 4)
69
            logger.write("\n")
70
    logger.write("\n")
517 farthen 71
 
171 farthen 72
    if errormsg:
73
        logger.error(str(errormsg)+"\n")
74
    exit(2)
75
 
76
 
77
def command(func):
78
    """
79
        Decorator for all commands.
80
        The decorated function is called with (self, all, other, arguments, ...)
81
    """
176 farthen 82
    @wraps(func)
172 farthen 83
    def decorator(*args):
171 farthen 84
        return func(args[0], *args[1:])
85
    func._command = True
86
    decorator.func = func
87
    return decorator
88
 
89
 
90
def commandClass(cls):
91
    """
92
        Decorator for the class. Sets the self.cmddict of the class
93
        to all functions decorated with @command
94
    """
95
    cls.cmddict = {}
582 farthen 96
    for attr, value in cls.__dict__.items():
171 farthen 97
        if getattr(value, 'func', False):
98
            if getattr(value.func, '_command', False):
99
                cls.cmddict[value.func.__name__] = value
100
    return cls
101
 
102
 
103
@commandClass
104
class Commandline(object):
105
    """
106
        If you want to create a new commandline function you just need to
107
        create a function with the name of it in this class and decorate
108
        it with the decorator @command. If you don't want to call the desired
109
        function (wrong arguments etc) just raise ArgumentError with or
341 farthen 110
        without an error message.
171 farthen 111
    """
112
    def __init__(self):
113
        self.logger = Logger()
114
        try:
499 farthen 115
            self.emcore = libemcore.Emcore(logger = self.logger)
427 farthen 116
        except libemcore.DeviceNotFoundError:
478 farthen 117
            self.logger.error("No emCORE device found!\n")
176 farthen 118
            exit(1)
119
        self.getinfo("version")
517 farthen 120
 
171 farthen 121
    def _parsecommand(self, func, args):
122
        # adds self to the commandline args.
123
        # this is needed because the functions need access to their class.
124
        args.insert(0, self)
125
        if func in self.cmddict:
126
            try:
172 farthen 127
                self.cmddict[func](*args)
582 farthen 128
            except (ArgumentError, libemcore.ArgumentError) as e:
176 farthen 129
                usage(e, specific=func)
427 farthen 130
            except (ArgumentError, libemcore.ArgumentError):
176 farthen 131
                usage("Syntax Error in function '" + func + "'", specific=func)
582 farthen 132
            except ArgumentTypeError as e:
176 farthen 133
                usage(e, specific=func)
171 farthen 134
            except NotImplementedError:
478 farthen 135
                self.logger.error("This function is not implemented yet!\n")
582 farthen 136
            except libemcore.DeviceError as e:
478 farthen 137
                self.logger.error(str(e) + "\n")
582 farthen 138
            except TypeError as e:
341 farthen 139
                # Only act on TypeErrors for the function we called, not on TypeErrors raised by another function.
171 farthen 140
                if str(e).split(" ", 1)[0] == func + "()":
516 farthen 141
                    self.logger.error(usage("Argument Error in '%s': Wrong argument count" % func, specific=func))
171 farthen 142
                else:
143
                    raise
427 farthen 144
            except libemcore.usb.core.USBError:
478 farthen 145
                self.logger.error("There is a problem with the USB connection.\n")
171 farthen 146
        else:
502 farthen 147
            usage("No such command!", docstring = False)
532 farthen 148
 
67 benedikt93 149
 
171 farthen 150
    @command
444 farthen 151
    def help(self):
502 farthen 152
        """ Displays this help """
153
        usage(docstring = True)
444 farthen 154
 
155
    @command
171 farthen 156
    def getinfo(self, infotype):
157
        """
427 farthen 158
            Get info on the running emCORE.
675 farthen 159
            <infotype> may be either of 'version', 'packetsize', 'mallocpoolbounds'.
171 farthen 160
        """
161
        if infotype == "version":
427 farthen 162
            hwtype = gethwname(self.emcore.lib.dev.hwtypeid)
516 farthen 163
            self.logger.info("Connected to %s v%d.%d.%d r%d running on %s\n" % (
164
                             libemcoredata.swtypes[self.emcore.lib.dev.swtypeid],
165
                             self.emcore.lib.dev.version.majorv,
166
                             self.emcore.lib.dev.version.minorv,
167
                             self.emcore.lib.dev.version.patchv,
168
                             self.emcore.lib.dev.version.revision,
169
                             hwtype))
343 farthen 170
 
171 farthen 171
        elif infotype == "packetsize":
516 farthen 172
            self.logger.info("Maximum packet sizes:\n")
173
            self.logger.info("command out: %d\n" % self.emcore.lib.dev.packetsizelimit.cout, 4)
174
            self.logger.info("command in: %d\n" % self.emcore.lib.dev.packetsizelimit.cin, 4)
175
            self.logger.info("data out: %d\n" % self.emcore.lib.dev.packetsizelimit.dout, 4)
176
            self.logger.info("data in: %d\n" % self.emcore.lib.dev.packetsizelimit.din, 4)
343 farthen 177
 
675 farthen 178
        elif infotype == "mallocpoolbounds":
179
            resp = self.emcore.getmallocpoolbounds()
180
            self.logger.info("The malloc pool is 0x%X - 0x%X" % (
181
                             self.emcore.lib.dev.mallocpool.lower,
182
                             self.emcore.lib.dev.mallocpool.upper - 1))
382 farthen 183
 
171 farthen 184
        else:
675 farthen 185
            raise ArgumentTypeError("one out of 'version', 'packetsize', 'mallocpoolbounds'", infotype)
64 benedikt93 186
 
171 farthen 187
    @command
188
    def reset(self, force=False):
189
        """
190
            Resets the device"
402 farthen 191
            If [force] is 1, the reset will be forced, otherwise it will be gracefully,
171 farthen 192
            which may take some time.
193
        """
532 farthen 194
        force = to_bool(force)
171 farthen 195
        if force: self.logger.info("Resetting forcefully...\n")
196
        else: self.logger.info("Resetting...\n")
427 farthen 197
        self.emcore.reset(force)
64 benedikt93 198
 
171 farthen 199
    @command
200
    def poweroff(self, force=False):
201
        """
202
            Powers the device off
402 farthen 203
            If [force] is 1, the poweroff will be forced, otherwise it will be gracefully,
171 farthen 204
            which may take some time.
205
        """
532 farthen 206
        force = to_bool(force)
281 farthen 207
        if force: self.logger.info("Powering off forcefully...\n")
208
        else: self.logger.info("Powering off...\n")
427 farthen 209
        self.emcore.poweroff(force)
64 benedikt93 210
 
171 farthen 211
    @command
442 farthen 212
    def uploadfile(self, filename, addr = None):
171 farthen 213
        """
214
            Uploads a file to the device
442 farthen 215
            <filename>: The path to the file
216
            [addr]: The address to upload the file to. Allocates a chunk of memory if not given.
171 farthen 217
        """
532 farthen 218
        addr = to_int(addr)
171 farthen 219
        try:
220
            f = open(filename, 'rb')
221
        except IOError:
222
            raise ArgumentError("File not readable. Does it exist?")
442 farthen 223
        if addr is not None:
516 farthen 224
            self.logger.info("Writing file '%s' to memory at 0x%X...\n" % (filename, addr))
442 farthen 225
        else:
516 farthen 226
            self.logger.info("Writing file '%s' to an allocated memory region...\n" % filename)
171 farthen 227
        with f:
442 farthen 228
            if addr is not None:
229
                self.emcore.write(addr, f.read())
230
            else:
231
                addr = self.emcore.upload(f.read())
232
            size = f.tell()
178 farthen 233
        f.close()
516 farthen 234
        self.logger.info("Done uploading %d bytes to 0x%X\n" % (size, addr))
442 farthen 235
        return addr, size
176 farthen 236
 
171 farthen 237
    @command
238
    def downloadfile(self, addr, size, filename):
239
        """
574 theseven 240
            Downloads a region of memory from the device to a file
241
            <addr>: the address to download the data from
171 farthen 242
            <size>: the number of bytes to be read
243
            <filename>: the path to the file
244
        """
532 farthen 245
        addr = to_int(addr)
246
        size = to_int(size)
171 farthen 247
        try:
248
            f = open(filename, 'wb')
249
        except IOError:
250
            raise ArgumentError("Can not open file for write!")
516 farthen 251
        self.logger.info("Reading data from address 0x%X with the size 0x%X to '%s'..." %
252
                        (addr, size, filename))
171 farthen 253
        with f:
427 farthen 254
            f.write(self.emcore.read(addr, size))
178 farthen 255
        f.close()
171 farthen 256
        self.logger.info("done\n")
517 farthen 257
 
171 farthen 258
    @command
578 theseven 259
    def hexdump(self, addr, size, width = 16, wordsize = 1, separate = 4, align = False, \
260
                relative = False, ascii = True, asciisep = 8, asciirep = ".", zeropad = True):
575 theseven 261
        """
262
            Downloads a region of memory from the device and hexdumps it
263
            <addr>: the address to download the data from
264
            <size>: the number of bytes to be dumped
265
            [width]: the number of words per output line
266
            [wordsize]: the number of bytes per word (little endian)
267
            [separate]: add an additional space character every [separate] words
268
            [align]: if true, output lines are aligned to the line size
269
            [relative]: if true, the addresses displayed are relative to the <addr>, not zero
270
            [ascii]: add ASCII representations of the bytes to the output
271
            [asciisep]: add an additional space character every [asciisep] ASCII characters
578 theseven 272
            [asciirep]: replacement character for non-printable ASCII characters
273
            [zeropad]: pad hex values with zero instead of space characters
575 theseven 274
        """
275
        addr = to_int(addr)
276
        size = to_int(size)
277
        width = to_int(width)
278
        wordsize = to_int(wordsize)
279
        separate = to_int(separate)
280
        align = to_bool(align)
281
        relative = to_bool(relative)
282
        ascii = to_bool(ascii)
283
        asciisep = to_int(asciisep)
578 theseven 284
        zeropad = to_bool(zeropad)
575 theseven 285
        if addr % wordsize != 0: raise ArgumentError("Address is not word aligned!")
286
        if size % wordsize != 0: raise ArgumentError("Size is not word aligned!")
287
        if align: skip = addr % (wordsize * width)
288
        else: skip = 0
289
        if relative: base = 0
290
        else: base = addr
291
        data = self.emcore.read(addr, size)
292
        for r in range(-skip, size, wordsize * width):
293
            sys.stdout.write("%08X:" % (base + r))
294
            for i in range(r, r + wordsize * width, wordsize):
295
                if i - r > 0 and (i - r) % (separate * wordsize) == 0: sys.stdout.write(" ")
296
                if i >= 0 and i < size:
297
                    w = 0
298
                    for b in range(wordsize):
577 theseven 299
                        w = w | (struct.unpack("B", data[i + b])[0] << (8 * b))
578 theseven 300
                    sys.stdout.write(((" %%0%dX" if zeropad else " %%%dX") % (wordsize * 2)) % w)
575 theseven 301
                else: sys.stdout.write(" " * (wordsize * 2 + 1))
302
            if ascii:
303
                sys.stdout.write(" |")
304
                for i in range(r, r + wordsize * width):
305
                    if i - r > 0 and (i - r) % asciisep == 0: sys.stdout.write(" ")
306
                    if i >= 0 and i < size:
307
                        if ord(data[i]) > 0x1f: sys.stdout.write(data[i])
578 theseven 308
                        else: sys.stdout.write(asciirep)
575 theseven 309
                    else: sys.stdout.write(" ")
310
                sys.stdout.write("|")
311
            sys.stdout.write("\n")
312
 
313
    @command
774 theseven 314
    def uploadbyte(self, addr, byte):
315
        """
316
            Uploads a single byte to the device
317
            <addr>: the address to upload the byte to
318
            <byte>: the byte to upload
319
        """
320
        addr = to_int(addr)
321
        byte = to_int(byte)
322
        if byte > 0xFF:
323
            raise ArgumentError("Specified integer too long")
324
        data = struct.pack("B", byte)
325
        self.emcore.write(addr, data)
326
        self.logger.info("Byte '0x%X' written successfully to 0x%X\n" % (byte, addr))
327
 
328
    @command
329
    def downloadbyte(self, addr):
330
        """
331
            Downloads a single byte from the device and prints it to the console window
332
            <addr>: the address to download the byte from
333
        """
334
        addr = to_int(addr)
335
        data = self.emcore.read(addr, 1)
336
        byte = struct.unpack("B", data)[0]
337
        self.logger.info("Read '0x%X' from address 0x%X\n" % (byte, addr))
338
 
339
    @command
171 farthen 340
    def uploadint(self, addr, integer):
341
        """
342
            Uploads a single integer to the device
260 theseven 343
            <addr>: the address to upload the integer to
344
            <integer>: the integer to upload
171 farthen 345
        """
532 farthen 346
        addr = to_int(addr)
347
        integer = to_int(integer)
171 farthen 348
        if integer > 0xFFFFFFFF:
349
            raise ArgumentError("Specified integer too long")
548 farthen 350
        data = struct.pack("<I", integer)
427 farthen 351
        self.emcore.write(addr, data)
516 farthen 352
        self.logger.info("Integer '0x%X' written successfully to 0x%X\n" % (integer, addr))
517 farthen 353
 
171 farthen 354
    @command
355
    def downloadint(self, addr):
356
        """
357
            Downloads a single integer from the device and prints it to the console window
236 farthen 358
            <addr>: the address to download the integer from
171 farthen 359
        """
532 farthen 360
        addr = to_int(addr)
427 farthen 361
        data = self.emcore.read(addr, 4)
548 farthen 362
        integer = struct.unpack("<I", data)[0]
516 farthen 363
        self.logger.info("Read '0x%X' from address 0x%X\n" % (integer, addr))
517 farthen 364
 
171 farthen 365
    @command
176 farthen 366
    def i2cread(self, bus, slave, addr, size):
171 farthen 367
        """
368
            Reads data from an I2C device
402 farthen 369
            <bus>: the bus index
370
            <slave>: the slave address
371
            <addr>: the start address on the I2C device
372
            <size>: the number of bytes to read
171 farthen 373
        """
532 farthen 374
        bus = to_int(bus)
375
        slave = to_int(slave)
376
        addr = to_int(addr)
377
        size = to_int(size)
427 farthen 378
        data = self.emcore.i2cread(bus, slave, addr, size)
548 farthen 379
        bytes = struct.unpack("<%dB" % len(data), data)
236 farthen 380
        self.logger.info("Data read from I2C:\n")
381
        for index, byte in enumerate(bytes):
533 theseven 382
            self.logger.info("%02X: %02X\n" % (addr + index, byte))
517 farthen 383
 
171 farthen 384
    @command
176 farthen 385
    def i2cwrite(self, bus, slave, addr, *args):
171 farthen 386
        """
387
            Writes data to an I2C device
402 farthen 388
            <bus>: the bus index
389
            <slave>: the slave address
390
            <addr>: the start address on the I2C device
532 farthen 391
            <db1> ... <dbN>: the data in single bytes,
236 farthen 392
                seperated by whitespaces, eg. 37 5A 4F EB
171 farthen 393
        """
532 farthen 394
        bus = to_int(bus)
395
        slave = to_int(slave)
396
        addr = to_int(addr)
176 farthen 397
        data = ""
171 farthen 398
        for arg in args:
532 farthen 399
            data += chr(to_int(arg))
236 farthen 400
        self.logger.info("Writing data to I2C...\n")
427 farthen 401
        self.emcore.i2cwrite(bus, slave, addr, data)
236 farthen 402
        self.logger.info("done\n")
517 farthen 403
 
171 farthen 404
    @command
176 farthen 405
    def console(self):
171 farthen 406
        """
176 farthen 407
            Reads data from the USB console continuously
171 farthen 408
        """
176 farthen 409
        while True:
427 farthen 410
            resp = self.emcore.usbcread()
599 farthen 411
            self.logger.write(resp.data, target = "stdout")
774 theseven 412
#            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
517 farthen 413
 
171 farthen 414
    @command
176 farthen 415
    def writeusbconsole(self, *args):
171 farthen 416
        """
176 farthen 417
            Writes the string <db1> ... <dbN> to the USB console.
171 farthen 418
        """
176 farthen 419
        text = ""
420
        for word in args:
421
            text += word + " "
422
        text = text[:-1]
516 farthen 423
        self.logger.info("Writing '%s' to the usb console\n" % text)
427 farthen 424
        self.emcore.usbcwrite(text)
517 farthen 425
 
171 farthen 426
    @command
176 farthen 427
    def readdevconsole(self, bitmask):
171 farthen 428
        """
176 farthen 429
            Reads data continuously from one or more of the device's consoles.
430
            <bitmask>: the bitmask of the consoles to read from.
171 farthen 431
        """
532 farthen 432
        bitmask = to_int(bitmask)
176 farthen 433
        while True:
427 farthen 434
            resp = self.emcore.cread()
501 farthen 435
            self.logger.write(resp.data)
176 farthen 436
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
437
 
171 farthen 438
    @command
176 farthen 439
    def writedevconsole(self, bitmask, *args):
171 farthen 440
        """
176 farthen 441
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
442
            <bitmask>: the bitmask of the consoles to write to
171 farthen 443
        """
532 farthen 444
        bitmask = to_int(bitmask)
176 farthen 445
        text = ""
446
        for word in args:
447
            text += word + " "
448
        text = text[:-1]
516 farthen 449
        self.logger.info("Writing '%s' to the device consoles identified with 0x%X\n" % (text, bitmask))
427 farthen 450
        self.emcore.cwrite(text, bitmask)
517 farthen 451
 
171 farthen 452
    @command
453
    def flushconsolebuffers(self, bitmask):
454
        """
455
            flushes one or more of the device consoles' buffers.
456
            <bitmask>: the bitmask of the consoles to be flushed
457
        """
532 farthen 458
        bitmask = to_int(bitmask)
516 farthen 459
        self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
427 farthen 460
        self.emcore.cflush(bitmask)
517 farthen 461
 
171 farthen 462
    @command
463
    def getprocinfo(self):
464
        """
465
            Fetches data on the currently running processes
466
        """
173 farthen 467
        import datetime
427 farthen 468
        threads = self.emcore.getprocinfo()
382 farthen 469
        threadload = 0
470
        idleload = 0
173 farthen 471
        for thread in threads:
392 theseven 472
            if thread.id != 0:
473
                threadload += thread.cpuload / 255.
382 farthen 474
            else:
392 theseven 475
                idleload += thread.cpuload / 255.
382 farthen 476
        coreload = 1 - (threadload + idleload)
477
        cpuload = threadload + coreload
392 theseven 478
        self.logger.info("Threads: %d, CPU load: %.1f%%, kernel load: %.1f%%, user load: %.1f%%\n\n"
479
                         % (len(threads), cpuload * 100, coreload * 100, threadload * 100))
382 farthen 480
        self.logger.info("Thread dump:\n")
481
        for thread in threads:
516 farthen 482
            self.logger.info("%s:\n" % thread.name, 2)
483
            self.logger.info("Threadstruct address: 0x%X\n" % thread.addr, 4)
484
            self.logger.info("Thread type: %s\n" % thread.thread_type, 4)
485
            self.logger.info("Thread state: %s\n" % thread.state, 4)
605 farthen 486
            if thread.block_type != "THREAD_NOT_BLOCKED":
609 farthen 487
                self.logger.info("Block type: %s\n" % thread.block_type, 4)
488
                if thread.block_type == "THREAD_BLOCK_MUTEX":
489
                    self.logger.info("Blocked by mutex: 0x%X\n" % thread.blocked_by, 6)
490
                    self.logger.info("Owner: %s (0x%X)\n" % (thread.blocked_by.owner.name, thread.blocked_by.owner), 8)
491
                elif thread.block_type == "THREAD_BLOCK_WAKEUP":
492
                    self.logger.info("Blocked by wakeup: 0x%X\n" % thread.blocked_by, 6)
516 farthen 493
            self.logger.info("Priority: %d/255\n" % thread.priority, 4)
396 farthen 494
            self.logger.info("Current CPU load: %.1f%%\n" % ((thread.cpuload * 100) / 255.), 4)
516 farthen 495
            self.logger.info("CPU time (total): %s\n" % datetime.timedelta(microseconds = thread.cputime_total), 4)
496
            self.logger.info("Stack address: 0x%X\n" % thread.stack, 4)
396 farthen 497
            self.logger.info("Registers:\n", 4)
177 farthen 498
            for registerrange in range(4):
499
                for register in range(registerrange, 16, 4):
500
                    registerrepr = "r"+str(register)
606 farthen 501
                    self.logger.info("{0:>3s}: 0x{1:08X}   ".format(registerrepr, thread.regs[register]), 5)
177 farthen 502
                self.logger.info("\n")
506 farthen 503
            self.logger.info("cpsr: 0x{0:08X}".format(thread.cpsr), 6)
173 farthen 504
            self.logger.info("\n")
505
 
171 farthen 506
    @command
507
    def lockscheduler(self):
508
        """
509
            Locks (freezes) the scheduler
510
        """
176 farthen 511
        self.logger.info("Will now lock scheduler\n")
427 farthen 512
        self.emcore.lockscheduler()
178 farthen 513
 
171 farthen 514
    @command
515
    def unlockscheduler(self):
516
        """
517
            Unlocks (unfreezes) the scheduler
518
        """
176 farthen 519
        self.logger.info("Will now unlock scheduler\n")
427 farthen 520
        self.emcore.unlockscheduler()
178 farthen 521
 
171 farthen 522
    @command
516 farthen 523
    def suspendthread(self, threadaddr):
171 farthen 524
        """
516 farthen 525
            Suspends the thread with the thread address <threadaddr>
171 farthen 526
        """
532 farthen 527
        threadaddr = to_int(threadaddr)
516 farthen 528
        self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
529
        self.emcore.suspendthread(threadaddr)
517 farthen 530
 
171 farthen 531
    @command
516 farthen 532
    def resumethread(self, threadaddr):
171 farthen 533
        """
516 farthen 534
            Resumes the thread with the thread address <threadaddr>
171 farthen 535
        """
532 farthen 536
        threadaddr = to_int(threadaddr)
516 farthen 537
        self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
538
        self.emcore.resumethread(threadaddr)
517 farthen 539
 
171 farthen 540
    @command
516 farthen 541
    def killthread(self, threadaddr):
171 farthen 542
        """
516 farthen 543
            Kills the thread with the thread address <threadaddr>
171 farthen 544
        """
532 farthen 545
        threadaddr = to_int(threadaddr)
516 farthen 546
        self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
547
        self.emcore.killthread(threadaddr)
517 farthen 548
 
171 farthen 549
    @command
550
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
551
        """
516 farthen 552
            Creates a new thread and returns its thread pointer
402 farthen 553
            <namepointer>: a pointer to the thread's name
554
            <entrypoint>: a pointer to the entrypoint of the thread
555
            <stackpointer>: a pointer to the stack of the thread
556
            <stacksize>: the size of the thread's stack
516 farthen 557
            <threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
402 farthen 558
            <priority>: the priority of the thread, from 1 to 255
559
            <state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
171 farthen 560
        """
532 farthen 561
        nameptr = to_int(nameptr)
562
        entrypoint = to_int(entrypoint)
563
        stackptr = to_int(stackptr)
564
        stacksize = to_int(stacksize)
565
        priority = to_int(priority)
516 farthen 566
        data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
427 farthen 567
        name = self.emcore.readstring(nameptr)
516 farthen 568
        self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
569
                         "the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
570
                        (data.threadptr, name, entrypoint, stackptr, stacksize, priority))
172 farthen 571
 
572
    @command
573
    def run(self, filename):
574
        """
427 farthen 575
            Uploads the emCORE application <filename> to
236 farthen 576
            the memory and executes it
172 farthen 577
        """
236 farthen 578
        try:
579
            f = open(filename, 'rb')
580
        except IOError:
581
            raise ArgumentError("File not readable. Does it exist?")
238 farthen 582
        with f:
427 farthen 583
            data = self.emcore.run(f.read())
516 farthen 584
        self.logger.info("Executed emCORE application as thread 0x%X\n" % data.thread)
517 farthen 585
 
171 farthen 586
    @command
173 farthen 587
    def execimage(self, addr):
171 farthen 588
        """
427 farthen 589
            Executes the emCORE application at <addr>.
171 farthen 590
        """
532 farthen 591
        addr = to_int(addr)
516 farthen 592
        self.logger.info("Starting emCORE app at 0x%X\n" % addr)
427 farthen 593
        self.emcore.execimage(addr)
176 farthen 594
 
171 farthen 595
    @command
176 farthen 596
    def flushcaches(self):
171 farthen 597
        """
176 farthen 598
            Flushes the CPUs data and instruction caches.
599
        """
600
        self.logger.info("Flushing CPU data and instruction caches...")
427 farthen 601
        self.emcore.flushcaches()
176 farthen 602
        self.logger.info("done\n")
603
 
604
    @command
605
    def readbootflash(self, addr_flash, addr_mem, size):
606
        """
171 farthen 607
            Reads <size> bytes from bootflash to memory.
608
            <addr_bootflsh>: the address in bootflash to read from
609
            <addr_mem>: the address in memory to copy the data to
610
        """
532 farthen 611
        addr_flash = to_int(addr_flash)
612
        addr_mem = to_int(addr_mem)
613
        size = to_int(size)
516 farthen 614
        self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
615
                        (addr_flash, addr_flash + size, addr_mem, addr_mem + size))
427 farthen 616
        self.emcore.bootflashread(addr_mem, addr_flash, size)
176 farthen 617
 
171 farthen 618
    @command
176 farthen 619
    def writebootflash(self, addr_flash, addr_mem, size, force=False):
171 farthen 620
        """
621
            Writes <size> bytes from memory to bootflash.
622
            ATTENTION: Don't call this unless you really know what you're doing!
623
            This may BRICK your device (unless it has a good recovery option)
624
            <addr_mem>: the address in memory to copy the data from
625
            <addr_bootflsh>: the address in bootflash to write to
775 theseven 626
            [force]: Use this flag to suppress the 10 seconds delay
171 farthen 627
        """
532 farthen 628
        addr_flash = to_int(addr_flash)
629
        addr_mem = to_int(addr_mem)
630
        size = to_int(size)
631
        force = to_bool(force)
516 farthen 632
        self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
633
                        (addr_mem, addr_mem + size, addr_flash, addr_flash + size))
174 farthen 634
        if force == False:
382 farthen 635
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
176 farthen 636
            for i in range(10):
174 farthen 637
                self.logger.info(".")
638
                time.sleep(1)
639
            self.logger.info("\n")
427 farthen 640
        self.emcore.bootflashwrite(addr_mem, addr_flash, size)
176 farthen 641
 
171 farthen 642
    @command
442 farthen 643
    def runfirmware(self, targetaddr, filename):
171 farthen 644
        """
402 farthen 645
            Uploads the firmware in <filename>
442 farthen 646
            to an allocated buffer and executes it at <targetaddr>.
171 farthen 647
        """
532 farthen 648
        targetaddr = to_int(targetaddr)
442 farthen 649
        addr, size = self.uploadfile(filename)
650
        self.execfirmware(targetaddr, addr, size)
64 benedikt93 651
 
171 farthen 652
    @command
442 farthen 653
    def execfirmware(self, targetaddr, addr, size):
176 farthen 654
        """
442 farthen 655
            Moves the firmware at <addr> with <size> to <targetaddr> and executes it
176 farthen 656
        """
532 farthen 657
        targetaddr = to_int(targetaddr)
658
        addr = to_int(addr)
536 farthen 659
        size = to_int(size)
660
        self.logger.info("Running firmware at 0x%X. Bye.\n" % targetaddr)
442 farthen 661
        self.emcore.execfirmware(targetaddr, addr, size)
176 farthen 662
 
663
    @command
171 farthen 664
    def aesencrypt(self, addr, size, keyindex):
665
        """
172 farthen 666
            Encrypts a buffer using a hardware key
402 farthen 667
            <addr>: the starting address of the buffer
668
            <size>: the size of the buffer
669
            <keyindex>: the index of the key in the crypto unit
171 farthen 670
        """
532 farthen 671
        addr = to_int(addr)
672
        size = to_int(size)
673
        keyindex = to_int(keyindex)
427 farthen 674
        self.emcore.aesencrypt(addr, size, keyindex)
82 benedikt93 675
 
171 farthen 676
    @command
677
    def aesdecrypt(self, addr, size, keyindex):
678
        """
172 farthen 679
            Decrypts a buffer using a hardware key
402 farthen 680
            <addr>: the starting address of the buffer
681
            <size>: the size of the buffer
682
            <keyindex>: the index of the key in the crypto unit
171 farthen 683
        """
532 farthen 684
        addr = to_int(addr)
685
        size = to_int(size)
686
        keyindex = to_int(keyindex)
427 farthen 687
        self.emcore.aesdecrypt(addr, size, keyindex)
172 farthen 688
 
689
    @command
690
    def hmac_sha1(self, addr, size, destination):
691
        """
402 farthen 692
            Generates a HMAC-SHA1 hash of the buffer
693
            <addr>: the starting address of the buffer
694
            <size>: the size of the buffer
695
            <destination>: the location where the key will be stored
172 farthen 696
        """
532 farthen 697
        addr = to_int(addr)
698
        size = to_int(size)
699
        destination = to_int(destination)
172 farthen 700
        sha1size = 0x14
516 farthen 701
        self.logger.info("Generating hmac-sha1 hash from the buffer at 0x%X with the size 0x%X and saving it to 0x%X - 0x%X\n" %
702
                        (addr, size, destination, destination + sha1size))
427 farthen 703
        self.emcore.hmac_sha1(addr, size, destination)
172 farthen 704
        self.logger.info("done\n")
427 farthen 705
        data = self.emcore.read(destination, sha1size)
172 farthen 706
        hash = ord(data)
516 farthen 707
        self.logger.info("The generated hash is 0x%X\n" % hash)
517 farthen 708
 
227 theseven 709
    @command
710
    def ipodnano2g_getnandinfo(self):
711
        """
712
            Target-specific function: ipodnano2g
713
            Gathers some information about the NAND chip used
714
        """
427 farthen 715
        data = self.emcore.ipodnano2g_getnandinfo()
516 farthen 716
        self.logger.info("NAND chip type: 0x%X\n" % data["type"])
717
        self.logger.info("Number of banks: %d\n" % data["banks"])
718
        self.logger.info("Number of blocks: %d\n" % data["blocks"])
719
        self.logger.info("Number of user blocks: %d\n" % data["userblocks"])
720
        self.logger.info("Pages per block: %d\n" % data["pagesperblock"])
517 farthen 721
 
227 theseven 722
    @command
404 farthen 723
    def ipodnano2g_nandread(self, addr, start, count, doecc=True, checkempty=True):
227 theseven 724
        """
725
            Target-specific function: ipodnano2g
726
            Reads data from the NAND chip into memory
402 farthen 727
            <addr>: the memory location where the data is written to
728
            <start>: start block
729
            <count>: block count
404 farthen 730
            [doecc]: use ecc error correction data
731
            [checkempty]: set statusflags if pages are empty
227 theseven 732
        """
532 farthen 733
        addr = to_int(addr)
734
        start = to_int(start)
735
        count = to_int(count)
736
        doecc = to_bool(doecc)
737
        checkempty = to_bool(checkempty)
516 farthen 738
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
739
                        (count, start, addr))
427 farthen 740
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
227 theseven 741
        self.logger.info("done\n")
517 farthen 742
 
227 theseven 743
    @command
404 farthen 744
    def ipodnano2g_nandwrite(self, addr, start, count, doecc=True):
227 theseven 745
        """
746
            Target-specific function: ipodnano2g
747
            Writes data to the NAND chip
402 farthen 748
            <addr>: the memory location where the data is read from
749
            <start>: start block
750
            <count>: block count
404 farthen 751
            [doecc]: create ecc error correction data
227 theseven 752
        """
532 farthen 753
        addr = to_int(addr)
754
        start = to_int(start)
755
        count = to_int(count)
756
        doecc = to_bool(doecc)
516 farthen 757
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
758
                        (count, start, addr))
427 farthen 759
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
227 theseven 760
        self.logger.info("done\n")
517 farthen 761
 
227 theseven 762
    @command
763
    def ipodnano2g_nanderase(self, addr, start, count):
764
        """
765
            Target-specific function: ipodnano2g
766
            Erases blocks on the NAND chip and stores the results to memory
402 farthen 767
            <addr>: the memory location where the results are stored
768
            <start>: start block
769
            <count>: block count
227 theseven 770
        """
532 farthen 771
        addr = to_int(addr)
772
        start = to_int(start)
773
        count = to_int(count)
516 farthen 774
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
775
                        (count, start, addr))
427 farthen 776
        self.emcore.ipodnano2g_nanderase(addr, start, count)
227 theseven 777
        self.logger.info("done\n")
517 farthen 778
 
228 theseven 779
    @command
780
    def ipodnano2g_dumpnand(self, filenameprefix):
781
        """
782
            Target-specific function: ipodnano2g
783
            Dumps the whole NAND chip to four files
402 farthen 784
            <filenameprefix>: prefix of the files that will be created
228 theseven 785
        """
427 farthen 786
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 787
        try:
775 theseven 788
            buf = self.emcore.memalign(0x10, 0x1088000)
789
            self.logger.info("Dumping NAND contents...")
790
            try:
791
                infofile = open(filenameprefix+"_info.txt", 'wb')
792
                datafile = open(filenameprefix+"_data.bin", 'wb')
793
                sparefile = open(filenameprefix+"_spare.bin", 'wb')
794
                statusfile = open(filenameprefix+"_status.bin", 'wb')
795
            except IOError:
796
                raise ArgumentError("Can not open file for writing!")
797
            infofile.write("NAND chip type: 0x%X\r\n" % info["type"])
798
            infofile.write("Number of banks: %d\r\n" % info["banks"])
799
            infofile.write("Number of blocks: %d\r\n" % info["blocks"])
800
            infofile.write("Number of user blocks: %d\r\n" % info["userblocks"])
801
            infofile.write("Pages per block: %d\r\n" % info["pagesperblock"])
802
            for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
803
                self.logger.info(".")
804
                self.emcore.ipodnano2g_nandread(buf, i * 8192, 8192, 1, 1)
805
                datafile.write(self.emcore.read(buf, 0x01000000))
806
                sparefile.write(self.emcore.read(buf + 0x01000000, 0x00080000))
807
                statusfile.write(self.emcore.read(buf + 0x01080000, 0x00008000))
808
            infofile.close()
809
            datafile.close()
810
            sparefile.close()
811
            statusfile.close()
812
            self.logger.info("done\n")
813
        finally:
814
            self.emcore.free(buf)
815
 
816
    @command
817
    def ipodnano2g_restorenand(self, filenameprefix, force=False):
818
        """
819
            Target-specific function: ipodnano2g
820
            Restores the whole NAND chip from <filenameprefix>_data.bin and <filenameprefix>_spare.bin
821
            [force]: use this flag to suppress the 10 seconds delay
822
        """
823
        self.logger.warn("Flashing NAND image %s!\n" % filenameprefix)
824
        if force == False:
825
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
826
            for i in range(10):
827
                self.logger.info(".")
828
                time.sleep(1)
829
            self.logger.info("\n\n")
830
        info = self.emcore.ipodnano2g_getnandinfo()
831
        ppb = info["pagesperblock"]
832
        banks = info["banks"]
833
        blocks = info["blocks"]
834
        try:
835
            if (os.path.getsize(filenameprefix+"_data.bin") != blocks * banks * ppb * 2048):
836
                raise ArgumentError("Data file size does not match flash size!")
837
            if (os.path.getsize(filenameprefix+"_spare.bin") != blocks * banks * ppb * 64):
838
                raise ArgumentError("Spare file size does not match flash size!")
839
            datafile = open(filenameprefix+"_data.bin", 'rb')
840
            sparefile = open(filenameprefix+"_spare.bin", 'rb')
228 theseven 841
        except IOError:
775 theseven 842
            raise ArgumentError("Can not open input files!")
843
        try:
776 theseven 844
            buf = self.emcore.memalign(0x10, 0x844)
775 theseven 845
            for block in range(info["blocks"]):
846
                for bank in range(info["banks"]):
776 theseven 847
                    self.logger.info("\r    Erasing block %d bank %d         " % (block, bank))
775 theseven 848
                    self.emcore.ipodnano2g_nanderase(buf, block * banks + bank, 1)
849
                    rc = struct.unpack("<I", self.emcore.read(buf, 4))[0]
850
                    if rc != 0: self.logger.info("\rBlock %d bank %d erase failed with RC %08X\n" % (block, bank, rc))
851
                for page in range(ppb):
776 theseven 852
                    for bank in range(banks):
853
                        data = datafile.read(2048) + sparefile.read(64)
854
                        if data == "\xff" * 2112: continue
855
                        self.emcore.write(buf, data)
856
                        self.logger.info("\rProgramming block %d page %d bank %d" % (block, page, bank))
857
                        self.emcore.ipodnano2g_nandwrite(buf, ((block * ppb) + page) * banks + bank, 1, 0)
858
                        rc = struct.unpack("<I", self.emcore.read(buf + 2112, 4))[0]
859
                        if rc != 0: self.logger.info("\rBlock %d bank %d page %d programming failed with RC %08X\n" % (block, bank, page, rc))
775 theseven 860
        finally:
861
            self.emcore.free(buf)
228 theseven 862
        datafile.close()
863
        sparefile.close()
776 theseven 864
        self.logger.info("\ndone\n")
517 farthen 865
 
228 theseven 866
    @command
867
    def ipodnano2g_wipenand(self, filename, force=False):
868
        """
869
            Target-specific function: ipodnano2g
870
            Wipes the whole NAND chip and logs the result to a file
402 farthen 871
            <filename>: location of the log file
775 theseven 872
            [force]: use this flag to suppress the 10 seconds delay
228 theseven 873
        """
382 farthen 874
        self.logger.warn("Wiping the whole NAND chip!\n")
228 theseven 875
        if force == False:
382 farthen 876
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
228 theseven 877
            for i in range(10):
878
                self.logger.info(".")
879
                time.sleep(1)
880
            self.logger.info("\n")
881
        try:
775 theseven 882
            buf = self.emcore.malloc(0x100)
883
            info = self.emcore.ipodnano2g_getnandinfo()
884
            self.logger.info("Wiping NAND contents...")
885
            try:
886
                statusfile = open(filename, 'wb')
887
            except IOError:
888
                raise ArgumentError("Can not open file for writing!")
889
            for i in range(info["banks"] * info["blocks"] / 64):
890
                self.logger.info(".")
891
                self.emcore.ipodnano2g_nanderase(buf, i * 64, 64)
892
                statusfile.write(self.emcore.read(buf, 0x00000100))
893
            statusfile.close()
894
            self.logger.info("done\n")
895
        finally:
896
            self.emcore.free(buf)
517 farthen 897
 
346 theseven 898
    @command
787 theseven 899
    def ipodclassic_readbbt(self, filename, tempaddr = None):
900
        """
901
            Target-specific function: ipodclassic
902
            Reads the bad block table from the hard disk to memory at <tempaddr>
903
            (or an allocated block if not given) and writes it to <filename>
904
        """
905
        tempaddr = to_int(tempaddr)
906
        try:
907
            f = open(filename, 'wb')
908
        except IOError:
909
            raise ArgumentError("File not writable.")
910
        self.logger.info("Reading bad block table from disk...")
911
        f.write(self.emcore.ipodclassic_readbbt(tempaddr))
912
        f.close()
913
        self.logger.info(" done\n")
914
 
915
    @command
585 theseven 916
    def ipodclassic_writebbt(self, filename, tempaddr = None):
346 theseven 917
        """
918
            Target-specific function: ipodclassic
585 theseven 919
            Uploads the bad block table <filename> to memory at <tempaddr>
920
            (or an allocated block if not given) and writes it to the hard disk
346 theseven 921
        """
602 theseven 922
        tempaddr = to_int(tempaddr)
346 theseven 923
        try:
924
            f = open(filename, 'rb')
925
        except IOError:
926
            raise ArgumentError("File not readable. Does it exist?")
927
        self.logger.info("Writing bad block table to disk...")
427 farthen 928
        data = self.emcore.ipodclassic_writebbt(f.read(), tempaddr)
346 theseven 929
        f.close()
930
        self.logger.info(" done\n")
517 farthen 931
 
346 theseven 932
    @command
791 theseven 933
    def ipodclassic_disablebbt(self):
934
        """
935
            Target-specific function: ipodclassic
936
            Disables the hard disk bad block table, if present
937
        """
938
        self.logger.info("Disabling hard disk BBT...")
939
        data = self.emcore.ipodclassic_disablebbt()
940
        self.logger.info(" done\n")
941
 
942
    @command
943
    def ipodclassic_reloadbbt(self):
944
        """
945
            Target-specific function: ipodclassic
946
            Reloads the hard disk bad block table, if present
947
        """
948
        self.logger.info("Reloading hard disk BBT...")
949
        data = self.emcore.ipodclassic_reloadbbt()
950
        self.logger.info(" done\n")
951
 
952
    @command
379 theseven 953
    def getvolumeinfo(self, volume):
954
        """
955
            Gathers some information about a storage volume used
404 farthen 956
            <volume>: volume id
379 theseven 957
        """
532 farthen 958
        volume = to_int(volume)
427 farthen 959
        data = self.emcore.storage_get_info(volume)
516 farthen 960
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
961
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
962
        self.logger.info("Vendor: %s\n" % data["vendor"])
963
        self.logger.info("Product: %s\n" % data["product"])
964
        self.logger.info("Revision: %s\n" % data["revision"])
517 farthen 965
 
379 theseven 966
    @command
967
    def readrawstorage(self, volume, sector, count, addr):
968
        """
969
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
970
        """
532 farthen 971
        volume = to_int(volume)
972
        sector = to_int(sector)
973
        count = to_int(count)
974
        addr = to_int(addr)
379 theseven 975
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
427 farthen 976
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
379 theseven 977
        self.logger.info("done\n")
517 farthen 978
 
379 theseven 979
    @command
980
    def writerawstorage(self, volume, sector, count, addr):
981
        """
982
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
983
        """
532 farthen 984
        volume = to_int(volume)
985
        sector = to_int(sector)
986
        count = to_int(count)
987
        addr = to_int(addr)
379 theseven 988
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
427 farthen 989
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
379 theseven 990
        self.logger.info("done\n")
517 farthen 991
 
379 theseven 992
    @command
475 farthen 993
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 994
        """
995
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
402 farthen 996
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 997
        """
532 farthen 998
        volume = to_int(volume)
999
        sector = to_int(sector)
1000
        count = to_int(count)
1001
        buffsize = to_int(buffsize)
379 theseven 1002
        try:
479 theseven 1003
            f = open(file, 'wb')
1004
        except IOError:
1005
            raise ArgumentError("Could not open local file for writing.")
1006
        try:
482 theseven 1007
            storageinfo = self.emcore.storage_get_info(volume)
1008
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 1009
            if buffer is None:
644 theseven 1010
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1011
                malloc = True
1012
            else:
532 farthen 1013
                buffer = to_int(buffer)
479 theseven 1014
                malloc = False
472 farthen 1015
            try:
479 theseven 1016
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
1017
                while count > 0:
1018
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
792 theseven 1019
                    self.emcore.storage_read_sectors_md(volume, sector, sectors, buffer)
479 theseven 1020
                    f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
1021
                    sector = sector + sectors
1022
                    count = count - sectors
1023
            finally:
1024
                if malloc == True:
1025
                    self.emcore.free(buffer)
1026
        finally:
472 farthen 1027
            f.close()
379 theseven 1028
        self.logger.info("done\n")
517 farthen 1029
 
379 theseven 1030
    @command
475 farthen 1031
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 1032
        """
1033
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 1034
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
792 theseven 1035
            If <count> is -1, the number of sectors will be determined from the file size.
379 theseven 1036
        """
532 farthen 1037
        volume = to_int(volume)
1038
        sector = to_int(sector)
1039
        count = to_int(count)
1040
        buffsize = to_int(buffsize)
379 theseven 1041
        try:
479 theseven 1042
            f = open(file, 'rb')
1043
        except IOError:
1044
            raise ArgumentError("Could not open local file for reading.")
1045
        try:
482 theseven 1046
            storageinfo = self.emcore.storage_get_info(volume)
792 theseven 1047
            if count == -1: count = int((os.path.getsize(file) + storageinfo.sectorsize - 1) / storageinfo.sectorsize)
482 theseven 1048
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 1049
            if buffer is None:
644 theseven 1050
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1051
                malloc = True
1052
            else:
532 farthen 1053
                buffer = to_int(buffer)
479 theseven 1054
                malloc = False
472 farthen 1055
            try:
479 theseven 1056
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
1057
                while count > 0:
1058
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
1059
                    bytes = storageinfo.sectorsize * sectors
792 theseven 1060
                    data = b""
1061
                    while len(data) < bytes:
1062
                       new = f.read(bytes - len(data))
1063
                       data = data + new
1064
                       if len(new) == 0: break
479 theseven 1065
                    self.emcore.write(buffer, data)
792 theseven 1066
                    self.emcore.storage_write_sectors_md(volume, sector, sectors, buffer)
479 theseven 1067
                    sector = sector + sectors
1068
                    count = count - sectors
1069
            finally:
1070
                if malloc == True:
1071
                    self.emcore.free(buffer)
1072
        finally:
472 farthen 1073
            f.close()
379 theseven 1074
        self.logger.info("done\n")
517 farthen 1075
 
379 theseven 1076
    @command
346 theseven 1077
    def mkdir(self, dirname):
1078
        """
402 farthen 1079
            Creates a directory with the name <dirname>
346 theseven 1080
        """
516 farthen 1081
        self.logger.info("Creating directory %s..." % dirname)
427 farthen 1082
        self.emcore.dir_create(dirname)
346 theseven 1083
        self.logger.info(" done\n")
517 farthen 1084
 
346 theseven 1085
    @command
1086
    def rmdir(self, dirname):
1087
        """
402 farthen 1088
            Removes an empty directory with the name <dirname>
346 theseven 1089
        """
516 farthen 1090
        self.logger.info("Removing directory %s..." % dirname)
427 farthen 1091
        self.emcore.dir_remove(dirname)
346 theseven 1092
        self.logger.info(" done\n")
517 farthen 1093
 
346 theseven 1094
    @command
349 theseven 1095
    def rm(self, filename):
346 theseven 1096
        """
402 farthen 1097
            Removes a file with the name <filename>
346 theseven 1098
        """
516 farthen 1099
        self.logger.info("Removing file %s..." % filename)
427 farthen 1100
        self.emcore.file_unlink(filename)
346 theseven 1101
        self.logger.info(" done\n")
517 farthen 1102
 
346 theseven 1103
    @command
406 theseven 1104
    def rmtree(self, path):
1105
        """
1106
            Recursively removes a folder
1107
            <path>: the folder to be removed
1108
        """
427 farthen 1109
        handle = self.emcore.dir_open(path)
406 theseven 1110
        while True:
1111
            try:
427 farthen 1112
                entry = self.emcore.dir_read(handle)
406 theseven 1113
                if entry.name == "." or entry.name == "..": continue
1114
                elif entry.attributes & 0x10:
1115
                    self.rmtree(path + "/" + entry.name)
1116
                else: self.rm(path + "/" + entry.name)
1117
            except: break
427 farthen 1118
        self.emcore.dir_close(handle)
406 theseven 1119
        self.rmdir(path)
517 farthen 1120
 
406 theseven 1121
    @command
352 theseven 1122
    def mv(self, oldname, newname):
350 theseven 1123
        """
402 farthen 1124
            Renames or moves file or directory <oldname> to <newname>
350 theseven 1125
        """
516 farthen 1126
        self.logger.info("Renaming %s to %s..." % (oldname, newname))
427 farthen 1127
        self.emcore.file_rename(oldname, newname)
350 theseven 1128
        self.logger.info(" done\n")
517 farthen 1129
 
350 theseven 1130
    @command
475 farthen 1131
    def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
346 theseven 1132
        """
1133
            Downloads a file
402 farthen 1134
            <remotename>: filename on the device
1135
            <localname>: filename on the computer
472 farthen 1136
            [buffsize]: buffer size (optional)
402 farthen 1137
            [buffer]: buffer address (optional)
346 theseven 1138
        """
532 farthen 1139
        buffsize = to_int(buffsize)
346 theseven 1140
        try:
479 theseven 1141
            f = open(localname, 'wb')
1142
        except IOError:
1143
            raise ArgumentError("Could not open local file for writing.")
1144
        try:
482 theseven 1145
            fd = self.emcore.file_open(remotename, 0)
472 farthen 1146
            try:
482 theseven 1147
                size = self.emcore.file_size(fd)
1148
                buffsize = min(buffsize, size)
1149
                if buffer is None:
644 theseven 1150
                    buffer = self.emcore.memalign(0x10, buffsize)
482 theseven 1151
                    malloc = True
1152
                else:
532 farthen 1153
                    buffer = to_int(buffer)
482 theseven 1154
                    malloc = False
479 theseven 1155
                try:
516 farthen 1156
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
479 theseven 1157
                    while size > 0:
488 theseven 1158
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
479 theseven 1159
                        f.write(self.emcore.read(buffer, bytes))
1160
                        size = size - bytes
1161
                finally:
482 theseven 1162
                    if malloc == True:
1163
                        self.emcore.free(buffer)
479 theseven 1164
            finally:
482 theseven 1165
                self.emcore.file_close(fd)
479 theseven 1166
        finally:
472 farthen 1167
            f.close()
346 theseven 1168
        self.logger.info(" done\n")
517 farthen 1169
 
346 theseven 1170
    @command
475 farthen 1171
    def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
406 theseven 1172
        """
1173
            Downloads a directory tree
1174
            <remotepath>: path on the device
1175
            <localpath>: path on the computer
472 farthen 1176
            [buffsize]: buffer size (optional)
406 theseven 1177
            [buffer]: buffer address (optional)
1178
        """
532 farthen 1179
        buffsize = to_int(buffsize)
479 theseven 1180
        handle = self.emcore.dir_open(remotepath)
472 farthen 1181
        try:
479 theseven 1182
            if buffer is None:
644 theseven 1183
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1184
                malloc = True
1185
            else:
532 farthen 1186
                buffer = to_int(buffer)
479 theseven 1187
                malloc = False
1188
            try:
1189
                try: os.mkdir(localpath)
1190
                except: pass
1191
                while True:
1192
                    try:
1193
                        entry = self.emcore.dir_read(handle)
1194
                    except: break
486 theseven 1195
                    if entry.name == "." or entry.name == "..": continue
1196
                    elif entry.attributes & 0x10:
1197
                        self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1198
                    else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
479 theseven 1199
            finally:
1200
                if malloc == True:
1201
                    self.emcore.free(buffer)
1202
        finally:
472 farthen 1203
            self.emcore.dir_close(handle)
517 farthen 1204
 
406 theseven 1205
    @command
475 farthen 1206
    def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
346 theseven 1207
        """
1208
            Uploads a file
406 theseven 1209
            <localname>: filename on the computer
402 farthen 1210
            <remotename>: filename on the device
472 farthen 1211
            [buffsize]: buffer size (optional)
402 farthen 1212
            [buffer]: buffer address (optional)
346 theseven 1213
        """
532 farthen 1214
        buffsize = to_int(buffsize)
346 theseven 1215
        try:
479 theseven 1216
            f = open(localname, 'rb')
1217
        except IOError:
1218
            raise ArgumentError("Could not open local file for reading.")
1219
        try:
482 theseven 1220
            buffsize = min(buffsize, os.path.getsize(localname))
479 theseven 1221
            if buffer is None:
644 theseven 1222
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1223
                malloc = True
1224
            else:
532 farthen 1225
                buffer = to_int(buffer)
479 theseven 1226
                malloc = False
472 farthen 1227
            try:
516 farthen 1228
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
479 theseven 1229
                fd = self.emcore.file_open(remotename, 0x15)
1230
                try:
1231
                    while True:
1232
                        data = f.read(buffsize)
1233
                        if len(data) == 0: break
1234
                        self.emcore.write(buffer, data)
1235
                        bytes = 0
1236
                        while bytes < len(data):
1237
                            bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
1238
                finally:
1239
                    self.emcore.file_close(fd)
1240
            finally:
1241
                if malloc == True:
1242
                    self.emcore.free(buffer)
1243
        finally:
472 farthen 1244
            f.close()
346 theseven 1245
        self.logger.info(" done\n")
517 farthen 1246
 
346 theseven 1247
    @command
475 farthen 1248
    def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
406 theseven 1249
        """
1250
            Uploads a directory tree
1251
            <localpath>: path on the computer
1252
            <remotepath>: path on the device
472 farthen 1253
            [buffsize]: buffer size (optional)
406 theseven 1254
            [buffer]: buffer address (optional)
1255
        """
532 farthen 1256
        buffsize = to_int(buffsize)
472 farthen 1257
        if buffer is None:
644 theseven 1258
            buffer = self.emcore.memalign(0x10, buffsize)
472 farthen 1259
            malloc = True
1260
        else:
532 farthen 1261
            buffer = to_int(buffer)
472 farthen 1262
            malloc = False
1263
        try:
1264
            try: self.mkdir(remotepath)
1265
            except: self.logger.info(" failed\n")
1266
            pathlen = len(localpath)
1267
            for d in os.walk(localpath):
1268
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1269
                for dir in d[1]:
1270
                    if dir != ".svn":
1271
                        try: self.mkdir(prefix + dir)
1272
                        except: self.logger.info(" failed\n")
1273
                for f in d[2]:
479 theseven 1274
                    if prefix.find("/.svn/") == -1:
477 farthen 1275
                        self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
472 farthen 1276
        finally:
1277
            if malloc == True:
1278
                self.emcore.free(buffer)
517 farthen 1279
 
406 theseven 1280
    @command
351 theseven 1281
    def ls(self, path = "/"):
346 theseven 1282
        """
1283
            Lists all files in the specified path
402 farthen 1284
            [path]: the path which is listed
346 theseven 1285
        """
427 farthen 1286
        handle = self.emcore.dir_open(path)
516 farthen 1287
        self.logger.info("Directory listing of %s:\n" % path)
346 theseven 1288
        while True:
1289
            try:
427 farthen 1290
                entry = self.emcore.dir_read(handle)
346 theseven 1291
            except: break
486 theseven 1292
            if entry.attributes & 0x10: size = "DIR"
1293
            else: size = locale.format("%d", entry.size, True).rjust(13)
1294
            self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
427 farthen 1295
        self.emcore.dir_close(handle)
474 farthen 1296
 
1297
    @command
483 theseven 1298
    def find(self, path = "/"):
1299
        """
1300
            Lists all files in the specified path, recursively
1301
            [path]: the path which is listed
1302
        """
1303
        handle = self.emcore.dir_open(path)
1304
        self.logger.info(path + "/\n")
1305
        while True:
1306
            try:
1307
                entry = self.emcore.dir_read(handle)
1308
            except: break
486 theseven 1309
            if entry.name == "." or entry.name == "..": continue
1310
            elif entry.attributes & 0x10: self.find(path + "/" + entry.name)
1311
            else: self.logger.info(path + "/" + entry.name + "\n")
483 theseven 1312
        self.emcore.dir_close(handle)
1313
 
1314
    @command
474 farthen 1315
    def malloc(self, size):
1316
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
532 farthen 1317
        size = to_int(size)
474 farthen 1318
        self.logger.info("Allocating %d bytes of memory\n" % size)
1319
        addr = self.emcore.malloc(size)
518 farthen 1320
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1321
 
1322
    @command
1323
    def memalign(self, align, size):
1324
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
532 farthen 1325
        align = to_int(align)
1326
        size = to_int(size)
518 farthen 1327
        self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
474 farthen 1328
        addr = self.emcore.memalign(align, size)
518 farthen 1329
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1330
 
1331
    @command
1332
    def realloc(self, ptr, size):
1333
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1334
            expanding or reducing the amount of memory available in the block.
1335
            Returns a pointer to the reallocated memory.
1336
        """
532 farthen 1337
        ptr = to_int(ptr)
1338
        size = to_int(size)
518 farthen 1339
        self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
474 farthen 1340
        addr = self.emcore.realloc(ptr, size)
518 farthen 1341
        self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
474 farthen 1342
 
1343
    @command
1344
    def reownalloc(self, ptr, owner):
1345
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
532 farthen 1346
        ptr = to_int(ptr)
1347
        owner = to_int(owner)
518 farthen 1348
        self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1349
        self.emcore.reownalloc(ptr, owner)
518 farthen 1350
        self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1351
 
1352
    @command
1353
    def free(self, ptr):
1354
        """ Frees the memory space pointed to by 'ptr' """
532 farthen 1355
        ptr = to_int(ptr)
518 farthen 1356
        self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
474 farthen 1357
        self.emcore.free(ptr)
518 farthen 1358
        self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
474 farthen 1359
 
1360
    @command
1361
    def free_all(self):
1362
        """ Frees all memory allocations created by the monitor thread """
1363
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1364
        self.emcore.free_all()
1365
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
778 farthen 1366
 
1367
    @command
1368
    def rtcread(self):
1369
        """ Reads the real time clock on the device """
1370
        import datetime
1371
        self.logger.info("Reading the clock\n")
1372
        dt = self.emcore.rtcread()
1373
        self.logger.info("Successfully read the clock: %s\n" % (dt.ctime()))
1374
 
1375
    @command
1376
    def rtcwrite(self):
1377
        """ Sets the real time clock on the device to the current local time """
1378
        import datetime
1379
        dt = datetime.datetime.now()
1380
        self.logger.info("Setting the clock to: %s\n" % (dt.ctime()))
1381
        self.emcore.rtcwrite(dt)
1382
        self.logger.info("Successfully set the clock\n")
474 farthen 1383
 
346 theseven 1384
 
171 farthen 1385
if __name__ == "__main__":
1386
    if len(sys.argv) < 2:
502 farthen 1387
        usage("No command specified", docstring = False)
382 farthen 1388
    try:
1389
        interface = Commandline()
1390
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1391
    except KeyboardInterrupt:
778 farthen 1392
        sys.exit()