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
#
22
#
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.
171 farthen 159
            <infotype> may be either of 'version', 'packetsize', 'usermemrange'.
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
 
171 farthen 178
        elif infotype == "usermemrange":
427 farthen 179
            resp = self.emcore.getusermemrange()
516 farthen 180
            self.logger.info("The user memory range is 0x%X - 0x%X" % (
181
                             self.emcore.lib.dev.usermem.lower,
182
                             self.emcore.lib.dev.usermem.upper - 1))
382 farthen 183
 
171 farthen 184
        else:
185
            raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", 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
171 farthen 314
    def uploadint(self, addr, integer):
315
        """
316
            Uploads a single integer to the device
260 theseven 317
            <addr>: the address to upload the integer to
318
            <integer>: the integer to upload
171 farthen 319
        """
532 farthen 320
        addr = to_int(addr)
321
        integer = to_int(integer)
171 farthen 322
        if integer > 0xFFFFFFFF:
323
            raise ArgumentError("Specified integer too long")
548 farthen 324
        data = struct.pack("<I", integer)
427 farthen 325
        self.emcore.write(addr, data)
516 farthen 326
        self.logger.info("Integer '0x%X' written successfully to 0x%X\n" % (integer, addr))
517 farthen 327
 
171 farthen 328
    @command
329
    def downloadint(self, addr):
330
        """
331
            Downloads a single integer from the device and prints it to the console window
236 farthen 332
            <addr>: the address to download the integer from
171 farthen 333
        """
532 farthen 334
        addr = to_int(addr)
427 farthen 335
        data = self.emcore.read(addr, 4)
548 farthen 336
        integer = struct.unpack("<I", data)[0]
516 farthen 337
        self.logger.info("Read '0x%X' from address 0x%X\n" % (integer, addr))
517 farthen 338
 
171 farthen 339
    @command
176 farthen 340
    def i2cread(self, bus, slave, addr, size):
171 farthen 341
        """
342
            Reads data from an I2C device
402 farthen 343
            <bus>: the bus index
344
            <slave>: the slave address
345
            <addr>: the start address on the I2C device
346
            <size>: the number of bytes to read
171 farthen 347
        """
532 farthen 348
        bus = to_int(bus)
349
        slave = to_int(slave)
350
        addr = to_int(addr)
351
        size = to_int(size)
427 farthen 352
        data = self.emcore.i2cread(bus, slave, addr, size)
548 farthen 353
        bytes = struct.unpack("<%dB" % len(data), data)
236 farthen 354
        self.logger.info("Data read from I2C:\n")
355
        for index, byte in enumerate(bytes):
533 theseven 356
            self.logger.info("%02X: %02X\n" % (addr + index, byte))
517 farthen 357
 
171 farthen 358
    @command
176 farthen 359
    def i2cwrite(self, bus, slave, addr, *args):
171 farthen 360
        """
361
            Writes data to an I2C device
402 farthen 362
            <bus>: the bus index
363
            <slave>: the slave address
364
            <addr>: the start address on the I2C device
532 farthen 365
            <db1> ... <dbN>: the data in single bytes,
236 farthen 366
                seperated by whitespaces, eg. 37 5A 4F EB
171 farthen 367
        """
532 farthen 368
        bus = to_int(bus)
369
        slave = to_int(slave)
370
        addr = to_int(addr)
176 farthen 371
        data = ""
171 farthen 372
        for arg in args:
532 farthen 373
            data += chr(to_int(arg))
236 farthen 374
        self.logger.info("Writing data to I2C...\n")
427 farthen 375
        self.emcore.i2cwrite(bus, slave, addr, data)
236 farthen 376
        self.logger.info("done\n")
517 farthen 377
 
171 farthen 378
    @command
176 farthen 379
    def console(self):
171 farthen 380
        """
176 farthen 381
            Reads data from the USB console continuously
171 farthen 382
        """
176 farthen 383
        while True:
427 farthen 384
            resp = self.emcore.usbcread()
599 farthen 385
            self.logger.write(resp.data, target = "stdout")
176 farthen 386
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
517 farthen 387
 
171 farthen 388
    @command
176 farthen 389
    def writeusbconsole(self, *args):
171 farthen 390
        """
176 farthen 391
            Writes the string <db1> ... <dbN> to the USB console.
171 farthen 392
        """
176 farthen 393
        text = ""
394
        for word in args:
395
            text += word + " "
396
        text = text[:-1]
516 farthen 397
        self.logger.info("Writing '%s' to the usb console\n" % text)
427 farthen 398
        self.emcore.usbcwrite(text)
517 farthen 399
 
171 farthen 400
    @command
176 farthen 401
    def readdevconsole(self, bitmask):
171 farthen 402
        """
176 farthen 403
            Reads data continuously from one or more of the device's consoles.
404
            <bitmask>: the bitmask of the consoles to read from.
171 farthen 405
        """
532 farthen 406
        bitmask = to_int(bitmask)
176 farthen 407
        while True:
427 farthen 408
            resp = self.emcore.cread()
501 farthen 409
            self.logger.write(resp.data)
176 farthen 410
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
411
 
171 farthen 412
    @command
176 farthen 413
    def writedevconsole(self, bitmask, *args):
171 farthen 414
        """
176 farthen 415
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
416
            <bitmask>: the bitmask of the consoles to write to
171 farthen 417
        """
532 farthen 418
        bitmask = to_int(bitmask)
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 device consoles identified with 0x%X\n" % (text, bitmask))
427 farthen 424
        self.emcore.cwrite(text, bitmask)
517 farthen 425
 
171 farthen 426
    @command
427
    def flushconsolebuffers(self, bitmask):
428
        """
429
            flushes one or more of the device consoles' buffers.
430
            <bitmask>: the bitmask of the consoles to be flushed
431
        """
532 farthen 432
        bitmask = to_int(bitmask)
516 farthen 433
        self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
427 farthen 434
        self.emcore.cflush(bitmask)
517 farthen 435
 
171 farthen 436
    @command
437
    def getprocinfo(self):
438
        """
439
            Fetches data on the currently running processes
440
        """
173 farthen 441
        import datetime
427 farthen 442
        threads = self.emcore.getprocinfo()
382 farthen 443
        threadload = 0
444
        idleload = 0
173 farthen 445
        for thread in threads:
392 theseven 446
            if thread.id != 0:
447
                threadload += thread.cpuload / 255.
382 farthen 448
            else:
392 theseven 449
                idleload += thread.cpuload / 255.
382 farthen 450
        coreload = 1 - (threadload + idleload)
451
        cpuload = threadload + coreload
392 theseven 452
        self.logger.info("Threads: %d, CPU load: %.1f%%, kernel load: %.1f%%, user load: %.1f%%\n\n"
453
                         % (len(threads), cpuload * 100, coreload * 100, threadload * 100))
382 farthen 454
        self.logger.info("Thread dump:\n")
455
        for thread in threads:
516 farthen 456
            self.logger.info("%s:\n" % thread.name, 2)
457
            self.logger.info("Threadstruct address: 0x%X\n" % thread.addr, 4)
458
            self.logger.info("Thread type: %s\n" % thread.thread_type, 4)
459
            self.logger.info("Thread state: %s\n" % thread.state, 4)
605 farthen 460
            if thread.block_type != "THREAD_NOT_BLOCKED":
609 farthen 461
                self.logger.info("Block type: %s\n" % thread.block_type, 4)
462
                if thread.block_type == "THREAD_BLOCK_MUTEX":
463
                    self.logger.info("Blocked by mutex: 0x%X\n" % thread.blocked_by, 6)
464
                    self.logger.info("Owner: %s (0x%X)\n" % (thread.blocked_by.owner.name, thread.blocked_by.owner), 8)
465
                elif thread.block_type == "THREAD_BLOCK_WAKEUP":
466
                    self.logger.info("Blocked by wakeup: 0x%X\n" % thread.blocked_by, 6)
516 farthen 467
            self.logger.info("Priority: %d/255\n" % thread.priority, 4)
396 farthen 468
            self.logger.info("Current CPU load: %.1f%%\n" % ((thread.cpuload * 100) / 255.), 4)
516 farthen 469
            self.logger.info("CPU time (total): %s\n" % datetime.timedelta(microseconds = thread.cputime_total), 4)
470
            self.logger.info("Stack address: 0x%X\n" % thread.stack, 4)
396 farthen 471
            self.logger.info("Registers:\n", 4)
177 farthen 472
            for registerrange in range(4):
473
                for register in range(registerrange, 16, 4):
474
                    registerrepr = "r"+str(register)
606 farthen 475
                    self.logger.info("{0:>3s}: 0x{1:08X}   ".format(registerrepr, thread.regs[register]), 5)
177 farthen 476
                self.logger.info("\n")
506 farthen 477
            self.logger.info("cpsr: 0x{0:08X}".format(thread.cpsr), 6)
173 farthen 478
            self.logger.info("\n")
479
 
171 farthen 480
    @command
481
    def lockscheduler(self):
482
        """
483
            Locks (freezes) the scheduler
484
        """
176 farthen 485
        self.logger.info("Will now lock scheduler\n")
427 farthen 486
        self.emcore.lockscheduler()
178 farthen 487
 
171 farthen 488
    @command
489
    def unlockscheduler(self):
490
        """
491
            Unlocks (unfreezes) the scheduler
492
        """
176 farthen 493
        self.logger.info("Will now unlock scheduler\n")
427 farthen 494
        self.emcore.unlockscheduler()
178 farthen 495
 
171 farthen 496
    @command
516 farthen 497
    def suspendthread(self, threadaddr):
171 farthen 498
        """
516 farthen 499
            Suspends the thread with the thread address <threadaddr>
171 farthen 500
        """
532 farthen 501
        threadaddr = to_int(threadaddr)
516 farthen 502
        self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
503
        self.emcore.suspendthread(threadaddr)
517 farthen 504
 
171 farthen 505
    @command
516 farthen 506
    def resumethread(self, threadaddr):
171 farthen 507
        """
516 farthen 508
            Resumes the thread with the thread address <threadaddr>
171 farthen 509
        """
532 farthen 510
        threadaddr = to_int(threadaddr)
516 farthen 511
        self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
512
        self.emcore.resumethread(threadaddr)
517 farthen 513
 
171 farthen 514
    @command
516 farthen 515
    def killthread(self, threadaddr):
171 farthen 516
        """
516 farthen 517
            Kills the thread with the thread address <threadaddr>
171 farthen 518
        """
532 farthen 519
        threadaddr = to_int(threadaddr)
516 farthen 520
        self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
521
        self.emcore.killthread(threadaddr)
517 farthen 522
 
171 farthen 523
    @command
524
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
525
        """
516 farthen 526
            Creates a new thread and returns its thread pointer
402 farthen 527
            <namepointer>: a pointer to the thread's name
528
            <entrypoint>: a pointer to the entrypoint of the thread
529
            <stackpointer>: a pointer to the stack of the thread
530
            <stacksize>: the size of the thread's stack
516 farthen 531
            <threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
402 farthen 532
            <priority>: the priority of the thread, from 1 to 255
533
            <state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
171 farthen 534
        """
532 farthen 535
        nameptr = to_int(nameptr)
536
        entrypoint = to_int(entrypoint)
537
        stackptr = to_int(stackptr)
538
        stacksize = to_int(stacksize)
539
        priority = to_int(priority)
516 farthen 540
        data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
427 farthen 541
        name = self.emcore.readstring(nameptr)
516 farthen 542
        self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
543
                         "the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
544
                        (data.threadptr, name, entrypoint, stackptr, stacksize, priority))
172 farthen 545
 
546
    @command
547
    def run(self, filename):
548
        """
427 farthen 549
            Uploads the emCORE application <filename> to
236 farthen 550
            the memory and executes it
172 farthen 551
        """
236 farthen 552
        try:
553
            f = open(filename, 'rb')
554
        except IOError:
555
            raise ArgumentError("File not readable. Does it exist?")
238 farthen 556
        with f:
427 farthen 557
            data = self.emcore.run(f.read())
516 farthen 558
        self.logger.info("Executed emCORE application as thread 0x%X\n" % data.thread)
517 farthen 559
 
171 farthen 560
    @command
173 farthen 561
    def execimage(self, addr):
171 farthen 562
        """
427 farthen 563
            Executes the emCORE application at <addr>.
171 farthen 564
        """
532 farthen 565
        addr = to_int(addr)
516 farthen 566
        self.logger.info("Starting emCORE app at 0x%X\n" % addr)
427 farthen 567
        self.emcore.execimage(addr)
176 farthen 568
 
171 farthen 569
    @command
176 farthen 570
    def flushcaches(self):
171 farthen 571
        """
176 farthen 572
            Flushes the CPUs data and instruction caches.
573
        """
574
        self.logger.info("Flushing CPU data and instruction caches...")
427 farthen 575
        self.emcore.flushcaches()
176 farthen 576
        self.logger.info("done\n")
577
 
578
    @command
579
    def readbootflash(self, addr_flash, addr_mem, size):
580
        """
171 farthen 581
            Reads <size> bytes from bootflash to memory.
582
            <addr_bootflsh>: the address in bootflash to read from
583
            <addr_mem>: the address in memory to copy the data to
584
        """
532 farthen 585
        addr_flash = to_int(addr_flash)
586
        addr_mem = to_int(addr_mem)
587
        size = to_int(size)
516 farthen 588
        self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
589
                        (addr_flash, addr_flash + size, addr_mem, addr_mem + size))
427 farthen 590
        self.emcore.bootflashread(addr_mem, addr_flash, size)
176 farthen 591
 
171 farthen 592
    @command
176 farthen 593
    def writebootflash(self, addr_flash, addr_mem, size, force=False):
171 farthen 594
        """
595
            Writes <size> bytes from memory to bootflash.
596
            ATTENTION: Don't call this unless you really know what you're doing!
597
            This may BRICK your device (unless it has a good recovery option)
598
            <addr_mem>: the address in memory to copy the data from
599
            <addr_bootflsh>: the address in bootflash to write to
402 farthen 600
            [force]: Use this flag to suppress the 5 seconds delay
171 farthen 601
        """
532 farthen 602
        addr_flash = to_int(addr_flash)
603
        addr_mem = to_int(addr_mem)
604
        size = to_int(size)
605
        force = to_bool(force)
516 farthen 606
        self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
607
                        (addr_mem, addr_mem + size, addr_flash, addr_flash + size))
174 farthen 608
        if force == False:
382 farthen 609
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
176 farthen 610
            for i in range(10):
174 farthen 611
                self.logger.info(".")
612
                time.sleep(1)
613
            self.logger.info("\n")
427 farthen 614
        self.emcore.bootflashwrite(addr_mem, addr_flash, size)
176 farthen 615
 
171 farthen 616
    @command
442 farthen 617
    def runfirmware(self, targetaddr, filename):
171 farthen 618
        """
402 farthen 619
            Uploads the firmware in <filename>
442 farthen 620
            to an allocated buffer and executes it at <targetaddr>.
171 farthen 621
        """
532 farthen 622
        targetaddr = to_int(targetaddr)
442 farthen 623
        addr, size = self.uploadfile(filename)
624
        self.execfirmware(targetaddr, addr, size)
64 benedikt93 625
 
171 farthen 626
    @command
442 farthen 627
    def execfirmware(self, targetaddr, addr, size):
176 farthen 628
        """
442 farthen 629
            Moves the firmware at <addr> with <size> to <targetaddr> and executes it
176 farthen 630
        """
532 farthen 631
        targetaddr = to_int(targetaddr)
632
        addr = to_int(addr)
536 farthen 633
        size = to_int(size)
634
        self.logger.info("Running firmware at 0x%X. Bye.\n" % targetaddr)
442 farthen 635
        self.emcore.execfirmware(targetaddr, addr, size)
176 farthen 636
 
637
    @command
171 farthen 638
    def aesencrypt(self, addr, size, keyindex):
639
        """
172 farthen 640
            Encrypts a buffer using a hardware key
402 farthen 641
            <addr>: the starting address of the buffer
642
            <size>: the size of the buffer
643
            <keyindex>: the index of the key in the crypto unit
171 farthen 644
        """
532 farthen 645
        addr = to_int(addr)
646
        size = to_int(size)
647
        keyindex = to_int(keyindex)
427 farthen 648
        self.emcore.aesencrypt(addr, size, keyindex)
82 benedikt93 649
 
171 farthen 650
    @command
651
    def aesdecrypt(self, addr, size, keyindex):
652
        """
172 farthen 653
            Decrypts a buffer using a hardware key
402 farthen 654
            <addr>: the starting address of the buffer
655
            <size>: the size of the buffer
656
            <keyindex>: the index of the key in the crypto unit
171 farthen 657
        """
532 farthen 658
        addr = to_int(addr)
659
        size = to_int(size)
660
        keyindex = to_int(keyindex)
427 farthen 661
        self.emcore.aesdecrypt(addr, size, keyindex)
172 farthen 662
 
663
    @command
664
    def hmac_sha1(self, addr, size, destination):
665
        """
402 farthen 666
            Generates a HMAC-SHA1 hash of the buffer
667
            <addr>: the starting address of the buffer
668
            <size>: the size of the buffer
669
            <destination>: the location where the key will be stored
172 farthen 670
        """
532 farthen 671
        addr = to_int(addr)
672
        size = to_int(size)
673
        destination = to_int(destination)
172 farthen 674
        sha1size = 0x14
516 farthen 675
        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" %
676
                        (addr, size, destination, destination + sha1size))
427 farthen 677
        self.emcore.hmac_sha1(addr, size, destination)
172 farthen 678
        self.logger.info("done\n")
427 farthen 679
        data = self.emcore.read(destination, sha1size)
172 farthen 680
        hash = ord(data)
516 farthen 681
        self.logger.info("The generated hash is 0x%X\n" % hash)
517 farthen 682
 
227 theseven 683
    @command
684
    def ipodnano2g_getnandinfo(self):
685
        """
686
            Target-specific function: ipodnano2g
687
            Gathers some information about the NAND chip used
688
        """
427 farthen 689
        data = self.emcore.ipodnano2g_getnandinfo()
516 farthen 690
        self.logger.info("NAND chip type: 0x%X\n" % data["type"])
691
        self.logger.info("Number of banks: %d\n" % data["banks"])
692
        self.logger.info("Number of blocks: %d\n" % data["blocks"])
693
        self.logger.info("Number of user blocks: %d\n" % data["userblocks"])
694
        self.logger.info("Pages per block: %d\n" % data["pagesperblock"])
517 farthen 695
 
227 theseven 696
    @command
404 farthen 697
    def ipodnano2g_nandread(self, addr, start, count, doecc=True, checkempty=True):
227 theseven 698
        """
699
            Target-specific function: ipodnano2g
700
            Reads data from the NAND chip into memory
402 farthen 701
            <addr>: the memory location where the data is written to
702
            <start>: start block
703
            <count>: block count
404 farthen 704
            [doecc]: use ecc error correction data
705
            [checkempty]: set statusflags if pages are empty
227 theseven 706
        """
532 farthen 707
        addr = to_int(addr)
708
        start = to_int(start)
709
        count = to_int(count)
710
        doecc = to_bool(doecc)
711
        checkempty = to_bool(checkempty)
516 farthen 712
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
713
                        (count, start, addr))
427 farthen 714
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
227 theseven 715
        self.logger.info("done\n")
517 farthen 716
 
227 theseven 717
    @command
404 farthen 718
    def ipodnano2g_nandwrite(self, addr, start, count, doecc=True):
227 theseven 719
        """
720
            Target-specific function: ipodnano2g
721
            Writes data to the NAND chip
402 farthen 722
            <addr>: the memory location where the data is read from
723
            <start>: start block
724
            <count>: block count
404 farthen 725
            [doecc]: create ecc error correction data
227 theseven 726
        """
532 farthen 727
        addr = to_int(addr)
728
        start = to_int(start)
729
        count = to_int(count)
730
        doecc = to_bool(doecc)
516 farthen 731
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
732
                        (count, start, addr))
427 farthen 733
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
227 theseven 734
        self.logger.info("done\n")
517 farthen 735
 
227 theseven 736
    @command
737
    def ipodnano2g_nanderase(self, addr, start, count):
738
        """
739
            Target-specific function: ipodnano2g
740
            Erases blocks on the NAND chip and stores the results to memory
402 farthen 741
            <addr>: the memory location where the results are stored
742
            <start>: start block
743
            <count>: block count
227 theseven 744
        """
532 farthen 745
        addr = to_int(addr)
746
        start = to_int(start)
747
        count = to_int(count)
516 farthen 748
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
749
                        (count, start, addr))
427 farthen 750
        self.emcore.ipodnano2g_nanderase(addr, start, count)
227 theseven 751
        self.logger.info("done\n")
517 farthen 752
 
228 theseven 753
    @command
754
    def ipodnano2g_dumpnand(self, filenameprefix):
755
        """
756
            Target-specific function: ipodnano2g
757
            Dumps the whole NAND chip to four files
402 farthen 758
            <filenameprefix>: prefix of the files that will be created
228 theseven 759
        """
427 farthen 760
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 761
        self.logger.info("Dumping NAND contents...")
762
        try:
763
            infofile = open(filenameprefix+"_info.txt", 'wb')
764
            datafile = open(filenameprefix+"_data.bin", 'wb')
765
            sparefile = open(filenameprefix+"_spare.bin", 'wb')
766
            statusfile = open(filenameprefix+"_status.bin", 'wb')
767
        except IOError:
768
            raise ArgumentError("Can not open file for writing!")
516 farthen 769
        infofile.write("NAND chip type: 0x%X\r\n" % info["type"])
770
        infofile.write("Number of banks: %d\r\n" % info["banks"])
771
        infofile.write("Number of blocks: %d\r\n" % info["blocks"])
772
        infofile.write("Number of user blocks: %d\r\n" % info["userblocks"])
773
        infofile.write("Pages per block: %d\r\n" % info["pagesperblock"])
228 theseven 774
        for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
775
            self.logger.info(".")
427 farthen 776
            self.emcore.ipodnano2g_nandread(0x08000000, i * 8192, 8192, 1, 1)
777
            datafile.write(self.emcore.read(0x08000000, 0x01000000))
778
            sparefile.write(self.emcore.read(0x09000000, 0x00080000))
779
            statusfile.write(self.emcore.read(0x09080000, 0x00008000))
228 theseven 780
        infofile.close()
781
        datafile.close()
782
        sparefile.close()
783
        statusfile.close()
784
        self.logger.info("done\n")
517 farthen 785
 
228 theseven 786
    @command
787
    def ipodnano2g_wipenand(self, filename, force=False):
788
        """
789
            Target-specific function: ipodnano2g
790
            Wipes the whole NAND chip and logs the result to a file
402 farthen 791
            <filename>: location of the log file
792
            [force]: use this flag to suppress the 5 seconds delay
228 theseven 793
        """
382 farthen 794
        self.logger.warn("Wiping the whole NAND chip!\n")
228 theseven 795
        if force == False:
382 farthen 796
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
228 theseven 797
            for i in range(10):
798
                self.logger.info(".")
799
                time.sleep(1)
800
            self.logger.info("\n")
427 farthen 801
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 802
        self.logger.info("Wiping NAND contents...")
803
        try:
804
            statusfile = open(filename, 'wb')
805
        except IOError:
806
            raise ArgumentError("Can not open file for writing!")
807
        for i in range(info["banks"] * info["blocks"] / 64):
808
            self.logger.info(".")
427 farthen 809
            self.emcore.ipodnano2g_nanderase(0x08000000, i * 64, 64)
810
            statusfile.write(self.emcore.read(0x08000000, 0x00000100))
228 theseven 811
        statusfile.close()
812
        self.logger.info("done\n")
517 farthen 813
 
346 theseven 814
    @command
585 theseven 815
    def ipodclassic_writebbt(self, filename, tempaddr = None):
346 theseven 816
        """
817
            Target-specific function: ipodclassic
585 theseven 818
            Uploads the bad block table <filename> to memory at <tempaddr>
819
            (or an allocated block if not given) and writes it to the hard disk
346 theseven 820
        """
602 theseven 821
        tempaddr = to_int(tempaddr)
346 theseven 822
        try:
823
            f = open(filename, 'rb')
824
        except IOError:
825
            raise ArgumentError("File not readable. Does it exist?")
826
        self.logger.info("Writing bad block table to disk...")
427 farthen 827
        data = self.emcore.ipodclassic_writebbt(f.read(), tempaddr)
346 theseven 828
        f.close()
829
        self.logger.info(" done\n")
517 farthen 830
 
346 theseven 831
    @command
379 theseven 832
    def getvolumeinfo(self, volume):
833
        """
834
            Gathers some information about a storage volume used
404 farthen 835
            <volume>: volume id
379 theseven 836
        """
532 farthen 837
        volume = to_int(volume)
427 farthen 838
        data = self.emcore.storage_get_info(volume)
516 farthen 839
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
840
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
841
        self.logger.info("Vendor: %s\n" % data["vendor"])
842
        self.logger.info("Product: %s\n" % data["product"])
843
        self.logger.info("Revision: %s\n" % data["revision"])
517 farthen 844
 
379 theseven 845
    @command
846
    def readrawstorage(self, volume, sector, count, addr):
847
        """
848
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
849
        """
532 farthen 850
        volume = to_int(volume)
851
        sector = to_int(sector)
852
        count = to_int(count)
853
        addr = to_int(addr)
379 theseven 854
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
427 farthen 855
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
379 theseven 856
        self.logger.info("done\n")
517 farthen 857
 
379 theseven 858
    @command
859
    def writerawstorage(self, volume, sector, count, addr):
860
        """
861
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
862
        """
532 farthen 863
        volume = to_int(volume)
864
        sector = to_int(sector)
865
        count = to_int(count)
866
        addr = to_int(addr)
379 theseven 867
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
427 farthen 868
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
379 theseven 869
        self.logger.info("done\n")
517 farthen 870
 
379 theseven 871
    @command
475 farthen 872
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 873
        """
874
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
402 farthen 875
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 876
        """
532 farthen 877
        volume = to_int(volume)
878
        sector = to_int(sector)
879
        count = to_int(count)
880
        buffsize = to_int(buffsize)
379 theseven 881
        try:
479 theseven 882
            f = open(file, 'wb')
883
        except IOError:
884
            raise ArgumentError("Could not open local file for writing.")
885
        try:
482 theseven 886
            storageinfo = self.emcore.storage_get_info(volume)
887
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 888
            if buffer is None:
889
                buffer = self.emcore.malloc(buffsize)
890
                malloc = True
891
            else:
532 farthen 892
                buffer = to_int(buffer)
479 theseven 893
                malloc = False
472 farthen 894
            try:
479 theseven 895
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
896
                while count > 0:
897
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
898
                    self.emcore.storage_read_sectors_md(volume, sector, sectors, buffsize, buffer)
899
                    f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
900
                    sector = sector + sectors
901
                    count = count - sectors
902
            finally:
903
                if malloc == True:
904
                    self.emcore.free(buffer)
905
        finally:
472 farthen 906
            f.close()
379 theseven 907
        self.logger.info("done\n")
517 farthen 908
 
379 theseven 909
    @command
475 farthen 910
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 911
        """
912
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 913
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 914
        """
532 farthen 915
        volume = to_int(volume)
916
        sector = to_int(sector)
917
        count = to_int(count)
918
        buffsize = to_int(buffsize)
379 theseven 919
        try:
479 theseven 920
            f = open(file, 'rb')
921
        except IOError:
922
            raise ArgumentError("Could not open local file for reading.")
923
        try:
482 theseven 924
            storageinfo = self.emcore.storage_get_info(volume)
925
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 926
            if buffer is None:
927
                buffer = self.emcore.malloc(buffsize)
928
                malloc = True
929
            else:
532 farthen 930
                buffer = to_int(buffer)
479 theseven 931
                malloc = False
472 farthen 932
            try:
479 theseven 933
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
934
                while count > 0:
935
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
936
                    bytes = storageinfo.sectorsize * sectors
937
                    data = f.read(bytes)
938
                    if len(data) == 0: break
939
                    while len(data) < bytes: data = data + f.read(bytes - len(data))
940
                    self.emcore.write(buffer, data)
941
                    self.emcore.storage_write_sectors_md(volume, sector, sectors, buffsize, buffer)
942
                    sector = sector + sectors
943
                    count = count - sectors
944
            finally:
945
                if malloc == True:
946
                    self.emcore.free(buffer)
947
        finally:
472 farthen 948
            f.close()
379 theseven 949
        self.logger.info("done\n")
517 farthen 950
 
379 theseven 951
    @command
346 theseven 952
    def mkdir(self, dirname):
953
        """
402 farthen 954
            Creates a directory with the name <dirname>
346 theseven 955
        """
516 farthen 956
        self.logger.info("Creating directory %s..." % dirname)
427 farthen 957
        self.emcore.dir_create(dirname)
346 theseven 958
        self.logger.info(" done\n")
517 farthen 959
 
346 theseven 960
    @command
961
    def rmdir(self, dirname):
962
        """
402 farthen 963
            Removes an empty directory with the name <dirname>
346 theseven 964
        """
516 farthen 965
        self.logger.info("Removing directory %s..." % dirname)
427 farthen 966
        self.emcore.dir_remove(dirname)
346 theseven 967
        self.logger.info(" done\n")
517 farthen 968
 
346 theseven 969
    @command
349 theseven 970
    def rm(self, filename):
346 theseven 971
        """
402 farthen 972
            Removes a file with the name <filename>
346 theseven 973
        """
516 farthen 974
        self.logger.info("Removing file %s..." % filename)
427 farthen 975
        self.emcore.file_unlink(filename)
346 theseven 976
        self.logger.info(" done\n")
517 farthen 977
 
346 theseven 978
    @command
406 theseven 979
    def rmtree(self, path):
980
        """
981
            Recursively removes a folder
982
            <path>: the folder to be removed
983
        """
427 farthen 984
        handle = self.emcore.dir_open(path)
406 theseven 985
        while True:
986
            try:
427 farthen 987
                entry = self.emcore.dir_read(handle)
406 theseven 988
                if entry.name == "." or entry.name == "..": continue
989
                elif entry.attributes & 0x10:
990
                    self.rmtree(path + "/" + entry.name)
991
                else: self.rm(path + "/" + entry.name)
992
            except: break
427 farthen 993
        self.emcore.dir_close(handle)
406 theseven 994
        self.rmdir(path)
517 farthen 995
 
406 theseven 996
    @command
352 theseven 997
    def mv(self, oldname, newname):
350 theseven 998
        """
402 farthen 999
            Renames or moves file or directory <oldname> to <newname>
350 theseven 1000
        """
516 farthen 1001
        self.logger.info("Renaming %s to %s..." % (oldname, newname))
427 farthen 1002
        self.emcore.file_rename(oldname, newname)
350 theseven 1003
        self.logger.info(" done\n")
517 farthen 1004
 
350 theseven 1005
    @command
475 farthen 1006
    def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
346 theseven 1007
        """
1008
            Downloads a file
402 farthen 1009
            <remotename>: filename on the device
1010
            <localname>: filename on the computer
472 farthen 1011
            [buffsize]: buffer size (optional)
402 farthen 1012
            [buffer]: buffer address (optional)
346 theseven 1013
        """
532 farthen 1014
        buffsize = to_int(buffsize)
346 theseven 1015
        try:
479 theseven 1016
            f = open(localname, 'wb')
1017
        except IOError:
1018
            raise ArgumentError("Could not open local file for writing.")
1019
        try:
482 theseven 1020
            fd = self.emcore.file_open(remotename, 0)
472 farthen 1021
            try:
482 theseven 1022
                size = self.emcore.file_size(fd)
1023
                buffsize = min(buffsize, size)
1024
                if buffer is None:
1025
                    buffer = self.emcore.malloc(buffsize)
1026
                    malloc = True
1027
                else:
532 farthen 1028
                    buffer = to_int(buffer)
482 theseven 1029
                    malloc = False
479 theseven 1030
                try:
516 farthen 1031
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
479 theseven 1032
                    while size > 0:
488 theseven 1033
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
479 theseven 1034
                        f.write(self.emcore.read(buffer, bytes))
1035
                        size = size - bytes
1036
                finally:
482 theseven 1037
                    if malloc == True:
1038
                        self.emcore.free(buffer)
479 theseven 1039
            finally:
482 theseven 1040
                self.emcore.file_close(fd)
479 theseven 1041
        finally:
472 farthen 1042
            f.close()
346 theseven 1043
        self.logger.info(" done\n")
517 farthen 1044
 
346 theseven 1045
    @command
475 farthen 1046
    def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
406 theseven 1047
        """
1048
            Downloads a directory tree
1049
            <remotepath>: path on the device
1050
            <localpath>: path on the computer
472 farthen 1051
            [buffsize]: buffer size (optional)
406 theseven 1052
            [buffer]: buffer address (optional)
1053
        """
532 farthen 1054
        buffsize = to_int(buffsize)
479 theseven 1055
        handle = self.emcore.dir_open(remotepath)
472 farthen 1056
        try:
479 theseven 1057
            if buffer is None:
1058
                buffer = self.emcore.malloc(buffsize)
1059
                malloc = True
1060
            else:
532 farthen 1061
                buffer = to_int(buffer)
479 theseven 1062
                malloc = False
1063
            try:
1064
                try: os.mkdir(localpath)
1065
                except: pass
1066
                while True:
1067
                    try:
1068
                        entry = self.emcore.dir_read(handle)
1069
                    except: break
486 theseven 1070
                    if entry.name == "." or entry.name == "..": continue
1071
                    elif entry.attributes & 0x10:
1072
                        self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1073
                    else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
479 theseven 1074
            finally:
1075
                if malloc == True:
1076
                    self.emcore.free(buffer)
1077
        finally:
472 farthen 1078
            self.emcore.dir_close(handle)
517 farthen 1079
 
406 theseven 1080
    @command
475 farthen 1081
    def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
346 theseven 1082
        """
1083
            Uploads a file
406 theseven 1084
            <localname>: filename on the computer
402 farthen 1085
            <remotename>: filename on the device
472 farthen 1086
            [buffsize]: buffer size (optional)
402 farthen 1087
            [buffer]: buffer address (optional)
346 theseven 1088
        """
532 farthen 1089
        buffsize = to_int(buffsize)
346 theseven 1090
        try:
479 theseven 1091
            f = open(localname, 'rb')
1092
        except IOError:
1093
            raise ArgumentError("Could not open local file for reading.")
1094
        try:
482 theseven 1095
            buffsize = min(buffsize, os.path.getsize(localname))
479 theseven 1096
            if buffer is None:
1097
                buffer = self.emcore.malloc(buffsize)
1098
                malloc = True
1099
            else:
532 farthen 1100
                buffer = to_int(buffer)
479 theseven 1101
                malloc = False
472 farthen 1102
            try:
516 farthen 1103
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
479 theseven 1104
                fd = self.emcore.file_open(remotename, 0x15)
1105
                try:
1106
                    while True:
1107
                        data = f.read(buffsize)
1108
                        if len(data) == 0: break
1109
                        self.emcore.write(buffer, data)
1110
                        bytes = 0
1111
                        while bytes < len(data):
1112
                            bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
1113
                finally:
1114
                    self.emcore.file_close(fd)
1115
            finally:
1116
                if malloc == True:
1117
                    self.emcore.free(buffer)
1118
        finally:
472 farthen 1119
            f.close()
346 theseven 1120
        self.logger.info(" done\n")
517 farthen 1121
 
346 theseven 1122
    @command
475 farthen 1123
    def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
406 theseven 1124
        """
1125
            Uploads a directory tree
1126
            <localpath>: path on the computer
1127
            <remotepath>: path on the device
472 farthen 1128
            [buffsize]: buffer size (optional)
406 theseven 1129
            [buffer]: buffer address (optional)
1130
        """
532 farthen 1131
        buffsize = to_int(buffsize)
472 farthen 1132
        if buffer is None:
1133
            buffer = self.emcore.malloc(buffsize)
1134
            malloc = True
1135
        else:
532 farthen 1136
            buffer = to_int(buffer)
472 farthen 1137
            malloc = False
1138
        try:
1139
            try: self.mkdir(remotepath)
1140
            except: self.logger.info(" failed\n")
1141
            pathlen = len(localpath)
1142
            for d in os.walk(localpath):
1143
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1144
                for dir in d[1]:
1145
                    if dir != ".svn":
1146
                        try: self.mkdir(prefix + dir)
1147
                        except: self.logger.info(" failed\n")
1148
                for f in d[2]:
479 theseven 1149
                    if prefix.find("/.svn/") == -1:
477 farthen 1150
                        self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
472 farthen 1151
        finally:
1152
            if malloc == True:
1153
                self.emcore.free(buffer)
517 farthen 1154
 
406 theseven 1155
    @command
351 theseven 1156
    def ls(self, path = "/"):
346 theseven 1157
        """
1158
            Lists all files in the specified path
402 farthen 1159
            [path]: the path which is listed
346 theseven 1160
        """
427 farthen 1161
        handle = self.emcore.dir_open(path)
516 farthen 1162
        self.logger.info("Directory listing of %s:\n" % path)
346 theseven 1163
        while True:
1164
            try:
427 farthen 1165
                entry = self.emcore.dir_read(handle)
346 theseven 1166
            except: break
486 theseven 1167
            if entry.attributes & 0x10: size = "DIR"
1168
            else: size = locale.format("%d", entry.size, True).rjust(13)
1169
            self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
427 farthen 1170
        self.emcore.dir_close(handle)
474 farthen 1171
 
1172
    @command
483 theseven 1173
    def find(self, path = "/"):
1174
        """
1175
            Lists all files in the specified path, recursively
1176
            [path]: the path which is listed
1177
        """
1178
        handle = self.emcore.dir_open(path)
1179
        self.logger.info(path + "/\n")
1180
        while True:
1181
            try:
1182
                entry = self.emcore.dir_read(handle)
1183
            except: break
486 theseven 1184
            if entry.name == "." or entry.name == "..": continue
1185
            elif entry.attributes & 0x10: self.find(path + "/" + entry.name)
1186
            else: self.logger.info(path + "/" + entry.name + "\n")
483 theseven 1187
        self.emcore.dir_close(handle)
1188
 
1189
    @command
474 farthen 1190
    def malloc(self, size):
1191
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
532 farthen 1192
        size = to_int(size)
474 farthen 1193
        self.logger.info("Allocating %d bytes of memory\n" % size)
1194
        addr = self.emcore.malloc(size)
518 farthen 1195
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1196
 
1197
    @command
1198
    def memalign(self, align, size):
1199
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
532 farthen 1200
        align = to_int(align)
1201
        size = to_int(size)
518 farthen 1202
        self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
474 farthen 1203
        addr = self.emcore.memalign(align, size)
518 farthen 1204
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1205
 
1206
    @command
1207
    def realloc(self, ptr, size):
1208
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1209
            expanding or reducing the amount of memory available in the block.
1210
            Returns a pointer to the reallocated memory.
1211
        """
532 farthen 1212
        ptr = to_int(ptr)
1213
        size = to_int(size)
518 farthen 1214
        self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
474 farthen 1215
        addr = self.emcore.realloc(ptr, size)
518 farthen 1216
        self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
474 farthen 1217
 
1218
    @command
1219
    def reownalloc(self, ptr, owner):
1220
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
532 farthen 1221
        ptr = to_int(ptr)
1222
        owner = to_int(owner)
518 farthen 1223
        self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1224
        self.emcore.reownalloc(ptr, owner)
518 farthen 1225
        self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1226
 
1227
    @command
1228
    def free(self, ptr):
1229
        """ Frees the memory space pointed to by 'ptr' """
532 farthen 1230
        ptr = to_int(ptr)
518 farthen 1231
        self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
474 farthen 1232
        self.emcore.free(ptr)
518 farthen 1233
        self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
474 farthen 1234
 
1235
    @command
1236
    def free_all(self):
1237
        """ Frees all memory allocations created by the monitor thread """
1238
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1239
        self.emcore.free_all()
1240
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
1241
 
346 theseven 1242
 
171 farthen 1243
if __name__ == "__main__":
1244
    if len(sys.argv) < 2:
502 farthen 1245
        usage("No command specified", docstring = False)
382 farthen 1246
    try:
1247
        interface = Commandline()
1248
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1249
    except KeyboardInterrupt:
1250
        sys.exit()